diff options
Diffstat (limited to 'services/console')
14 files changed, 154 insertions, 103 deletions
diff --git a/services/console/interface/logviewer/logviewer.py b/services/console/interface/logviewer/logviewer.py index 3d90f09..8aaf347 100644 --- a/services/console/interface/logviewer/logviewer.py +++ b/services/console/interface/logviewer/logviewer.py @@ -28,29 +28,29 @@ import pango from sugar import env class MultiLogView(gtk.VBox): - def __init__(self, path): + def __init__(self, path, extra_files): self._active_log = None - self._iters = [] - + self._extra_files = extra_files + # Creating Main treeview with Actitivities list - tv_menu = gtk.TreeView() - tv_menu.connect('cursor-changed', self._load_log) - tv_menu.set_rules_hint(True) + self._tv_menu = gtk.TreeView() + self._tv_menu.connect('cursor-changed', self._load_log) + self._tv_menu.set_rules_hint(True) # Set width box_width = gtk.gdk.screen_width() * 80 / 100 - tv_menu.set_size_request(box_width*25/100, 0) + self._tv_menu.set_size_request(box_width*25/100, 0) - self.store_menu = gtk.TreeStore(str) - tv_menu.set_model(self.store_menu) + self._store_menu = gtk.TreeStore(str) + self._tv_menu.set_model(self._store_menu) - self._add_column(tv_menu, 'Sugar logs', 0) + self._add_column(self._tv_menu, 'Sugar logs', 0) self._logs_path = os.path.join(env.get_profile_path(), 'logs') self._activity = {} # Activities menu self.hbox = gtk.HBox(False, 3) - self.hbox.pack_start(tv_menu, True, True, 0) + self.hbox.pack_start(self._tv_menu, True, True, 0) # Activity log, set width self._view = LogView() @@ -59,52 +59,62 @@ class MultiLogView(gtk.VBox): self.hbox.pack_start(self._view, True, True, 0) self.hbox.show_all() - gobject.timeout_add(1000, self._update, tv_menu) + gobject.timeout_add(1000, self._update) # Load the log information in View (textview) def _load_log(self, treeview): treeselection = treeview.get_selection() - treestore, iter = treeselection.get_selected() - + # Get current selection - act_log = self.store_menu.get_value(iter, 0) - + act_log = self._store_menu.get_value(iter, 0) + # Set buffer and scroll down self._view.textview.set_buffer(self._activity[act_log]) self._view.textview.scroll_to_mark(self._activity[act_log].get_insert(), 0); self._active_log = act_log - - def _update(self, tv_menu): + + def _update(self): # Searching log files for logfile in os.listdir(self._logs_path): full_log_path = os.path.join(self._logs_path, logfile) - - if os.path.isdir(full_log_path): - continue - - if not self._activity.has_key(logfile): - self._add_activity(logfile) - model = LogBuffer(full_log_path) - self._activity[logfile] = model - - self._activity[logfile].update() - written = self._activity[logfile]._written - - # Load the first iter - if self._active_log == None: - self._active_log = logfile - iter = tv_menu.get_model().get_iter_root() - tv_menu.get_selection().select_iter(iter) - self._load_log(tv_menu) - - if written > 0 and self._active_log == logfile: - self._view.textview.scroll_to_mark(self._activity[logfile].get_insert(), 0); + self._add_log_file(full_log_path) + + for ext in self._extra_files: + self._add_log_file(ext) return True - + + def _get_filename_from_path(self, path): + return path.split('/')[-1] + + def _add_log_file(self, path): + if os.path.isdir(path): + return False + + logfile = self._get_filename_from_path(path) + + if not self._activity.has_key(logfile): + self._add_activity(logfile) + model = LogBuffer(path) + self._activity[logfile] = model + + self._activity[logfile].update() + written = self._activity[logfile]._written + + # Load the first iter + if self._active_log == None: + self._active_log = logfile + iter = self._tv_menu.get_model().get_iter_root() + self._tv_menu.get_selection().select_iter(iter) + self._load_log(self._tv_menu) + + if written > 0 and self._active_log == logfile: + self._view.textview.scroll_to_mark(self._activity[logfile].get_insert(), 0) + + def _add_activity(self, name): - self._insert_row(self.store_menu, None, name) + self._insert_row(self._store_menu, None, name) # Add a new column to the main treeview, (code from Memphis) def _add_column(self, treeview, column_name, index): @@ -171,9 +181,20 @@ class LogView(gtk.ScrolledWindow): self.textview.show() class Interface: - def __init__(self): path = None - viewer = MultiLogView(path) + xserver_logfile = self._get_xserver_logfile_path() + + # Aditional files to watch in logviewer + ext_files = [] + ext_files.append(xserver_logfile) + + viewer = MultiLogView(path, ext_files) self.widget = viewer.hbox + # Get the Xorg log file path, we have two ways to get the path: do a system + # call and exec a 'xset -q' or just read directly the file that we know + # always be the right one for a XO machine... + def _get_xserver_logfile_path(self): + path = "/var/log/Xorg.0.log" + return path diff --git a/services/console/interface/memphis/memphis.py b/services/console/interface/memphis/memphis.py index 0dd52fc..5b1ce40 100644 --- a/services/console/interface/memphis/memphis.py +++ b/services/console/interface/memphis/memphis.py @@ -130,15 +130,14 @@ class Data: treeview.set_model(self.store) def _start_memphis(self, button): - # Update information every 1.5 second button.hide() self.interface.button_stop.show() self._running_status = True - gobject.timeout_add(1500, self.load_data, self.treeview) + self._gid = gobject.timeout_add(1500, self.load_data, self.treeview) def _stop_memphis(self, button): - + gobject.source_remove(self._gid) self._running_status = False button.hide() self.interface.button_start.show() diff --git a/services/console/interface/memphis/plugins/Makefile.am b/services/console/interface/memphis/plugins/Makefile.am index a18eafe..d026419 100644 --- a/services/console/interface/memphis/plugins/Makefile.am +++ b/services/console/interface/memphis/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = clean_size cpu dirty_size memphis_init +SUBDIRS = clean_size cpu smaps memphis_init sugardir = $(pkgdatadir)/services/console/interface/memphis/plugins sugar_PYTHON = diff --git a/services/console/interface/memphis/plugins/dirty_size/__init__.py b/services/console/interface/memphis/plugins/dirty_size/__init__.py deleted file mode 100644 index f8e9e0a..0000000 --- a/services/console/interface/memphis/plugins/dirty_size/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ - -import info - - -INTERNALS = { - # Basic information - 'PLGNAME': "Dirty Size", - 'TABNAME': None, # No tabbed plugin - 'AUTHOR': "Eduardo Silva", - 'DESC': "Get dirty size memory usage", - - # Plugin API - 'Plg': None, # Plugin object - - 'top_data': [int], # Top data types needed by memphis core plugin - 'top_cols': ["PDRSS (kb)"] - } diff --git a/services/console/interface/memphis/plugins/memphis_init/info.py b/services/console/interface/memphis/plugins/memphis_init/info.py index 6e524c7..667645c 100644 --- a/services/console/interface/memphis/plugins/memphis_init/info.py +++ b/services/console/interface/memphis/plugins/memphis_init/info.py @@ -11,3 +11,4 @@ def plg_on_top_data_refresh(self, ppinfo): data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']] return data + diff --git a/services/console/interface/memphis/plugins/dirty_size/Makefile.am b/services/console/interface/memphis/plugins/smaps/Makefile.am index 1f81dfb..1f81dfb 100644 --- a/services/console/interface/memphis/plugins/dirty_size/Makefile.am +++ b/services/console/interface/memphis/plugins/smaps/Makefile.am diff --git a/services/console/interface/memphis/plugins/dirty_size/README b/services/console/interface/memphis/plugins/smaps/README index ee4d1a5..ee4d1a5 100644 --- a/services/console/interface/memphis/plugins/dirty_size/README +++ b/services/console/interface/memphis/plugins/smaps/README diff --git a/services/console/interface/memphis/plugins/smaps/__init__.py b/services/console/interface/memphis/plugins/smaps/__init__.py new file mode 100644 index 0000000..5977d4b --- /dev/null +++ b/services/console/interface/memphis/plugins/smaps/__init__.py @@ -0,0 +1,17 @@ + +import info + + +INTERNALS = { + # Basic information + 'PLGNAME': "SMaps", + 'TABNAME': None, # No tabbed plugin + 'AUTHOR': "Eduardo Silva", + 'DESC': "Get dirty size and reference memory usage", + + # Plugin API + 'Plg': None, # Plugin object + + 'top_data': [int, int], # Top data types needed by memphis core plugin + 'top_cols': ["PDRSS (kb)", "Referenced (kb)"] + } diff --git a/services/console/interface/memphis/plugins/dirty_size/info.py b/services/console/interface/memphis/plugins/smaps/info.py index 54a2e7e..998a1a2 100644 --- a/services/console/interface/memphis/plugins/dirty_size/info.py +++ b/services/console/interface/memphis/plugins/smaps/info.py @@ -8,13 +8,12 @@ def plg_on_top_data_refresh(self, ppinfo): - - dirty_sizes = get_dirty(self, ppinfo['pid']) + smaps = get_data(self, ppinfo['pid']) - # memhis need an array - return [dirty_sizes['private']] + # memphis need an array + return [smaps['private_dirty'], smaps['referenced']] -def get_dirty(pself, pid): +def get_data(pself, pid): ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid) - return ProcAnalysis.DirtyRSS() + return ProcAnalysis.SMaps() diff --git a/services/console/interface/terminal/terminal.py b/services/console/interface/terminal/terminal.py index 5eebfb3..4aba858 100644 --- a/services/console/interface/terminal/terminal.py +++ b/services/console/interface/terminal/terminal.py @@ -32,7 +32,7 @@ class Terminal(gtk.HBox): self._vte = vte.Terminal() self._configure_vte() - self._vte.set_size(30, 5) + self._vte.set_size(100, 5) self._vte.set_size_request(200, 450) self._vte.show() self.pack_start(self._vte) diff --git a/services/console/lib/procmem/analysis.py b/services/console/lib/procmem/analysis.py index d2a247a..e9d7aec 100644 --- a/services/console/lib/procmem/analysis.py +++ b/services/console/lib/procmem/analysis.py @@ -7,20 +7,22 @@ class Analysis: def __init__(self, pid): self.pid = pid - def DirtyRSS(self): + def SMaps(self): smaps = proc_smaps.ProcSmaps(self.pid) - dirty = [] + private_dirty = 0 + shared_dirty = 0 + referenced = 0 - private = 0 - shared = 0 - for map in smaps.mappings: - private += map.private_dirty - shared += map.shared_dirty + private_dirty += map.private_dirty + shared_dirty += map.shared_dirty + referenced += map.referenced - dirty = {"private": int(private), "shared": int(shared)} + smaps = {"private_dirty": int(private_dirty), \ + "shared_dirty": int(shared_dirty),\ + "referenced": int(referenced)} - return dirty + return smaps def ApproxRealMemoryUsage(self): maps = proc_smaps.ProcMaps(self.pid) diff --git a/services/console/lib/procmem/proc.py b/services/console/lib/procmem/proc.py index adc2f6b..d50242b 100644 --- a/services/console/lib/procmem/proc.py +++ b/services/console/lib/procmem/proc.py @@ -1,4 +1,6 @@ -import sys, os +import os +import re +import sys import string class ProcInfo: @@ -36,10 +38,12 @@ class ProcInfo: return None # Parsing data , check 'man 5 proc' for details - data = infile.read().split() - + stat_data = infile.read() infile.close() - + + process_name = self._get_process_name(stat_data) + data = self._get_safe_split(stat_data) + state_dic = { 'R': 'Running', 'S': 'Sleeping', @@ -48,27 +52,34 @@ class ProcInfo: '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) + 'pid': int(data[0]), # Process ID + 'name': 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 - + + # Return the process name + def _get_process_name(self, data): + m = re.search("\(.*\)", data) + return m.string[m.start()+1:m.end()-1] + + def _get_safe_split(self, data): + new_data = re.sub("\(.*\)", '()', data) + return new_data.split() # Returns the CPU usage expressed in Jiffies def get_CPU_usage(self, cpu_hz, used_jiffies, start_time): diff --git a/services/console/lib/procmem/proc_smaps.py b/services/console/lib/procmem/proc_smaps.py index ce93cb2..422866c 100644 --- a/services/console/lib/procmem/proc_smaps.py +++ b/services/console/lib/procmem/proc_smaps.py @@ -36,7 +36,8 @@ class ProcSmaps: # Shared_Dirty: 0 kB # Private_Clean: 8 kB # Private_Dirty: 0 kB - + # Referenced: 4 kb -> Introduced in kernel 2.6.22 + while num_lines > 0: fields = lines[line_idx].split (" ", 5) if len (fields) == 6: @@ -51,13 +52,20 @@ class ProcSmaps: 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]) + referenced = self.parse_smaps_size_line (lines[line_idx + 7]) name = name.strip () - mapping = Mapping (size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name) + mapping = Mapping (size, rss, shared_clean, shared_dirty, \ + private_clean, private_dirty, referenced, permissions, name) self.mappings.append (mapping) - num_lines -= 7 - line_idx += 7 + num_lines -= 8 + line_idx += 8 + + self._clear_reference(pid) + + def _clear_reference(self, pid): + os.system("echo 1 > /proc/%s/clear_refs" % pid) # Parses a line of the form "foo: 42 kB" and returns an integer for the "42" field def parse_smaps_size_line (self, line): @@ -66,13 +74,15 @@ class ProcSmaps: return int(fields[1]) class Mapping: - def __init__ (self, size, rss, shared_clean, shared_dirty, private_clean, private_dirty, permissions, name): + def __init__ (self, size, rss, shared_clean, shared_dirty, \ + private_clean, private_dirty, referenced, 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.referenced = referenced self.permissions = permissions self.name = name diff --git a/services/console/sugar-console b/services/console/sugar-console index af709a6..357b7fe 100755 --- a/services/console/sugar-console +++ b/services/console/sugar-console @@ -6,7 +6,15 @@ pygtk.require('2.0') import os import sys from sugar import env +from sugar import util sys.path.append(env.get_service_path('console')) +# change to the user's home directory if it is set +# root if not +os.chdir(os.environ.get('HOME', '/')) + +#set the process title so it shows up as sugar-console not python +util.set_proc_title('sugar-console') + import console |