blob: 3a9f8a5304148b2670839062e1bf27d1100b0a54 [file] [log] [blame]
#
# Copyright (C) International Business Machines Corp., 2009
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# 2009-Dec-31: Initial version by Darren Hart <dvhltc@us.ibm.com>
#
import gobject #delete me ?
import time
import sys
import gtk
from tracecmd import *
from ctracecmdgui import *
"""
Python interface for tracecmd GTK widgets
Python tracecmd applications should be written to this interface. It will be
updated as the tracecmd gui C API changes and try to minimze the impact to
python applications. The ctracecmdgui Python module is automatically generated
using SWIG and it is recommended applications not use it directly.
"""
# In a "real" app these width should be determined at runtime testing max length
# strings in the current font.
TS_COL_W = 150
CPU_COL_W = 35
EVENT_COL_W = 150
PID_COL_W = 75
COMM_COL_W = 250
def timing(func):
def wrapper(*arg):
start = time.time()
ret = func(*arg)
end = time.time()
print '@%s took %0.3f s' % (func.func_name, (end-start))
return ret
return wrapper
class EventStore(gtk.GenericTreeModel):
# FIXME: get these from the C code: trace_view_store->column_types ...
@timing
def __init__(self, trace):
gtk.GenericTreeModel.__init__(self)
self.trace = trace
self.cstore = trace_view_store_new(trace.handle)
self.gtk_cstore = trace_view_store_as_gtk_tree_model(self.cstore)
num_rows = trace_view_store_num_rows_get(self.cstore)
print "Loaded %d events from trace" % (num_rows)
def on_get_flags(self):
return trace_view_store_get_flags(self.gtk_cstore)
def on_get_n_columns(self):
return trace_view_store_get_n_columns(self.gtk_cstore)
def on_get_column_type(self, col):
# I couldn't figure out how to convert the C GType into the python
# GType. The current typemap converts the C GType into the python type,
# which is what this function is supposed to return anyway.
pytype = trace_view_store_get_column_type(self.gtk_cstore, col)
return pytype
def on_get_iter(self, path):
if len(path) > 1 and path[1] != 1:
return None
n = path[0]
rec = trace_view_store_get_row(self.cstore, n)
return rec
def on_get_path(self, rec):
if not rec:
return None
start_row = trace_view_store_start_row_get(self.cstore)
return (trace_view_record_pos_get(rec) - start_row,)
def on_get_value(self, rec, col):
# FIXME: write SWIG wrapper to marshal the Gvalue and wrap the rec in an
# Iter
pass
#return trace_view_store_get_value_py(self.cstore, rec, col)
def on_iter_next(self, rec):
pos = trace_view_record_pos_get(rec)
start_row = trace_view_store_start_row_get(self.cstore)
return trace_view_store_get_row(self.cstore, pos - start_row + 1)
def on_iter_children(self, rec):
if rec:
return None
return trace_view_store_get_row(self.cstore, 0)
def on_iter_has_child(self, rec):
return False
def on_iter_n_children(self, rec):
if rec:
return 0
return trace_view_store_num_rows_get(self.cstore)
def on_iter_nth_child(self, rec, n):
if rec:
return None
return trace_view_store_get_row(self.cstore, n)
def on_iter_parent(self, child):
return None
def get_event(self, iter):
path = self.get_path(iter)
if not path:
return None
rec = trace_view_store_get_row(self.cstore, path[0])
if not rec:
return None
ev = self.trace.read_event_at(trace_view_record_offset_get(rec))
return ev
class EventView(gtk.TreeView):
def __init__(self, model):
gtk.TreeView.__init__(self, model)
self.set_fixed_height_mode(True)
ts_col = gtk.TreeViewColumn("Time (s)")
ts_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
ts_col.set_fixed_width(TS_COL_W)
ts_cell = gtk.CellRendererText()
ts_col.pack_start(ts_cell, False)
ts_col.set_cell_data_func(ts_cell, self.data_func, "ts")
self.append_column(ts_col)
cpu_col = gtk.TreeViewColumn("CPU")
cpu_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
cpu_col.set_fixed_width(CPU_COL_W)
cpu_cell = gtk.CellRendererText()
cpu_col.pack_start(cpu_cell, False)
cpu_col.set_cell_data_func(cpu_cell, self.data_func, "cpu")
self.append_column(cpu_col)
event_col = gtk.TreeViewColumn("Event")
event_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
event_col.set_fixed_width(EVENT_COL_W)
event_cell = gtk.CellRendererText()
event_col.pack_start(event_cell, False)
event_col.set_cell_data_func(event_cell, self.data_func, "event")
self.append_column(event_col)
pid_col = gtk.TreeViewColumn("PID")
pid_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
pid_col.set_fixed_width(PID_COL_W)
pid_cell = gtk.CellRendererText()
pid_col.pack_start(pid_cell, False)
pid_col.set_cell_data_func(pid_cell, self.data_func, "pid")
self.append_column(pid_col)
comm_col = gtk.TreeViewColumn("Comm")
comm_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
comm_col.set_fixed_width(COMM_COL_W)
comm_cell = gtk.CellRendererText()
comm_col.pack_start(comm_cell, False)
comm_col.set_cell_data_func(comm_cell, self.data_func, "comm")
self.append_column(comm_col)
def data_func(self, col, cell, model, iter, data):
ev = model.get_event(iter)
#ev = model.get_value(iter, 0)
if not ev:
return False
if data == "ts":
cell.set_property("markup", "%d.%d" % (ev.ts/1000000000,
ev.ts%1000000000))
elif data == "cpu":
cell.set_property("markup", ev.cpu)
elif data == "event":
cell.set_property("markup", ev.name)
elif data == "pid":
cell.set_property("markup", ev.pid)
elif data == "comm":
cell.set_property("markup", ev.comm)
else:
print "Unknown Column:", data
return False
return True
class EventViewerApp(gtk.Window):
def __init__(self, trace):
gtk.Window.__init__(self)
self.set_size_request(650, 400)
self.set_position(gtk.WIN_POS_CENTER)
self.connect("destroy", gtk.main_quit)
self.set_title("Event Viewer")
store = EventStore(trace)
view = EventView(store)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
sw.add(view)
# track how often the treeview data_func is called
self.add(sw)
self.show_all()
# Basic builtin test, execute module directly
if __name__ == "__main__":
if len(sys.argv) >=2:
filename = sys.argv[1]
else:
filename = "trace.dat"
print "Initializing trace..."
trace = Trace(filename)
print "Initializing app..."
app = EventViewerApp(trace)
print "Go!"
gtk.main()