New developer-console
This commit is contained in:
committed by
Marco Pesenti Gritti
parent
9a7518f230
commit
d51031d882
@@ -0,0 +1,8 @@
|
||||
|
||||
sugardir = $(pkgdatadir)/shell/console/procmem
|
||||
|
||||
sugar_PYTHON = \
|
||||
__init__.py \
|
||||
proc.py \
|
||||
proc_smaps.py \
|
||||
analysis.py
|
||||
@@ -0,0 +1,30 @@
|
||||
import proc, proc_smaps
|
||||
|
||||
class Analysis:
|
||||
|
||||
pid = 0
|
||||
|
||||
def __init__(self, pid):
|
||||
self.pid = pid
|
||||
|
||||
def DirtyRSS(self):
|
||||
smaps = proc_smaps.ProcSmaps(self.pid)
|
||||
dirty = []
|
||||
|
||||
private = 0
|
||||
shared = 0
|
||||
|
||||
for map in smaps.mappings:
|
||||
private += map.private_dirty
|
||||
shared += map.shared_dirty
|
||||
|
||||
dirty = {"private": int(private), "shared": int(shared)}
|
||||
|
||||
return dirty
|
||||
|
||||
def ApproxRealMemoryUsage(self):
|
||||
maps = proc_smaps.ProcMaps(self.pid)
|
||||
size = (maps.clean_size/1024)
|
||||
|
||||
return size
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys, os
|
||||
import string
|
||||
|
||||
class ProcInfo:
|
||||
|
||||
dir_path = "/proc/" # Our cute Proc File System
|
||||
status_file = "status"
|
||||
stat_file = "stat"
|
||||
|
||||
proc_list = [] # Our PID list :D
|
||||
proc_info = [] #
|
||||
|
||||
def __init__(self):
|
||||
self.proc_list = self.Get_PID_List()
|
||||
|
||||
# Returns Process List
|
||||
def Get_PID_List(self):
|
||||
list = []
|
||||
|
||||
# Exists our procfs ?
|
||||
if os.path.isdir(self.dir_path):
|
||||
# around dir entries
|
||||
for f in os.listdir(self.dir_path):
|
||||
if os.path.isdir(self.dir_path+f) & str.isdigit(f):
|
||||
list.append(int(f))
|
||||
|
||||
return list
|
||||
|
||||
def MemoryInfo(self, pid):
|
||||
# Path
|
||||
pidfile = self.dir_path + str(pid) + "/stat"
|
||||
try:
|
||||
infile = open(pidfile, "r")
|
||||
except:
|
||||
print "Error trying " + pidfile
|
||||
return None
|
||||
|
||||
# Parsing data , check 'man 5 proc' for details
|
||||
data = infile.read().split()
|
||||
|
||||
infile.close()
|
||||
|
||||
state_dic = {
|
||||
'R': 'Running',
|
||||
'S': 'Sleeping',
|
||||
'D': 'Disk sleep',
|
||||
'Z': 'Zombie',
|
||||
'T': 'Traced/Stopped',
|
||||
'W': 'Paging'
|
||||
}
|
||||
|
||||
# user and group owners
|
||||
pidstat = os.stat(pidfile)
|
||||
|
||||
info = {
|
||||
'pid': int(data[0]), # Process ID
|
||||
'name': data[1].strip('()'), # Process name
|
||||
'state': data[2], # Process State, ex: R|S|D|Z|T|W
|
||||
'state_name': state_dic[data[2]], # Process State name, ex: Running, sleeping, Zombie, etc
|
||||
'ppid': int(data[3]), # Parent process ID
|
||||
'utime': int(data[13]), # Used jiffies in user mode
|
||||
'stime': int(data[14]), # Used jiffies in kernel mode
|
||||
'start_time': int(data[21]), # Process time from system boot (jiffies)
|
||||
'vsize': int(data[22]), # Virtual memory size used (bytes)
|
||||
'rss': int(data[23])*4, # Resident Set Size (bytes)
|
||||
'user_id': pidstat.st_uid, # process owner
|
||||
'group_id': pidstat.st_gid # owner group
|
||||
}
|
||||
|
||||
return info
|
||||
|
||||
|
||||
# Returns the CPU usage expressed in Jiffies
|
||||
def get_CPU_usage(self, cpu_hz, used_jiffies, start_time):
|
||||
|
||||
# Uptime info
|
||||
uptime_file = self.dir_path + "/uptime"
|
||||
try:
|
||||
infile = file(uptime_file, "r")
|
||||
except:
|
||||
print "Error trying uptime file"
|
||||
return None
|
||||
|
||||
uptime_line = infile.readline()
|
||||
uptime = string.split(uptime_line, " ",2)
|
||||
|
||||
infile.close()
|
||||
|
||||
# System uptime, from /proc/uptime
|
||||
uptime = float(uptime[0])
|
||||
|
||||
# Jiffies
|
||||
avail_jiffies = (uptime * cpu_hz) - start_time
|
||||
|
||||
cpu_usage = {'used_jiffies': used_jiffies, 'avail_jiffies': avail_jiffies}
|
||||
|
||||
return cpu_usage
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
####################################################################
|
||||
# This class open the /proc/PID/maps and /proc/PID/smaps files
|
||||
# to get useful information about the real memory usage
|
||||
####################################################################
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
# Parse the /proc/PID/smaps file
|
||||
class ProcSmaps:
|
||||
|
||||
mappings = [] # Devices information
|
||||
|
||||
def __init__(self, pid):
|
||||
|
||||
smapfile = "/proc/%s/smaps" % pid
|
||||
self.mappings = []
|
||||
|
||||
# Coded by Federico Mena (script)
|
||||
try:
|
||||
infile = open(smapfile, "r")
|
||||
input = infile.read()
|
||||
infile.close()
|
||||
except:
|
||||
print "Error trying " + smapfile
|
||||
return
|
||||
|
||||
lines = input.splitlines()
|
||||
|
||||
num_lines = len (lines)
|
||||
line_idx = 0
|
||||
|
||||
# 08065000-08067000 rw-p 0001c000 03:01 147613 /opt/gnome/bin/evolution-2.6
|
||||
# Size: 8 kB
|
||||
# Rss: 8 kB
|
||||
# Shared_Clean: 0 kB
|
||||
# Shared_Dirty: 0 kB
|
||||
# Private_Clean: 8 kB
|
||||
# Private_Dirty: 0 kB
|
||||
|
||||
while num_lines > 0:
|
||||
fields = lines[line_idx].split (" ", 5)
|
||||
if len (fields) == 6:
|
||||
(offsets, permissions, bin_permissions, device, inode, name) = fields
|
||||
else:
|
||||
(offsets, permissions, bin_permissions, device, inode) = fields
|
||||
name = ""
|
||||
|
||||
size = self.parse_smaps_size_line (lines[line_idx + 1])
|
||||
rss = self.parse_smaps_size_line (lines[line_idx + 2])
|
||||
shared_clean = self.parse_smaps_size_line (lines[line_idx + 3])
|
||||
shared_dirty = self.parse_smaps_size_line (lines[line_idx + 4])
|
||||
private_clean = self.parse_smaps_size_line (lines[line_idx + 5])
|
||||
private_dirty = self.parse_smaps_size_line (lines[line_idx + 6])
|
||||
name = name.strip ()
|
||||
|
||||
mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name)
|
||||
self.mappings.append (mapping)
|
||||
|
||||
num_lines -= 7
|
||||
line_idx += 7
|
||||
|
||||
# Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field
|
||||
def parse_smaps_size_line (self, line):
|
||||
# Rss: 8 kB
|
||||
fields = line.split ()
|
||||
return int(fields[1])
|
||||
|
||||
class Mapping:
|
||||
def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name):
|
||||
self.size = size
|
||||
self.rss = rss
|
||||
self.shared_clean = shared_clean
|
||||
self.shared_dirty = shared_dirty
|
||||
self.private_clean = private_clean
|
||||
self.private_dirty = private_dirty
|
||||
self.permissions = permissions
|
||||
self.name = name
|
||||
|
||||
# Parse /proc/PID/maps file to get the clean memory usage by process,
|
||||
# we avoid lines with backed-files
|
||||
class ProcMaps:
|
||||
|
||||
clean_size = 0
|
||||
|
||||
def __init__(self, pid):
|
||||
mapfile = "/proc/%s/maps" % pid
|
||||
|
||||
try:
|
||||
infile = open(mapfile, "r")
|
||||
except:
|
||||
print "Error trying " + mapfile
|
||||
return None
|
||||
|
||||
sum = 0
|
||||
to_data_do = {
|
||||
"[anon]": self.parse_size_line,
|
||||
"[heap]": self.parse_size_line
|
||||
}
|
||||
|
||||
for line in infile:
|
||||
arr = line.split()
|
||||
|
||||
# Just parse writable mapped areas
|
||||
if arr[1][1] != "w":
|
||||
continue
|
||||
|
||||
if len(arr) == 6:
|
||||
# if we got a backed-file we skip this info
|
||||
if os.path.isfile(arr[5]):
|
||||
continue
|
||||
else:
|
||||
line_size = to_data_do.get(arr[5], self.skip)(line)
|
||||
sum += line_size
|
||||
else:
|
||||
line_size = self.parse_size_line(line)
|
||||
sum += line_size
|
||||
|
||||
infile.close()
|
||||
self.clean_size = sum
|
||||
|
||||
def skip(self, line):
|
||||
return 0
|
||||
|
||||
# Parse a maps line and return the mapped size
|
||||
def parse_size_line(self, line):
|
||||
start, end = line.split()[0].split('-')
|
||||
size = int(end, 16) - int(start, 16)
|
||||
return size
|
||||
Reference in New Issue
Block a user