Rework the console to use autoactivation, move it in services/

This commit is contained in:
Marco Pesenti Gritti
2007-01-08 18:06:59 +01:00
parent 764eee81e5
commit cae78d7041
54 changed files with 83 additions and 98 deletions
@@ -0,0 +1,8 @@
SUBDIRS = plugins
sugardir = $(pkgdatadir)/shell/console/interface/memphis
sugar_PYTHON = \
__init__.py \
memphis.py \
plugin.py
@@ -0,0 +1 @@
from memphis import Interface
@@ -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
@@ -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)
@@ -0,0 +1,4 @@
SUBDIRS = clean_size cpu dirty_size memphis_init
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins
sugar_PYTHON =
@@ -0,0 +1,6 @@
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/clean_size
sugar_PYTHON = \
README \
__init__.py \
info.py
@@ -0,0 +1,2 @@
This plugin give support to get the clean size memory usage
by process using the /proc/PID/maps file.
@@ -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)"]
}
@@ -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]
@@ -0,0 +1,6 @@
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/cpu
sugar_PYTHON = \
README \
__init__.py \
info.py
@@ -0,0 +1,2 @@
This plugin give support to draw the Virtual Memory Size
usage by the current tracing process.
@@ -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 = {}
@@ -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
@@ -0,0 +1,6 @@
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/dirty_size
sugar_PYTHON = \
README \
__init__.py \
info.py
@@ -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.
@@ -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)"]
}
@@ -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()
@@ -0,0 +1,6 @@
sugardir = $(pkgdatadir)/shell/console/interface/memphis/plugins/memphis_init
sugar_PYTHON = \
README \
__init__.py \
info.py
@@ -0,0 +1,2 @@
This plugin give support to draw the Virtual Memory Size
usage by the current tracing process.
@@ -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
}
@@ -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