diff options
Diffstat (limited to 'python/event-viewer.py')
-rwxr-xr-x | python/event-viewer.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/python/event-viewer.py b/python/event-viewer.py new file mode 100755 index 00000000..e3b2edd4 --- /dev/null +++ b/python/event-viewer.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python2 + +import getopt +from gobject import * +import gtk +from tracecmd import * +import time + +app = None +data_func_cnt = 0 + +# 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): + class EventRef(object): + '''Inner class to build the trace event index''' + def __init__(self, index, timestamp, offset, cpu): + self.index = index + self.offset = offset + self.ts = timestamp + self.cpu = cpu + + def __cmp__(self, other): + if self.ts < other.ts: + return -1 + if self.ts > other.ts: + return 1 + if self.offset < other.offset: + return -1 + if self.offset > other.offset: + return 1 + return 0 + + # The store only returns the record offset into the trace + # The view is responsible for looking up the Event with the offset + column_types = (long,) + + @timing + def __init__(self, trace): + gtk.GenericTreeModel.__init__(self) + self.trace = trace + self.refs = [] + self._load_trace() + self._sort() + self._reindex() + + @timing + def _load_trace(self): + print("Building trace index...") + index = 0 + for cpu in range(0, trace.cpus): + rec = tracecmd_read_data(self.trace._handle, cpu) + while rec: + offset = tep_record_offset_get(rec) + ts = tep_record_ts_get(rec) + self.refs.append(self.EventRef(index, ts, offset, cpu)) + index = index + 1 + rec = tracecmd_read_data(self.trace._handle, cpu) + print("Loaded %d events from trace" % (index)) + + @timing + def _sort(self): + self.refs.sort() + + @timing + def _reindex(self): + for i in range(0, len(self.refs)): + self.refs[i].index = i + + def on_get_flags(self): + return gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST + + def on_get_n_columns(self): + return len(self.column_types) + + def on_get_column_type(self, col): + return self.column_types[col] + + def on_get_iter(self, path): + return self.refs[path[0]] + + def on_get_path(self, ref): + return ref.index + + def on_get_value(self, ref, col): + ''' + The Event record was getting deleted when passed back via this + method, now it just returns the ref itself. Use get_event() instead. + ''' + if col == 0: + #return self.trace.read_event_at(ref.offset) + return ref + return None + + def on_iter_next(self, ref): + try: + return self.refs[ref.index+1] + except IndexError: + return None + + def on_iter_children(self, ref): + if ref: + return None + return self.refs[0] + + def on_iter_has_child(self, ref): + return False + + def on_iter_n_children(self, ref): + if ref: + return 0 + return len(self.refs) + + def on_iter_nth_child(self, ref, n): + if ref: + return None + try: + return self.refs[n] + except IndexError: + return None + + def on_iter_parent(self, child): + return None + + def get_event(self, iter): + '''This allocates a record which must be freed by the caller''' + try: + ref = self.refs[self.get_path(iter)[0]] + ev = self.trace.read_event_at(ref.offset) + return ev + except IndexError: + return None + + +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): + global app, data_func_cnt + + ev = model.get_event(iter) + #ev = model.get_value(iter, 0) + if not ev: + return False + + if data == "ts": + cell.set_property("markup", "%d.%09d" % (ev.ts/1000000000, + ev.ts%1000000000)) + data_func_cnt = data_func_cnt + 1 + if app: + app.inc_data_func() + 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.data_func_label = gtk.Label("0") + hbox = gtk.HBox() + hbox.pack_start(gtk.Label("TS Data Func Calls:"), False, False) + hbox.pack_start(self.data_func_label, False, False) + + vbox = gtk.VBox() + vbox.pack_start(hbox, False) + vbox.pack_end(sw) + + self.add(vbox) + self.show_all() + + def inc_data_func(self): + global data_func_cnt + self.data_func_label.set_text(str(data_func_cnt)) + + +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() |