240 lines
7.7 KiB
Python
240 lines
7.7 KiB
Python
#
|
|
# 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()
|