| # |
| # 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 <[email protected]> |
| # |
| |
| 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() |