From 9a7518f23076d824aefa5cc764af65b639cb7e1d Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Thu, 16 Nov 2006 11:07:30 +0100 Subject: [PATCH 1/3] Get rid of dbus 0.94 compatibility, since we build dbus in jhbuild now. Yay! --- .gitignore | 1 - Makefile.am | 2 +- configure.ac | 1 - dbus-installed-094.conf.in | 26 -------------------------- dbus-uninstalled-094.conf | 25 ------------------------- sugar-emulator | 7 +------ sugar/__installed__.py.in | 1 - sugar/__uninstalled__.py | 1 - sugar/activity/bundleregistry.py | 6 +----- sugar/env.py | 3 --- 10 files changed, 3 insertions(+), 70 deletions(-) delete mode 100644 dbus-installed-094.conf.in delete mode 100644 dbus-uninstalled-094.conf diff --git a/.gitignore b/.gitignore index edc55926..4f204b61 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,6 @@ missing py-compile stamp-h1 dbus-installed.conf -dbus-installed-094.conf intltool-extract intltool-extract.in intltool-merge diff --git a/Makefile.am b/Makefile.am index 58822d05..adb34ab3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,7 @@ SUBDIRS = activities lib po shell sugar services tools ACLOCAL_AMFLAGS = -I m4 dbusconfdir = $(pkgdatadir) -dbusconf_DATA = dbus-installed.conf dbus-installed-094.conf +dbusconf_DATA = dbus-installed.conf bin_SCRIPTS = \ sugar-emulator \ diff --git a/configure.ac b/configure.ac index e96a4ff0..8fdef065 100644 --- a/configure.ac +++ b/configure.ac @@ -51,7 +51,6 @@ AM_GLIB_GNU_GETTEXT AC_OUTPUT([ Makefile dbus-installed.conf -dbus-installed-094.conf activities/Makefile activities/web/Makefile activities/chat/Makefile diff --git a/dbus-installed-094.conf.in b/dbus-installed-094.conf.in deleted file mode 100644 index 7b6d6074..00000000 --- a/dbus-installed-094.conf.in +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - session - - unix:tmpdir=/tmp - - @prefix@/share/sugar/activities - @prefix@/share/sugar/services - /tmp/sugar-services - - - - - - - - - - - diff --git a/dbus-uninstalled-094.conf b/dbus-uninstalled-094.conf deleted file mode 100644 index fbed2d6a..00000000 --- a/dbus-uninstalled-094.conf +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - session - - unix:tmpdir=/tmp - - /tmp/sugar - /tmp/sugar-services - - - - - - - - - - - diff --git a/sugar-emulator b/sugar-emulator index a26f0f23..a45f73e2 100755 --- a/sugar-emulator +++ b/sugar-emulator @@ -76,12 +76,7 @@ for i in range(1, len(sys.argv)): emulator = Emulator(fullscreen) emulator.start() -if env.get_dbus_version() < '0.95': - if not os.path.isdir('/tmp/sugar-services'): - os.mkdir('/tmp/sugar-services') - dbus_config = env.get_dbus_config_094() -else: - dbus_config = env.get_dbus_config() +dbus_config = env.get_dbus_config() os.execlp('dbus-launch', 'dbus-launch', '--exit-with-session', '--config-file=%s' % dbus_config, program) diff --git a/sugar/__installed__.py.in b/sugar/__installed__.py.in index 78489f43..832fca50 100644 --- a/sugar/__installed__.py.in +++ b/sugar/__installed__.py.in @@ -4,5 +4,4 @@ sugar_activities_dir = '@prefix@/share/sugar/activities' sugar_activity_info_dir = '@prefix@/share/sugar/activities' sugar_services_dir = '@prefix@/share/sugar/services' sugar_dbus_config = '@prefix@/share/sugar/dbus-installed.conf' -sugar_dbus_config_094 = '@prefix@/share/sugar/dbus-installed-094.conf' sugar_shell_bin_dir = '@prefix@/bin' diff --git a/sugar/__uninstalled__.py b/sugar/__uninstalled__.py index 121e0508..e0bfc295 100644 --- a/sugar/__uninstalled__.py +++ b/sugar/__uninstalled__.py @@ -9,5 +9,4 @@ sugar_services_dir = os.path.join(_sourcedir, 'services') sugar_activity_info_dir = _tmpdir sugar_activities_dir = os.path.join(_sourcedir, 'activities') sugar_dbus_config = os.path.join(_sourcedir, 'dbus-uninstalled.conf') -sugar_dbus_config_094 = os.path.join(_sourcedir, 'dbus-uninstalled-094.conf') sugar_shell_bin_dir = os.path.join(_sourcedir, 'shell') diff --git a/sugar/activity/bundleregistry.py b/sugar/activity/bundleregistry.py index c6d05319..182bfcf5 100644 --- a/sugar/activity/bundleregistry.py +++ b/sugar/activity/bundleregistry.py @@ -10,11 +10,7 @@ class _ServiceParser(ConfigParser): class _ServiceManager(object): def __init__(self): - if env.get_dbus_version() < '0.95': - self._path = '/tmp/sugar-services' - else: - self._path = os.path.expanduser('~/.local/share/dbus-1/services') - + self._path = os.path.expanduser('~/.local/share/dbus-1/services') if not os.path.isdir(self._path): os.makedirs(self._path) diff --git a/sugar/env.py b/sugar/env.py index 0c996b47..e48b72a8 100644 --- a/sugar/env.py +++ b/sugar/env.py @@ -54,9 +54,6 @@ def get_services_dir(): def get_dbus_config(): return sugar_dbus_config -def get_dbus_config_094(): - return sugar_dbus_config_094 - def get_shell_bin_dir(): return sugar_shell_bin_dir From d51031d8829db282008f778e30a2f0c044abfe07 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 16 Nov 2006 09:09:07 -0300 Subject: [PATCH 2/3] New developer-console --- configure.ac | 7 + shell/Makefile.am | 6 +- shell/console/Makefile.am | 10 + shell/console/__init__.py | 1 + shell/console/console.py | 43 +++++ .../logviewer.py} | 21 +- shell/console/memphis.py | 182 ++++++++++++++++++ shell/console/plugin.py | 50 +++++ shell/console/plugins/Makefile.am | 4 + shell/console/plugins/clean_size/Makefile.am | 6 + shell/console/plugins/clean_size/README | 2 + shell/console/plugins/clean_size/__init__.py | 16 ++ shell/console/plugins/clean_size/info.py | 15 ++ shell/console/plugins/cpu/Makefile.am | 6 + shell/console/plugins/cpu/README | 2 + shell/console/plugins/cpu/__init__.py | 23 +++ shell/console/plugins/cpu/info.py | 48 +++++ shell/console/plugins/dirty_size/Makefile.am | 6 + shell/console/plugins/dirty_size/README | 2 + shell/console/plugins/dirty_size/__init__.py | 17 ++ shell/console/plugins/dirty_size/info.py | 20 ++ .../console/plugins/memphis_init/Makefile.am | 6 + shell/console/plugins/memphis_init/README | 2 + .../console/plugins/memphis_init/__init__.py | 15 ++ shell/console/plugins/memphis_init/info.py | 13 ++ shell/console/procmem/Makefile.am | 8 + shell/console/procmem/__init__.py | 0 shell/console/procmem/analysis.py | 30 +++ shell/console/procmem/proc.py | 100 ++++++++++ shell/console/procmem/proc_smaps.py | 129 +++++++++++++ shell/console/terminal.py | 143 ++++++++++++++ shell/data/kbdconfig | 2 +- shell/sugar-devel-console | 9 + sugar/activity/Activity.py | 1 + 34 files changed, 927 insertions(+), 18 deletions(-) create mode 100644 shell/console/Makefile.am create mode 100644 shell/console/__init__.py create mode 100755 shell/console/console.py rename shell/{sugar-log-viewer => console/logviewer.py} (86%) mode change 100755 => 100644 create mode 100644 shell/console/memphis.py create mode 100755 shell/console/plugin.py create mode 100644 shell/console/plugins/Makefile.am create mode 100644 shell/console/plugins/clean_size/Makefile.am create mode 100644 shell/console/plugins/clean_size/README create mode 100644 shell/console/plugins/clean_size/__init__.py create mode 100644 shell/console/plugins/clean_size/info.py create mode 100644 shell/console/plugins/cpu/Makefile.am create mode 100644 shell/console/plugins/cpu/README create mode 100644 shell/console/plugins/cpu/__init__.py create mode 100644 shell/console/plugins/cpu/info.py create mode 100644 shell/console/plugins/dirty_size/Makefile.am create mode 100644 shell/console/plugins/dirty_size/README create mode 100644 shell/console/plugins/dirty_size/__init__.py create mode 100644 shell/console/plugins/dirty_size/info.py create mode 100644 shell/console/plugins/memphis_init/Makefile.am create mode 100644 shell/console/plugins/memphis_init/README create mode 100644 shell/console/plugins/memphis_init/__init__.py create mode 100644 shell/console/plugins/memphis_init/info.py create mode 100644 shell/console/procmem/Makefile.am create mode 100644 shell/console/procmem/__init__.py create mode 100644 shell/console/procmem/analysis.py create mode 100644 shell/console/procmem/proc.py create mode 100644 shell/console/procmem/proc_smaps.py create mode 100644 shell/console/terminal.py create mode 100755 shell/sugar-devel-console diff --git a/configure.ac b/configure.ac index 8fdef065..61752047 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,13 @@ shell/view/Makefile shell/view/home/Makefile shell/view/frame/Makefile shell/model/Makefile +shell/console/Makefile +shell/console/plugins/Makefile +shell/console/plugins/clean_size/Makefile +shell/console/plugins/cpu/Makefile +shell/console/plugins/dirty_size/Makefile +shell/console/plugins/memphis_init/Makefile +shell/console/procmem/Makefile sugar/Makefile sugar/__installed__.py sugar/activity/Makefile diff --git a/shell/Makefile.am b/shell/Makefile.am index 885ca5eb..fb601a2a 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -1,11 +1,11 @@ -SUBDIRS = conf data model view +SUBDIRS = conf data model view console bin_SCRIPTS = \ sugar-activity \ sugar-activity-factory \ - sugar-log-viewer \ sugar-shell \ - sugar-shutdown + sugar-shutdown \ + sugar-devel-console sugardir = $(pkgdatadir)/shell sugar_PYTHON = \ diff --git a/shell/console/Makefile.am b/shell/console/Makefile.am new file mode 100644 index 00000000..5b838301 --- /dev/null +++ b/shell/console/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = plugins procmem + +sugardir = $(pkgdatadir)/shell/console +sugar_PYTHON = \ + __init__.py \ + console.py \ + memphis.py \ + logviewer.py \ + terminal.py \ + plugin.py diff --git a/shell/console/__init__.py b/shell/console/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/shell/console/__init__.py @@ -0,0 +1 @@ + diff --git a/shell/console/console.py b/shell/console/console.py new file mode 100755 index 00000000..45d1bb19 --- /dev/null +++ b/shell/console/console.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +import gtk + +# Console interfaces +import memphis +import logviewer +import terminal + +window = gtk.Window() +window.set_title('Developer console') + +width = gtk.gdk.screen_width()* 95 / 100 +height = gtk.gdk.screen_height() * 3 / 4 + +window.set_default_size(width, height) + +window.realize() +window.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + +# Memphis interface +memphis_widget = memphis.Interface().widget +memphis_widget.show() + +# Sugar log viewer interface +logviewer_widget = logviewer.Interface().widget +logviewer_widget.show() + +# Sugar log viewer interface +terminal_widget = terminal.Interface().widget +terminal_widget.show() + +# Notebook +notebook = gtk.Notebook() +notebook.append_page(memphis_widget, gtk.Label('Memphis')) +notebook.append_page(logviewer_widget, gtk.Label('Log Viewer')) +notebook.append_page(terminal_widget, gtk.Label('Terminal')) + +notebook.show() + +window.add(notebook) +window.show() +gtk.main() diff --git a/shell/sugar-log-viewer b/shell/console/logviewer.py old mode 100755 new mode 100644 similarity index 86% rename from shell/sugar-log-viewer rename to shell/console/logviewer.py index 4b7d7c07..fb589a27 --- a/shell/sugar-log-viewer +++ b/shell/console/logviewer.py @@ -91,18 +91,11 @@ class MultiLogView(gtk.Notebook): return True -window = gtk.Window() -window.set_default_size(gtk.gdk.screen_width() * 3 / 4, - gtk.gdk.screen_height() * 3 / 4) +class Interface: -window.realize() -window.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) - -path = os.path.join(env.get_profile_path(), 'logs') -viewer = MultiLogView(path) -window.add(viewer) -viewer.show() - -window.show() - -gtk.main() + def __init__(self): + path = os.path.join(env.get_profile_path(), 'logs') + viewer = MultiLogView(path) + viewer.show() + self.widget = viewer + \ No newline at end of file diff --git a/shell/console/memphis.py b/shell/console/memphis.py new file mode 100644 index 00000000..45139879 --- /dev/null +++ b/shell/console/memphis.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python + +import sys, os +import string +import wnck +import plugin + +from procmem import proc + +try: + import gtk + import gtk.gdk + import gobject +except: + sys.exit(1) + +class Interface: + + store_data_types = [] + store_data_types_details = [] + + def __init__(self): + + # Our GtkTree (Treeview) + self.treeview = gtk.TreeView() + self.widget = self.treeview + + # Loading plugins + self.plg = plugin.Plugin() + + # TOP data types (columns) + self.store_data_types = [] + + for plg in self.plg.list: + plg_data = plg.INTERNALS + + # Give plugin object to plugin + plg.INTERNALS['Plg'] = self.plg + + # Creating a store model and loading process data to Treeview + # self.store_data_types, ex [int, str, str, str, int,...] + #self.store = gtk.TreeStore(*self.store_data_types) + self.data = Data(self.treeview, self.plg.list) + +class Data: + + treeview = None + last_col_index = 0 + + store_data_cols = [] + store_data_types = [] + store_data_types_details = [] + + def __init__(self, treeview, plg_list): + + # Top data types + self.plg_list = plg_list + + for plg in self.plg_list: + + if plg.INTERNALS['top_data'] != None: + last_dt = len(self.store_data_types) + + if last_dt > 0: + last_dt -= 1 + + len_dt = len(plg.INTERNALS['top_data']) + + self.store_data_types_details.append({"plugin": plg, "init": last_dt, "end": last_dt + len_dt}) + + for dt in plg.INTERNALS['top_data']: + self.store_data_types.append(dt) + + for col in plg.INTERNALS['top_cols']: + self.store_data_cols.append(col) + + # Set global treeview + self.treeview = treeview + + # Basic columns + index = 0 + for column_name in self.store_data_cols: + self.add_column(column_name, index) + index += 1 + + self.store = gtk.TreeStore(*self.store_data_types) + treeview.set_model(self.store) + + # Update information every 1 second + gobject.timeout_add(500, self.load_data, treeview) + + # Add a new column to the main treeview + def add_column(self, column_name, index): + cell = gtk.CellRendererText() + col_tv = gtk.TreeViewColumn(column_name, cell, text=index) + col_tv.set_resizable(True) + col_tv.connect('clicked', self.sort_column_clicked) + col_tv.set_property('clickable', True) + + self.treeview.append_column(col_tv) + + # Set the last column index added + self.last_col_index = index + + # Sorting + def sort_column_clicked(self, TreeViewColumn): + cols = self.treeview.get_columns() + + # Searching column index + index = 0 + for col in cols: + if col == TreeViewColumn: + break + + index += 1 + + self.store.set_sort_column_id(index, gtk.SORT_DESCENDING) + + def load_data(self, treeview): + self.store.clear() + + # Getting procfs data + self.procdata = proc.ProcInfo() + self.process_list = [] + + pids = [] + screen = wnck.screen_get_default() + windows = screen.get_windows() + + current_pid = os.getpid() + + for win in windows: + pid = int(win.get_pid()) + if current_pid != pid: + pids.append(pid) + + self.process_list = set(pids) + + # Sort rows using pid + #self.process_list.sort(key=operator.itemgetter('pid')) + self.process_iter = [] + + for pid in self.process_list: + pi = self.build_row(self.store, None, self.procdata, pid) + self.process_iter.append(pi) + + treeview.set_rules_hint(True) + treeview.expand_all() + + return True + + def build_row(self, store, parent_iter, proc_data, pid): + data = [] + + pinfo = proc_data.MemoryInfo(pid) + + # Look for plugins that need to update the top data treeview + for plg in self.plg_list: + plg_data = [] + + if plg.INTERNALS['top_data'] != None: + # data = [xxx, yyy,zzz,...] + plg_data = plg.info.plg_on_top_data_refresh(plg, pinfo) + + for field in plg_data: + data.append(field) + + pi = self.insert_row(store, parent_iter, data) + + return pi + + # Insert a Row in our TreeView + def insert_row(self, store, parent, row_data): + iter = store.insert_after(parent, None) + + index = 0 + + for data in row_data: + store.set_value(iter, index , data) + index += 1 + + return iter diff --git a/shell/console/plugin.py b/shell/console/plugin.py new file mode 100755 index 00000000..5ad5ba20 --- /dev/null +++ b/shell/console/plugin.py @@ -0,0 +1,50 @@ +############################################### +# Memphis Plugin Support +############################################### + +import sys, os, time +import gtk, gobject + +from procmem import proc, proc_smaps, analysis + +class Plugin: + + # Plugin list + list = [] + proc = proc.ProcInfo() + + internal_plugin = "memphis_init" + plg_path = os.path.dirname(os.path.abspath(__file__)) + "/plugins" + + # Frequency timer, managed by main program + freq_timer = 0 + + def __init__(self): + + sys.path.insert(0, self.plg_path) + + # Including memphis plugin + self.list.append(__import__(self.internal_plugin)) + + if os.path.isdir(self.plg_path): + # around dir entries + for plg in os.listdir(self.plg_path): + + if plg == self.internal_plugin: + continue + + if os.path.isdir(self.plg_path + "/" + plg): + p = __import__(plg) + self.list.append(__import__(plg)) + + # Parse /proc/PID/smaps information + def proc_get_smaps(self, pid): + return proc_smaps.ProcSmaps(pid) + + # Parse /proc/PID/maps information + def proc_get_maps(self, pid): + return proc_smaps.ProcMaps(pid) + + def proc_analysis(self, pid): + return analysis.Analysis(pid) + \ No newline at end of file diff --git a/shell/console/plugins/Makefile.am b/shell/console/plugins/Makefile.am new file mode 100644 index 00000000..8d71fb86 --- /dev/null +++ b/shell/console/plugins/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = clean_size cpu dirty_size memphis_init + +sugardir = $(pkgdatadir)/shell/console/plugins +sugar_PYTHON = diff --git a/shell/console/plugins/clean_size/Makefile.am b/shell/console/plugins/clean_size/Makefile.am new file mode 100644 index 00000000..9b0a7d0a --- /dev/null +++ b/shell/console/plugins/clean_size/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/plugins/clean_size +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/shell/console/plugins/clean_size/README b/shell/console/plugins/clean_size/README new file mode 100644 index 00000000..3dd3ae33 --- /dev/null +++ b/shell/console/plugins/clean_size/README @@ -0,0 +1,2 @@ +This plugin give support to get the clean size memory usage +by process using the /proc/PID/maps file. diff --git a/shell/console/plugins/clean_size/__init__.py b/shell/console/plugins/clean_size/__init__.py new file mode 100644 index 00000000..fed740c0 --- /dev/null +++ b/shell/console/plugins/clean_size/__init__.py @@ -0,0 +1,16 @@ + +import info + +INTERNALS = { + # Basic information + 'PLGNAME': "Clean Size", + 'TABNAME': None, + 'AUTHOR': "Eduardo Silva", + 'DESC': "Print the approx real memory usage", + + # Plugin API + 'Plg': None, # Plugin object + + 'top_data': [int], # Top data types needed by memphis core plugin + 'top_cols': ["Approx Real Usage (kb)"] + } diff --git a/shell/console/plugins/clean_size/info.py b/shell/console/plugins/clean_size/info.py new file mode 100644 index 00000000..e223ea54 --- /dev/null +++ b/shell/console/plugins/clean_size/info.py @@ -0,0 +1,15 @@ +########################################################### +# Main function: +# ----------------- +# self: self plugin object +# mself: memphis object / principal class +# pinfo: row with information about current tracing process +############################################################ + +def plg_on_top_data_refresh(self, pinfo): + + # Get clean size + maps = self.INTERNALS['Plg'].proc_get_maps(pinfo['pid']) + + size = (maps.clean_size/1024) + return [size] diff --git a/shell/console/plugins/cpu/Makefile.am b/shell/console/plugins/cpu/Makefile.am new file mode 100644 index 00000000..e796a97a --- /dev/null +++ b/shell/console/plugins/cpu/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/plugins/cpu +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/shell/console/plugins/cpu/README b/shell/console/plugins/cpu/README new file mode 100644 index 00000000..9c7d6f31 --- /dev/null +++ b/shell/console/plugins/cpu/README @@ -0,0 +1,2 @@ +This plugin give support to draw the Virtual Memory Size +usage by the current tracing process. diff --git a/shell/console/plugins/cpu/__init__.py b/shell/console/plugins/cpu/__init__.py new file mode 100644 index 00000000..3ec61356 --- /dev/null +++ b/shell/console/plugins/cpu/__init__.py @@ -0,0 +1,23 @@ +import os +import info + +INTERNALS = { + 'PLGNAME': "cpu", + 'TABNAME': None, + 'AUTHOR': "Eduardo Silva", + 'DESC': "Print CPU usage", + + # Plugin API + 'Plg': None, # Plugin object + 'current_plg': None, # Current plugin object + 'current_page': None, # Current page number + + # Top process view requirements + 'top_data': [int], # Top data types needed by memphis core plugin + 'top_cols': ["%CPU "] # Column names + } + +# Get CPU frequency +cpu_hz = os.sysconf(2) + +pids_ujiffies = {} diff --git a/shell/console/plugins/cpu/info.py b/shell/console/plugins/cpu/info.py new file mode 100644 index 00000000..b8b715ef --- /dev/null +++ b/shell/console/plugins/cpu/info.py @@ -0,0 +1,48 @@ +########################################################### +# Main function: +# ----------------- +# self: self plugin object +# mself: memphis object / principal class +# pinfo: row with information about current tracing process +############################################################ + +def plg_on_top_data_refresh(self, pinfo): + PI = self.INTERNALS['Plg'].proc + + pid = pinfo['pid'] + + # Get JIFFIES CPU usage + used_jiffies = pinfo['utime'] + pinfo['stime'] + last_ujiffies = get_pid_ujiffies(self, pid) + + cpu_usage = PI.get_CPU_usage(self.cpu_hz, used_jiffies, pinfo['start_time']) + + # Get PERCENT CPU usage + if last_ujiffies == 0.0: + pcpu = 0.0 + set_pid_ujiffies(self, pid, cpu_usage['used_jiffies']) + data = [int(pcpu)] + return data + + used_jiffies = cpu_usage['used_jiffies'] - last_ujiffies + + # Available jiffies are + avail_jiffies = (500/1000.0)*self.cpu_hz # 500 = 0.5 second + pcpu = ((used_jiffies*100)/avail_jiffies) + + set_pid_ujiffies(self, pid, cpu_usage['used_jiffies']) + + data = [int(pcpu)] + return data + +def get_pid_ujiffies(self, pid): + + if pid in self.pids_ujiffies: + return self.pids_ujiffies[pid] + else: + set_pid_ujiffies(self, pid, 0) + return self.pids_ujiffies[pid] + +def set_pid_ujiffies(self, pid, ujiffies): + self.pids_ujiffies[pid] = ujiffies + diff --git a/shell/console/plugins/dirty_size/Makefile.am b/shell/console/plugins/dirty_size/Makefile.am new file mode 100644 index 00000000..f97813e8 --- /dev/null +++ b/shell/console/plugins/dirty_size/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/plugins/dirty_size +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/shell/console/plugins/dirty_size/README b/shell/console/plugins/dirty_size/README new file mode 100644 index 00000000..ee4d1a5e --- /dev/null +++ b/shell/console/plugins/dirty_size/README @@ -0,0 +1,2 @@ +This plugin give support to get the public and shared dirty memory usage +by process using the /proc/PID/smaps file. diff --git a/shell/console/plugins/dirty_size/__init__.py b/shell/console/plugins/dirty_size/__init__.py new file mode 100644 index 00000000..2661db86 --- /dev/null +++ b/shell/console/plugins/dirty_size/__init__.py @@ -0,0 +1,17 @@ + +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/shell/console/plugins/dirty_size/info.py b/shell/console/plugins/dirty_size/info.py new file mode 100644 index 00000000..631d86a9 --- /dev/null +++ b/shell/console/plugins/dirty_size/info.py @@ -0,0 +1,20 @@ +########################################################### +# Main function: +# ----------------- +# self: self plugin object +# mself: memphis object / principal class +# pinfo: row with information about current tracing process +############################################################ + + +def plg_on_top_data_refresh(self, ppinfo): + + dirty_sizes = get_dirty(self, ppinfo['pid']) + + # memhis need an array + return [dirty_sizes['private']] + +def get_dirty(pself, pid): + ProcAnalysis = pself.INTERNALS['Plg'].proc_analysis(pid) + + return ProcAnalysis.DirtyRSS() diff --git a/shell/console/plugins/memphis_init/Makefile.am b/shell/console/plugins/memphis_init/Makefile.am new file mode 100644 index 00000000..3f986185 --- /dev/null +++ b/shell/console/plugins/memphis_init/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/plugins/memphis_init +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/shell/console/plugins/memphis_init/README b/shell/console/plugins/memphis_init/README new file mode 100644 index 00000000..9c7d6f31 --- /dev/null +++ b/shell/console/plugins/memphis_init/README @@ -0,0 +1,2 @@ +This plugin give support to draw the Virtual Memory Size +usage by the current tracing process. diff --git a/shell/console/plugins/memphis_init/__init__.py b/shell/console/plugins/memphis_init/__init__.py new file mode 100644 index 00000000..c13ce2ea --- /dev/null +++ b/shell/console/plugins/memphis_init/__init__.py @@ -0,0 +1,15 @@ +import info + +INTERNALS = { + 'PLGNAME': "memphis", + 'TABNAME': None, + 'AUTHOR': "Eduardo Silva", + 'DESC': "Print basic process information", + + # Plugin API + 'Plg': None, # Plugin object + + # Top process view requirements + 'top_data': [int, str, str], # Top data types needed by memphis core plugin + 'top_cols': ["PID", "Process Name", "Status"] # Column names + } diff --git a/shell/console/plugins/memphis_init/info.py b/shell/console/plugins/memphis_init/info.py new file mode 100644 index 00000000..94d2d43c --- /dev/null +++ b/shell/console/plugins/memphis_init/info.py @@ -0,0 +1,13 @@ +########################################################### +# Main function: +# ----------------- +# self: self plugin object +# mself: memphis object / principal class +# pinfo: row with information about current tracing process +############################################################ + +def plg_on_top_data_refresh(self, ppinfo): + + data = [ppinfo['pid'], ppinfo['name'], ppinfo['state_name']] + + return data diff --git a/shell/console/procmem/Makefile.am b/shell/console/procmem/Makefile.am new file mode 100644 index 00000000..eface373 --- /dev/null +++ b/shell/console/procmem/Makefile.am @@ -0,0 +1,8 @@ + +sugardir = $(pkgdatadir)/shell/console/procmem + +sugar_PYTHON = \ + __init__.py \ + proc.py \ + proc_smaps.py \ + analysis.py diff --git a/shell/console/procmem/__init__.py b/shell/console/procmem/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/shell/console/procmem/analysis.py b/shell/console/procmem/analysis.py new file mode 100644 index 00000000..a468acd3 --- /dev/null +++ b/shell/console/procmem/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 + \ No newline at end of file diff --git a/shell/console/procmem/proc.py b/shell/console/procmem/proc.py new file mode 100644 index 00000000..af0a6564 --- /dev/null +++ b/shell/console/procmem/proc.py @@ -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 + diff --git a/shell/console/procmem/proc_smaps.py b/shell/console/procmem/proc_smaps.py new file mode 100644 index 00000000..84bef433 --- /dev/null +++ b/shell/console/procmem/proc_smaps.py @@ -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 diff --git a/shell/console/terminal.py b/shell/console/terminal.py new file mode 100644 index 00000000..e0330902 --- /dev/null +++ b/shell/console/terminal.py @@ -0,0 +1,143 @@ +import gtk +import vte +import pango + +class Terminal(gtk.HBox): + def __init__(self): + gtk.HBox.__init__(self, False, 4) + + self._vte = vte.Terminal() + self._configure_vte() + self._vte.set_size(30, 5) + self._vte.set_size_request(200, 350) + self._vte.show() + self.pack_start(self._vte) + + self._scrollbar = gtk.VScrollbar(self._vte.get_adjustment()) + self._scrollbar.show() + self.pack_start(self._scrollbar, False, False, 0) + + self._vte.connect("child-exited", lambda term: term.fork_command()) + + self._vte.fork_command() + + def _configure_vte(self): + self._vte.set_font(pango.FontDescription('Monospace 10')) + self._vte.set_colors(gtk.gdk.color_parse ('#AAAAAA'), + gtk.gdk.color_parse ('#000000'), + []) + self._vte.set_cursor_blinks(False) + self._vte.set_audible_bell(False) + self._vte.set_scrollback_lines(100) + self._vte.set_allow_bold(True) + self._vte.set_scroll_on_keystroke(False) + self._vte.set_scroll_on_output(False) + self._vte.set_emulation('xterm') + self._vte.set_visible_bell(False) + + def on_gconf_notification(self, client, cnxn_id, entry, what): + self.reconfigure_vte() + + def on_vte_button_press(self, term, event): + if event.button == 3: + self.do_popup(event) + return True + + def on_vte_popup_menu(self, term): + pass + +class Multiple: + + page_number = 0 + + def __init__(self): + self.notebook = gtk.Notebook() + self.add_new_terminal() + + open_terminal = gtk.Button('Open a new terminal') + open_terminal.connect("clicked", self.add_new_terminal) + open_terminal.show() + + self.notebook.show() + + self.main_vbox = gtk.VBox(False, 3) + self.main_vbox.pack_start(open_terminal, True, True, 5) + self.main_vbox.pack_start(self.notebook, True, True, 5) + + self.main_vbox.show_all() + + # Remove a page from the notebook + def close_terminal(self, button, child): + page = self.notebook.page_num(child) + + if page != -1: + self.notebook.remove_page(page) + + + pages = self.notebook.get_n_pages() + if pages <= 0: + self.page_number = 0 + self.add_new_terminal() + + # Need to refresh the widget -- + # This forces the widget to redraw itself. + self.notebook.queue_draw_area(0, 0, -1, -1) + + def add_icon_to_button(self, button): + iconBox = gtk.HBox(False, 0) + image = gtk.Image() + image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU) + gtk.Button.set_relief(button, gtk.RELIEF_NONE) + + settings = gtk.Widget.get_settings (button) + (w,h) = gtk.icon_size_lookup_for_settings (settings, gtk.ICON_SIZE_MENU) + gtk.Widget.set_size_request (button, w + 4, h + 4) + image.show() + iconBox.pack_start(image, True, False, 0) + button.add(iconBox) + iconBox.show() + + def add_new_terminal(self, *arguments, **keywords): + self.page_number += 1 + + terminal = Terminal() + terminal.show() + + eventBox = self.create_custom_tab("Term %d" % self.page_number, terminal) + self.notebook.append_page(terminal, eventBox) + + # Set the new page + pages = gtk.Notebook.get_n_pages(self.notebook) + self.notebook.set_current_page(pages - 1) + return True + + def create_custom_tab(self, text, child): + eventBox = gtk.EventBox() + tabBox = gtk.HBox(False, 2) + tabLabel = gtk.Label(text) + + tabButton = gtk.Button() + tabButton.connect('clicked', self.close_terminal, child) + + # Add a picture on a button + self.add_icon_to_button(tabButton) + iconBox = gtk.HBox(False, 0) + + eventBox.show() + tabButton.show() + tabLabel.show() + + tabBox.pack_start(tabLabel, False) + tabBox.pack_start(tabButton, False) + + tabBox.show_all() + eventBox.add(tabBox) + + return eventBox + +class Interface: + + def __init__(self): + multiple = Multiple() + self.widget = multiple.main_vbox + \ No newline at end of file diff --git a/shell/data/kbdconfig b/shell/data/kbdconfig index 30e49538..132cf6f9 100644 --- a/shell/data/kbdconfig +++ b/shell/data/kbdconfig @@ -6,6 +6,6 @@ p=prev c=close -F12=!sugar-log-viewer +F12=!sugar-devel-console q=!sugar-emulator-shutdown Escape=!sugar-shutdown diff --git a/shell/sugar-devel-console b/shell/sugar-devel-console new file mode 100755 index 00000000..bf679d21 --- /dev/null +++ b/shell/sugar-devel-console @@ -0,0 +1,9 @@ +#!/usr/bin/env python + +# Sugar developer console launcher +import os, sys +from sugar import env + +sys.path.insert(0, os.path.join(env.get_data_dir(), 'shell')) + +import console.console diff --git a/sugar/activity/Activity.py b/sugar/activity/Activity.py index 16143300..2f273031 100644 --- a/sugar/activity/Activity.py +++ b/sugar/activity/Activity.py @@ -100,6 +100,7 @@ class Activity(gtk.Window): bus = dbus.SessionBus() xid = self.window.xid + bus_name = dbus.service.BusName(get_service_name(xid), bus=bus) self._bus = ActivityDbusService(bus_name, get_object_path(xid)) self._bus.start(self._pservice, self) From 9031ebf503b891e394ff41379cf21eb6a17afba3 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 16 Nov 2006 10:46:13 -0300 Subject: [PATCH 3/3] developer console window size fixes --- shell/console/console.py | 12 ++++++------ shell/console/terminal.py | 6 +++--- shell/sugar-devel-console | 3 +++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/shell/console/console.py b/shell/console/console.py index 45d1bb19..565b973c 100755 --- a/shell/console/console.py +++ b/shell/console/console.py @@ -10,8 +10,8 @@ import terminal window = gtk.Window() window.set_title('Developer console') -width = gtk.gdk.screen_width()* 95 / 100 -height = gtk.gdk.screen_height() * 3 / 4 +width = gtk.gdk.screen_width() * 95 / 100 +height = gtk.gdk.screen_height() * 95 / 100 window.set_default_size(width, height) @@ -19,14 +19,14 @@ window.realize() window.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) # Memphis interface -memphis_widget = memphis.Interface().widget +memphis_widget = memphis.Interface().widget memphis_widget.show() -# Sugar log viewer interface -logviewer_widget = logviewer.Interface().widget +# Log viewer interface +logviewer_widget = logviewer.Interface().widget logviewer_widget.show() -# Sugar log viewer interface +# Terminal interface terminal_widget = terminal.Interface().widget terminal_widget.show() diff --git a/shell/console/terminal.py b/shell/console/terminal.py index e0330902..6a92661e 100644 --- a/shell/console/terminal.py +++ b/shell/console/terminal.py @@ -9,7 +9,7 @@ class Terminal(gtk.HBox): self._vte = vte.Terminal() self._configure_vte() self._vte.set_size(30, 5) - self._vte.set_size_request(200, 350) + self._vte.set_size_request(200, 450) self._vte.show() self.pack_start(self._vte) @@ -61,8 +61,8 @@ class Multiple: self.notebook.show() self.main_vbox = gtk.VBox(False, 3) - self.main_vbox.pack_start(open_terminal, True, True, 5) - self.main_vbox.pack_start(self.notebook, True, True, 5) + self.main_vbox.pack_start(open_terminal, True, True, 2) + self.main_vbox.pack_start(self.notebook, True, True, 2) self.main_vbox.show_all() diff --git a/shell/sugar-devel-console b/shell/sugar-devel-console index bf679d21..707f8344 100755 --- a/shell/sugar-devel-console +++ b/shell/sugar-devel-console @@ -1,6 +1,9 @@ #!/usr/bin/env python # Sugar developer console launcher +import pygtk +pygtk.require('2.0') + import os, sys from sugar import env