• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python2
2
3import getopt
4from gobject import *
5import gtk
6from tracecmd import *
7import time
8
9app = None
10data_func_cnt = 0
11
12# In a "real" app these width should be determined at runtime testing max length
13# strings in the current font.
14TS_COL_W    = 150
15CPU_COL_W   = 35
16EVENT_COL_W = 150
17PID_COL_W   = 75
18COMM_COL_W  = 250
19
20
21def timing(func):
22  def wrapper(*arg):
23      start = time.time()
24      ret = func(*arg)
25      end = time.time()
26      print('@%s took %0.3f s' % (func.func_name, (end-start)))
27      return ret
28  return wrapper
29
30
31class EventStore(gtk.GenericTreeModel):
32    class EventRef(object):
33        '''Inner class to build the trace event index'''
34        def __init__(self, index, timestamp, offset, cpu):
35            self.index = index
36            self.offset = offset
37            self.ts = timestamp
38            self.cpu = cpu
39
40        def __cmp__(self, other):
41            if self.ts < other.ts:
42                return -1
43            if self.ts > other.ts:
44                return 1
45            if self.offset < other.offset:
46                return -1
47            if self.offset > other.offset:
48                return 1
49            return 0
50
51    # The store only returns the record offset into the trace
52    # The view is responsible for looking up the Event with the offset
53    column_types = (long,)
54
55    @timing
56    def __init__(self, trace):
57        gtk.GenericTreeModel.__init__(self)
58        self.trace = trace
59        self.refs = []
60        self._load_trace()
61        self._sort()
62        self._reindex()
63
64    @timing
65    def _load_trace(self):
66        print("Building trace index...")
67        index = 0
68        for cpu in range(0, trace.cpus):
69            rec = tracecmd_read_data(self.trace._handle, cpu)
70            while rec:
71                offset = tep_record_offset_get(rec)
72                ts = tep_record_ts_get(rec)
73                self.refs.append(self.EventRef(index, ts, offset, cpu))
74                index = index + 1
75                rec = tracecmd_read_data(self.trace._handle, cpu)
76        print("Loaded %d events from trace" % (index))
77
78    @timing
79    def _sort(self):
80        self.refs.sort()
81
82    @timing
83    def _reindex(self):
84        for i in range(0, len(self.refs)):
85            self.refs[i].index = i
86
87    def on_get_flags(self):
88        return gtk.TREE_MODEL_LIST_ONLY | gtk.TREE_MODEL_ITERS_PERSIST
89
90    def on_get_n_columns(self):
91        return len(self.column_types)
92
93    def on_get_column_type(self, col):
94        return self.column_types[col]
95
96    def on_get_iter(self, path):
97        return self.refs[path[0]]
98
99    def on_get_path(self, ref):
100        return ref.index
101
102    def on_get_value(self, ref, col):
103        '''
104        The Event record was getting deleted when passed back via this
105        method, now it just returns the ref itself. Use get_event() instead.
106        '''
107        if col == 0:
108            #return self.trace.read_event_at(ref.offset)
109            return ref
110        return None
111
112    def on_iter_next(self, ref):
113        try:
114            return self.refs[ref.index+1]
115        except IndexError:
116            return None
117
118    def on_iter_children(self, ref):
119        if ref:
120            return None
121        return self.refs[0]
122
123    def on_iter_has_child(self, ref):
124        return False
125
126    def on_iter_n_children(self, ref):
127        if ref:
128            return 0
129        return len(self.refs)
130
131    def on_iter_nth_child(self, ref, n):
132        if ref:
133            return None
134        try:
135            return self.refs[n]
136        except IndexError:
137            return None
138
139    def on_iter_parent(self, child):
140        return None
141
142    def get_event(self, iter):
143        '''This allocates a record which must be freed by the caller'''
144        try:
145            ref = self.refs[self.get_path(iter)[0]]
146            ev = self.trace.read_event_at(ref.offset)
147            return ev
148        except IndexError:
149            return None
150
151
152class EventView(gtk.TreeView):
153    def __init__(self, model):
154        gtk.TreeView.__init__(self, model)
155        self.set_fixed_height_mode(True)
156
157        ts_col = gtk.TreeViewColumn("Time (s)")
158        ts_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
159        ts_col.set_fixed_width(TS_COL_W)
160        ts_cell = gtk.CellRendererText()
161        ts_col.pack_start(ts_cell, False)
162        ts_col.set_cell_data_func(ts_cell, self.data_func, "ts")
163        self.append_column(ts_col)
164
165        cpu_col = gtk.TreeViewColumn("CPU")
166        cpu_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
167        cpu_col.set_fixed_width(CPU_COL_W)
168        cpu_cell = gtk.CellRendererText()
169        cpu_col.pack_start(cpu_cell, False)
170        cpu_col.set_cell_data_func(cpu_cell, self.data_func, "cpu")
171        self.append_column(cpu_col)
172
173        event_col = gtk.TreeViewColumn("Event")
174        event_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
175        event_col.set_fixed_width(EVENT_COL_W)
176        event_cell = gtk.CellRendererText()
177        event_col.pack_start(event_cell, False)
178        event_col.set_cell_data_func(event_cell, self.data_func, "event")
179        self.append_column(event_col)
180
181        pid_col = gtk.TreeViewColumn("PID")
182        pid_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
183        pid_col.set_fixed_width(PID_COL_W)
184        pid_cell = gtk.CellRendererText()
185        pid_col.pack_start(pid_cell, False)
186        pid_col.set_cell_data_func(pid_cell, self.data_func, "pid")
187        self.append_column(pid_col)
188
189        comm_col = gtk.TreeViewColumn("Comm")
190        comm_col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
191        comm_col.set_fixed_width(COMM_COL_W)
192        comm_cell = gtk.CellRendererText()
193        comm_col.pack_start(comm_cell, False)
194        comm_col.set_cell_data_func(comm_cell, self.data_func, "comm")
195        self.append_column(comm_col)
196
197    def data_func(self, col, cell, model, iter, data):
198        global app, data_func_cnt
199
200        ev = model.get_event(iter)
201        #ev = model.get_value(iter, 0)
202        if not ev:
203            return False
204
205        if data == "ts":
206            cell.set_property("markup", "%d.%09d" % (ev.ts/1000000000,
207                                                     ev.ts%1000000000))
208            data_func_cnt = data_func_cnt + 1
209            if app:
210                app.inc_data_func()
211        elif data == "cpu":
212            cell.set_property("markup", ev.cpu)
213        elif data == "event":
214            cell.set_property("markup", ev.name)
215        elif data == "pid":
216            cell.set_property("markup", ev.pid)
217        elif data == "comm":
218            cell.set_property("markup", ev.comm)
219        else:
220            print("Unknown Column:", data)
221            return False
222
223        return True
224
225
226class EventViewerApp(gtk.Window):
227    def __init__(self, trace):
228        gtk.Window.__init__(self)
229
230        self.set_size_request(650, 400)
231        self.set_position(gtk.WIN_POS_CENTER)
232
233        self.connect("destroy", gtk.main_quit)
234        self.set_title("Event Viewer")
235
236        store = EventStore(trace)
237        view = EventView(store)
238
239        sw = gtk.ScrolledWindow()
240        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
241        sw.add(view)
242
243        # track how often the treeview data_func is called
244        self.data_func_label = gtk.Label("0")
245        hbox = gtk.HBox()
246        hbox.pack_start(gtk.Label("TS Data Func Calls:"), False, False)
247        hbox.pack_start(self.data_func_label, False, False)
248
249        vbox = gtk.VBox()
250        vbox.pack_start(hbox, False)
251        vbox.pack_end(sw)
252
253        self.add(vbox)
254        self.show_all()
255
256    def inc_data_func(self):
257        global data_func_cnt
258        self.data_func_label.set_text(str(data_func_cnt))
259
260
261if __name__ == "__main__":
262    if len(sys.argv) >=2:
263        filename = sys.argv[1]
264    else:
265        filename = "trace.dat"
266
267    print("Initializing trace...")
268    trace = Trace(filename)
269    print("Initializing app...")
270    app = EventViewerApp(trace)
271    print("Go!")
272    gtk.main()
273