1# 2# Copyright (C) International Business Machines Corp., 2009 3# 4# This program is free software; you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation; either version 2 of the License, or 7# (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program; if not, write to the Free Software 16# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17# 18# 2009-Dec-31: Initial version by Darren Hart <[email protected]> 19# 20 21import gobject #delete me ? 22import time 23import sys 24import gtk 25from tracecmd import * 26from ctracecmdgui import * 27 28""" 29Python interface for tracecmd GTK widgets 30 31Python tracecmd applications should be written to this interface. It will be 32updated as the tracecmd gui C API changes and try to minimze the impact to 33python applications. The ctracecmdgui Python module is automatically generated 34using SWIG and it is recommended applications not use it directly. 35""" 36 37# In a "real" app these width should be determined at runtime testing max length 38# strings in the current font. 39TS_COL_W = 150 40CPU_COL_W = 35 41EVENT_COL_W = 150 42PID_COL_W = 75 43COMM_COL_W = 250 44 45 46def timing(func): 47 def wrapper(*arg): 48 start = time.time() 49 ret = func(*arg) 50 end = time.time() 51 print('@%s took %0.3f s' % (func.func_name, (end-start))) 52 return ret 53 return wrapper 54 55 56class EventStore(gtk.GenericTreeModel): 57 # FIXME: get these from the C code: trace_view_store->column_types ... 58 @timing 59 def __init__(self, trace): 60 gtk.GenericTreeModel.__init__(self) 61 self.trace = trace 62 self.cstore = trace_view_store_new(trace.handle) 63 self.gtk_cstore = trace_view_store_as_gtk_tree_model(self.cstore) 64 num_rows = trace_view_store_num_rows_get(self.cstore) 65 print("Loaded %d events from trace" % (num_rows)) 66 67 def on_get_flags(self): 68 return trace_view_store_get_flags(self.gtk_cstore) 69 70 def on_get_n_columns(self): 71 return trace_view_store_get_n_columns(self.gtk_cstore) 72 73 def on_get_column_type(self, col): 74 # I couldn't figure out how to convert the C GType into the python 75 # GType. The current typemap converts the C GType into the python type, 76 # which is what this function is supposed to return anyway. 77 pytype = trace_view_store_get_column_type(self.gtk_cstore, col) 78 return pytype 79 80 def on_get_iter(self, path): 81 if len(path) > 1 and path[1] != 1: 82 return None 83 n = path[0] 84 rec = trace_view_store_get_row(self.cstore, n) 85 return rec 86 87 def on_get_path(self, rec): 88 if not rec: 89 return None 90 start_row = trace_view_store_start_row_get(self.cstore) 91 return (trace_view_record_pos_get(rec) - start_row,) 92 93 def on_get_value(self, rec, col): 94 # FIXME: write SWIG wrapper to marshal the Gvalue and wrap the rec in an 95 # Iter 96 pass 97 #return trace_view_store_get_value_py(self.cstore, rec, col) 98 99 def on_iter_next(self, rec): 100 pos = trace_view_record_pos_get(rec) 101 start_row = trace_view_store_start_row_get(self.cstore) 102 return trace_view_store_get_row(self.cstore, pos - start_row + 1) 103 104 def on_iter_children(self, rec): 105 if rec: 106 return None 107 return trace_view_store_get_row(self.cstore, 0) 108 109 def on_iter_has_child(self, rec): 110 return False 111 112 def on_iter_n_children(self, rec): 113 if rec: 114 return 0 115 return trace_view_store_num_rows_get(self.cstore) 116 117 def on_iter_nth_child(self, rec, n): 118 if rec: 119 return None 120 return trace_view_store_get_row(self.cstore, n) 121 122 def on_iter_parent(self, child): 123 return None 124 125 def get_event(self, iter): 126 path = self.get_path(iter) 127 if not path: 128 return None 129 rec = trace_view_store_get_row(self.cstore, path[0]) 130 if not rec: 131 return None 132 ev = self.trace.read_event_at(trace_view_record_offset_get(rec)) 133 return ev 134 135 136class EventView(gtk.TreeView): 137 def __init__(self, model): 138 gtk.TreeView.__init__(self, model) 139 self.set_fixed_height_mode(True) 140 141 ts_col = gtk.TreeViewColumn("Time (s)") 142 ts_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 143 ts_col.set_fixed_width(TS_COL_W) 144 ts_cell = gtk.CellRendererText() 145 ts_col.pack_start(ts_cell, False) 146 ts_col.set_cell_data_func(ts_cell, self.data_func, "ts") 147 self.append_column(ts_col) 148 149 cpu_col = gtk.TreeViewColumn("CPU") 150 cpu_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 151 cpu_col.set_fixed_width(CPU_COL_W) 152 cpu_cell = gtk.CellRendererText() 153 cpu_col.pack_start(cpu_cell, False) 154 cpu_col.set_cell_data_func(cpu_cell, self.data_func, "cpu") 155 self.append_column(cpu_col) 156 157 event_col = gtk.TreeViewColumn("Event") 158 event_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 159 event_col.set_fixed_width(EVENT_COL_W) 160 event_cell = gtk.CellRendererText() 161 event_col.pack_start(event_cell, False) 162 event_col.set_cell_data_func(event_cell, self.data_func, "event") 163 self.append_column(event_col) 164 165 pid_col = gtk.TreeViewColumn("PID") 166 pid_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 167 pid_col.set_fixed_width(PID_COL_W) 168 pid_cell = gtk.CellRendererText() 169 pid_col.pack_start(pid_cell, False) 170 pid_col.set_cell_data_func(pid_cell, self.data_func, "pid") 171 self.append_column(pid_col) 172 173 comm_col = gtk.TreeViewColumn("Comm") 174 comm_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 175 comm_col.set_fixed_width(COMM_COL_W) 176 comm_cell = gtk.CellRendererText() 177 comm_col.pack_start(comm_cell, False) 178 comm_col.set_cell_data_func(comm_cell, self.data_func, "comm") 179 self.append_column(comm_col) 180 181 def data_func(self, col, cell, model, iter, data): 182 ev = model.get_event(iter) 183 #ev = model.get_value(iter, 0) 184 if not ev: 185 return False 186 187 if data == "ts": 188 cell.set_property("markup", "%d.%d" % (ev.ts/1000000000, 189 ev.ts%1000000000)) 190 elif data == "cpu": 191 cell.set_property("markup", ev.cpu) 192 elif data == "event": 193 cell.set_property("markup", ev.name) 194 elif data == "pid": 195 cell.set_property("markup", ev.pid) 196 elif data == "comm": 197 cell.set_property("markup", ev.comm) 198 else: 199 print("Unknown Column:", data) 200 return False 201 202 return True 203 204 205class EventViewerApp(gtk.Window): 206 def __init__(self, trace): 207 gtk.Window.__init__(self) 208 209 self.set_size_request(650, 400) 210 self.set_position(gtk.WIN_POS_CENTER) 211 212 self.connect("destroy", gtk.main_quit) 213 self.set_title("Event Viewer") 214 215 store = EventStore(trace) 216 view = EventView(store) 217 218 sw = gtk.ScrolledWindow() 219 sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) 220 sw.add(view) 221 222 # track how often the treeview data_func is called 223 self.add(sw) 224 self.show_all() 225 226 227# Basic builtin test, execute module directly 228if __name__ == "__main__": 229 if len(sys.argv) >=2: 230 filename = sys.argv[1] 231 else: 232 filename = "trace.dat" 233 234 print("Initializing trace...") 235 trace = Trace(filename) 236 print("Initializing app...") 237 app = EventViewerApp(trace) 238 print("Go!") 239 gtk.main() 240