diff options
-rw-r--r-- | Makefile | 2 | ||||
-rwxr-xr-x | event-viewer.py | 172 | ||||
-rw-r--r-- | tracecmd.py | 11 |
3 files changed, 160 insertions, 25 deletions
@@ -87,8 +87,10 @@ plugin_mac80211.so: plugin_mac80211.o | |||
87 | .PHONY: python | 87 | .PHONY: python |
88 | python: $(TCMD_LIB_OBJS) | 88 | python: $(TCMD_LIB_OBJS) |
89 | swig -Wall -python -noproxy ctracecmd.i | 89 | swig -Wall -python -noproxy ctracecmd.i |
90 | #swig -Wall -python ctracecmd.i | ||
90 | gcc -fpic -c `python-config --includes` ctracecmd_wrap.c | 91 | gcc -fpic -c `python-config --includes` ctracecmd_wrap.c |
91 | $(CC) --shared $^ ctracecmd_wrap.o -o ctracecmd.so | 92 | $(CC) --shared $^ ctracecmd_wrap.o -o ctracecmd.so |
93 | #$(CC) --shared $^ ctracecmd_wrap.o -o _ctracecmd.so | ||
92 | 94 | ||
93 | 95 | ||
94 | .PHONY: force | 96 | .PHONY: force |
diff --git a/event-viewer.py b/event-viewer.py index a8ccd5b..6f35642 100755 --- a/event-viewer.py +++ b/event-viewer.py | |||
@@ -1,8 +1,10 @@ | |||
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | 2 | ||
3 | import getopt | ||
3 | from gobject import * | 4 | from gobject import * |
4 | import gtk | 5 | import gtk |
5 | from tracecmd import * | 6 | from tracecmd import * |
7 | import time | ||
6 | 8 | ||
7 | app = None | 9 | app = None |
8 | data_func_cnt = 0 | 10 | data_func_cnt = 0 |
@@ -15,21 +17,136 @@ EVENT_COL_W = 150 | |||
15 | PID_COL_W = 75 | 17 | PID_COL_W = 75 |
16 | COMM_COL_W = 250 | 18 | COMM_COL_W = 250 |
17 | 19 | ||
18 | class EventStore(gtk.ListStore): | 20 | |
21 | def 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 | |||
31 | class 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 | ||
19 | def __init__(self, trace): | 56 | def __init__(self, trace): |
20 | gtk.ListStore.__init__(self, gobject.TYPE_PYOBJECT) | 57 | gtk.GenericTreeModel.__init__(self) |
21 | self.trace = trace | 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 | ||
22 | for cpu in range(0, trace.cpus): | 68 | for cpu in range(0, trace.cpus): |
23 | ev = trace.read_event(cpu) | 69 | rec = tracecmd_read_data(self.trace.handle, cpu) |
24 | while ev: | 70 | while rec: |
25 | # store the record offset into the trace file | 71 | offset = record_offset_get(rec) |
26 | self.append([record_offset_get(ev.rec)]) | 72 | ts = record_ts_get(rec) |
27 | ev = trace.read_event(cpu) | 73 | self.refs.append(self.EventRef(index, ts, offset, cpu)) |
28 | print "Loaded %d events across %d cpus" % (len(self), trace.cpus) | 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 | ||
29 | 141 | ||
30 | def get_event(self, iter): | 142 | def get_event(self, iter): |
31 | offset = self.get_value(iter, 0) | 143 | '''This allocates a record which must be freed by the caller''' |
32 | return self.trace.read_event_at(offset) | 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 | ||
33 | 150 | ||
34 | 151 | ||
35 | class EventView(gtk.TreeView): | 152 | class EventView(gtk.TreeView): |
@@ -81,29 +198,29 @@ class EventView(gtk.TreeView): | |||
81 | global app, data_func_cnt | 198 | global app, data_func_cnt |
82 | 199 | ||
83 | ev = model.get_event(iter) | 200 | ev = model.get_event(iter) |
201 | #ev = model.get_value(iter, 0) | ||
84 | if not ev: | 202 | if not ev: |
85 | return False | 203 | return False |
204 | |||
86 | if data == "ts": | 205 | if data == "ts": |
87 | cell.set_property("markup", "%d.%d" % (ev.ts/1000000000, | 206 | cell.set_property("markup", "%d.%d" % (ev.ts/1000000000, |
88 | ev.ts%1000000000)) | 207 | ev.ts%1000000000)) |
89 | data_func_cnt = data_func_cnt + 1 | 208 | data_func_cnt = data_func_cnt + 1 |
90 | if app: | 209 | if app: |
91 | app.inc_data_func() | 210 | app.inc_data_func() |
92 | return True | 211 | elif data == "cpu": |
93 | if data == "cpu": | ||
94 | cell.set_property("markup", ev.cpu) | 212 | cell.set_property("markup", ev.cpu) |
95 | return True | 213 | elif data == "event": |
96 | if data == "event": | ||
97 | cell.set_property("markup", ev.name) | 214 | cell.set_property("markup", ev.name) |
98 | return True | 215 | elif data == "pid": |
99 | if data == "pid": | ||
100 | cell.set_property("markup", ev.pid) | 216 | cell.set_property("markup", ev.pid) |
101 | return True | 217 | elif data == "comm": |
102 | if data == "comm": | ||
103 | cell.set_property("markup", ev.comm) | 218 | cell.set_property("markup", ev.comm) |
104 | return True | 219 | else: |
220 | print "Unknown Column:", data | ||
221 | return False | ||
105 | 222 | ||
106 | return False | 223 | return True |
107 | 224 | ||
108 | 225 | ||
109 | class EventViewerApp(gtk.Window): | 226 | class EventViewerApp(gtk.Window): |
@@ -116,9 +233,8 @@ class EventViewerApp(gtk.Window): | |||
116 | self.connect("destroy", gtk.main_quit) | 233 | self.connect("destroy", gtk.main_quit) |
117 | self.set_title("Event Viewer") | 234 | self.set_title("Event Viewer") |
118 | 235 | ||
119 | 236 | store = EventStore(trace) | |
120 | es = EventStore(trace) | 237 | view = EventView(store) |
121 | view = EventView(es) | ||
122 | 238 | ||
123 | sw = gtk.ScrolledWindow() | 239 | sw = gtk.ScrolledWindow() |
124 | sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) | 240 | sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) |
@@ -143,6 +259,14 @@ class EventViewerApp(gtk.Window): | |||
143 | 259 | ||
144 | 260 | ||
145 | if __name__ == "__main__": | 261 | if __name__ == "__main__": |
146 | trace = Trace("trace.dat") | 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..." | ||
147 | app = EventViewerApp(trace) | 270 | app = EventViewerApp(trace) |
271 | print "Go!" | ||
148 | gtk.main() | 272 | gtk.main() |
diff --git a/tracecmd.py b/tracecmd.py index fdcda76..e7ea5f6 100644 --- a/tracecmd.py +++ b/tracecmd.py | |||
@@ -44,6 +44,9 @@ class Event(object): | |||
44 | (self.ts/1000000000, self.ts%1000000000, self.cpu, self.name, | 44 | (self.ts/1000000000, self.ts%1000000000, self.cpu, self.name, |
45 | self.num_field("common_pid"), self.comm, self.type) | 45 | self.num_field("common_pid"), self.comm, self.type) |
46 | 46 | ||
47 | def __del__(self): | ||
48 | free_record(self.rec); | ||
49 | |||
47 | 50 | ||
48 | # TODO: consider caching the results of the properties | 51 | # TODO: consider caching the results of the properties |
49 | @property | 52 | @property |
@@ -100,6 +103,8 @@ class Trace(object): | |||
100 | def read_event(self, cpu): | 103 | def read_event(self, cpu): |
101 | rec = tracecmd_read_data(self.handle, cpu) | 104 | rec = tracecmd_read_data(self.handle, cpu) |
102 | if rec: | 105 | if rec: |
106 | #rec.acquire() | ||
107 | #rec.thisown = 1 | ||
103 | return Event(self, rec, cpu) | 108 | return Event(self, rec, cpu) |
104 | return None | 109 | return None |
105 | 110 | ||
@@ -108,7 +113,11 @@ class Trace(object): | |||
108 | # SWIG only returns the CPU if the record is None for some reason | 113 | # SWIG only returns the CPU if the record is None for some reason |
109 | if isinstance(res, int): | 114 | if isinstance(res, int): |
110 | return None | 115 | return None |
111 | return Event(self, res[0], res[1]) | 116 | rec,cpu = res |
117 | #rec.acquire() | ||
118 | #rec.thisown = 1 | ||
119 | ev = Event(self, rec, cpu) | ||
120 | return ev | ||
112 | 121 | ||
113 | def peek_event(self, cpu): | 122 | def peek_event(self, cpu): |
114 | pass | 123 | pass |