diff options
Diffstat (limited to 'services/console/interface/memphis')
21 files changed, 498 insertions, 0 deletions
diff --git a/services/console/interface/memphis/Makefile.am b/services/console/interface/memphis/Makefile.am new file mode 100644 index 0000000..319dad6 --- /dev/null +++ b/services/console/interface/memphis/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS = plugins + +sugardir = $(pkgdatadir)/shell/console/interface/memphis +sugar_PYTHON = \ + __init__.py \ + memphis.py \ + plugin.py + diff --git a/services/console/interface/memphis/__init__.py b/services/console/interface/memphis/__init__.py new file mode 100644 index 0000000..145d9d4 --- /dev/null +++ b/services/console/interface/memphis/__init__.py @@ -0,0 +1 @@ +from memphis import Interface diff --git a/services/console/interface/memphis/memphis.py b/services/console/interface/memphis/memphis.py new file mode 100644 index 0000000..8fbc85b --- /dev/null +++ b/services/console/interface/memphis/memphis.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python + +# Copyright (C) 2006, Eduardo Silva (edsiper@gmail.com). +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import 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.treeview.show() + + self.button_start = gtk.Button('Start Memphis') + self.button_stop = gtk.Button('Stop Memphis') + + fixed = gtk.Fixed() + fixed.add(self.button_start) + fixed.add(self.button_stop) + + vbox = gtk.VBox(False) + vbox.set_border_width(5) + vbox.pack_start(fixed, True, True, 0) + + # Our GtkTree (Treeview) + self.treeview = gtk.TreeView() + t_width = gtk.gdk.screen_width() + t_height = gtk.gdk.screen_height() * 83 / 100 + + self.treeview.set_size_request(t_width, t_height) + vbox.pack_start(self.treeview, True, True, 0) + vbox.show_all() + self.widget = vbox + + # 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, self.treeview, self.plg.list) + + self.button_stop.hide() + self.button_start.connect('clicked', self.data._start_memphis) + self.button_stop.connect('clicked', self.data._stop_memphis) + +class Data: + + last_col_index = 0 + + store_data_cols = [] + store_data_types = [] + store_data_types_details = [] + + _running_status = False + + def __init__(self, interface, treeview, plg_list): + + self.interface = interface + + # 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) + + 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) + + def _stop_memphis(self, button): + + self._running_status = False + button.hide() + self.interface.button_start.show() + + # 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 self._running_status + + 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/services/console/interface/memphis/plugin.py b/services/console/interface/memphis/plugin.py new file mode 100644 index 0000000..5ee8eb7 --- /dev/null +++ b/services/console/interface/memphis/plugin.py @@ -0,0 +1,48 @@ +############################################### +# Memphis Plugin Support +############################################### + +import sys, os +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) + diff --git a/services/console/interface/memphis/plugins/Makefile.am b/services/console/interface/memphis/plugins/Makefile.am new file mode 100644 index 0000000..2c6b1dd --- /dev/null +++ b/services/console/interface/memphis/plugins/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = clean_size cpu dirty_size memphis_init + +sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins +sugar_PYTHON = diff --git a/services/console/interface/memphis/plugins/clean_size/Makefile.am b/services/console/interface/memphis/plugins/clean_size/Makefile.am new file mode 100644 index 0000000..33565f5 --- /dev/null +++ b/services/console/interface/memphis/plugins/clean_size/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/clean_size +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/services/console/interface/memphis/plugins/clean_size/README b/services/console/interface/memphis/plugins/clean_size/README new file mode 100644 index 0000000..3dd3ae3 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/clean_size/__init__.py b/services/console/interface/memphis/plugins/clean_size/__init__.py new file mode 100644 index 0000000..75ce1d1 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/clean_size/info.py b/services/console/interface/memphis/plugins/clean_size/info.py new file mode 100644 index 0000000..25ed044 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/cpu/Makefile.am b/services/console/interface/memphis/plugins/cpu/Makefile.am new file mode 100644 index 0000000..58e9eab --- /dev/null +++ b/services/console/interface/memphis/plugins/cpu/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/cpu +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/services/console/interface/memphis/plugins/cpu/README b/services/console/interface/memphis/plugins/cpu/README new file mode 100644 index 0000000..9c7d6f3 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/cpu/__init__.py b/services/console/interface/memphis/plugins/cpu/__init__.py new file mode 100644 index 0000000..e22a413 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/cpu/info.py b/services/console/interface/memphis/plugins/cpu/info.py new file mode 100644 index 0000000..9cb1ad4 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/dirty_size/Makefile.am b/services/console/interface/memphis/plugins/dirty_size/Makefile.am new file mode 100644 index 0000000..47c5298 --- /dev/null +++ b/services/console/interface/memphis/plugins/dirty_size/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/dirty_size +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/services/console/interface/memphis/plugins/dirty_size/README b/services/console/interface/memphis/plugins/dirty_size/README new file mode 100644 index 0000000..ee4d1a5 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/dirty_size/__init__.py b/services/console/interface/memphis/plugins/dirty_size/__init__.py new file mode 100644 index 0000000..f8e9e0a --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/dirty_size/info.py b/services/console/interface/memphis/plugins/dirty_size/info.py new file mode 100644 index 0000000..54a2e7e --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/memphis_init/Makefile.am b/services/console/interface/memphis/plugins/memphis_init/Makefile.am new file mode 100644 index 0000000..53b398a --- /dev/null +++ b/services/console/interface/memphis/plugins/memphis_init/Makefile.am @@ -0,0 +1,6 @@ + +sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/memphis_init +sugar_PYTHON = \ + README \ + __init__.py \ + info.py diff --git a/services/console/interface/memphis/plugins/memphis_init/README b/services/console/interface/memphis/plugins/memphis_init/README new file mode 100644 index 0000000..9c7d6f3 --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/memphis_init/__init__.py b/services/console/interface/memphis/plugins/memphis_init/__init__.py new file mode 100644 index 0000000..f5ada7e --- /dev/null +++ b/services/console/interface/memphis/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/services/console/interface/memphis/plugins/memphis_init/info.py b/services/console/interface/memphis/plugins/memphis_init/info.py new file mode 100644 index 0000000..6e524c7 --- /dev/null +++ b/services/console/interface/memphis/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 |