aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-30 13:30:48 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-30 13:30:48 -0500
commit708b9e195cbaebdbea5bfccb751c7fce0a25b9f7 (patch)
tree9480a14c7d5112897f540c2a7ed42fab85ffc7b5
parent53336fb4d2d41f865557bb5ff0bc686db5e31793 (diff)
parent5f85740ef7a9e7e61fdbd2583a1ff2b1001c4418 (diff)
Merge branch 'trace-cmd' into trace-view
-rw-r--r--Makefile4
-rw-r--r--ctracecmd.i9
-rwxr-xr-xevent-viewer.py272
-rw-r--r--tracecmd.py36
4 files changed, 310 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 0f65858..e75e2e0 100644
--- a/Makefile
+++ b/Makefile
@@ -119,10 +119,12 @@ plugin_mac80211.so: plugin_mac80211.o
119 119
120 120
121.PHONY: python 121.PHONY: python
122python: $(TCMD_LIB_OBJS) trace-cmd.o trace-read.o 122python: $(TCMD_LIB_OBJS)
123 swig -Wall -python -noproxy ctracecmd.i 123 swig -Wall -python -noproxy ctracecmd.i
124 #swig -Wall -python ctracecmd.i
124 gcc -fpic -c `python-config --includes` ctracecmd_wrap.c 125 gcc -fpic -c `python-config --includes` ctracecmd_wrap.c
125 $(CC) --shared $^ ctracecmd_wrap.o -o ctracecmd.so 126 $(CC) --shared $^ ctracecmd_wrap.o -o ctracecmd.so
127 #$(CC) --shared $^ ctracecmd_wrap.o -o _ctracecmd.so
126 128
127 129
128.PHONY: force 130.PHONY: force
diff --git a/ctracecmd.i b/ctracecmd.i
index a9d3ca5..f0b0eb7 100644
--- a/ctracecmd.i
+++ b/ctracecmd.i
@@ -2,14 +2,23 @@
2%module ctracecmd 2%module ctracecmd
3%include typemaps.i 3%include typemaps.i
4 4
5/* return a (rec,cpu) tuple in python */
6extern struct record *tracecmd_read_at(struct tracecmd_input *handle,
7 unsigned long long offset,
8 int *OUTPUT);
9
10
5%{ 11%{
6#include "trace-cmd.h" 12#include "trace-cmd.h"
7%} 13%}
8 14
15
16/* return python longs from unsigned long long functions */
9%typemap(out) unsigned long long { 17%typemap(out) unsigned long long {
10$result = PyLong_FromUnsignedLongLong((unsigned long long) $1); 18$result = PyLong_FromUnsignedLongLong((unsigned long long) $1);
11} 19}
12 20
21
13%inline %{ 22%inline %{
14PyObject *pevent_read_number_field_py(struct format_field *f, void *data) 23PyObject *pevent_read_number_field_py(struct format_field *f, void *data)
15{ 24{
diff --git a/event-viewer.py b/event-viewer.py
new file mode 100755
index 0000000..6f35642
--- /dev/null
+++ b/event-viewer.py
@@ -0,0 +1,272 @@
1#!/usr/bin/env python
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 = record_offset_get(rec)
72 ts = 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.%d" % (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()
diff --git a/tracecmd.py b/tracecmd.py
index f9a2708..e7ea5f6 100644
--- a/tracecmd.py
+++ b/tracecmd.py
@@ -32,15 +32,20 @@ TODO: consider a complete class hierarchy of ftrace events...
32""" 32"""
33 33
34class Event(object): 34class Event(object):
35 def __init__(self, trace, record): 35 def __init__(self, trace, record, cpu):
36 self.trace = trace 36 self.trace = trace
37 self.rec = record 37 self.rec = record
38 self.cpu = cpu
38 type = pevent_data_type(trace.pe, record) 39 type = pevent_data_type(trace.pe, record)
39 self.ec = pevent_data_event_from_type(trace.pe, type) 40 self.format = pevent_data_event_from_type(trace.pe, type)
40 41
41 def __str__(self): 42 def __str__(self):
42 return "%d.%d %s: pid=%d comm=%s type=%d" % \ 43 return "%d.%d CPU%d %s: pid=%d comm=%s type=%d" % \
43 (self.ts/1000000000, self.ts%1000000000, self.name, self.num_field("common_pid"), self.comm, self.type) 44 (self.ts/1000000000, self.ts%1000000000, self.cpu, self.name,
45 self.num_field("common_pid"), self.comm, self.type)
46
47 def __del__(self):
48 free_record(self.rec);
44 49
45 50
46 # TODO: consider caching the results of the properties 51 # TODO: consider caching the results of the properties
@@ -50,7 +55,7 @@ class Event(object):
50 55
51 @property 56 @property
52 def name(self): 57 def name(self):
53 return event_name_get(self.ec) 58 return event_format_name_get(self.format)
54 59
55 @property 60 @property
56 def pid(self): 61 def pid(self):
@@ -65,7 +70,7 @@ class Event(object):
65 return pevent_data_type(self.trace.pe, self.rec) 70 return pevent_data_type(self.trace.pe, self.rec)
66 71
67 def num_field(self, name): 72 def num_field(self, name):
68 f = pevent_find_any_field(self.ec, name) 73 f = pevent_find_any_field(self.format, name)
69 val = pevent_read_number_field_py(f, record_data_get(self.rec)) 74 val = pevent_read_number_field_py(f, record_data_get(self.rec))
70 return val 75 return val
71 76
@@ -82,9 +87,7 @@ class Trace(object):
82 self.pe = None 87 self.pe = None
83 88
84 try: 89 try:
85 file = open(filename) 90 self.handle = tracecmd_open(filename)
86 self.handle = tracecmd_open(file.fileno())
87 print "self.handle: ", self.handle
88 #FIXME: check if these throw exceptions automatically or if we have 91 #FIXME: check if these throw exceptions automatically or if we have
89 # to check return codes manually 92 # to check return codes manually
90 tracecmd_read_headers(self.handle) 93 tracecmd_read_headers(self.handle)
@@ -100,9 +103,22 @@ 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:
103 return Event(self, rec) 106 #rec.acquire()
107 #rec.thisown = 1
108 return Event(self, rec, cpu)
104 return None 109 return None
105 110
111 def read_event_at(self, offset):
112 res = tracecmd_read_at(self.handle, offset)
113 # SWIG only returns the CPU if the record is None for some reason
114 if isinstance(res, int):
115 return None
116 rec,cpu = res
117 #rec.acquire()
118 #rec.thisown = 1
119 ev = Event(self, rec, cpu)
120 return ev
121
106 def peek_event(self, cpu): 122 def peek_event(self, cpu):
107 pass 123 pass
108 124