diff options
-rw-r--r-- | ctracecmd.i | 15 | ||||
-rw-r--r-- | tracecmd-test.py | 36 | ||||
-rw-r--r-- | tracecmd.py | 135 |
3 files changed, 150 insertions, 36 deletions
diff --git a/ctracecmd.i b/ctracecmd.i index 80fface..20a681c 100644 --- a/ctracecmd.i +++ b/ctracecmd.i | |||
@@ -1,13 +1,28 @@ | |||
1 | // tracecmd.i | 1 | // tracecmd.i |
2 | %module ctracecmd | 2 | %module ctracecmd |
3 | %include typemaps.i | ||
3 | 4 | ||
4 | %{ | 5 | %{ |
5 | #include "trace-cmd.h" | 6 | #include "trace-cmd.h" |
6 | %} | 7 | %} |
7 | 8 | ||
9 | /* typemaps must come before the implementation of wrapped functions */ | ||
10 | extern int pevent_read_number_field_32(struct format_field *f, void *data, | ||
11 | unsigned long *OUTPUT, unsigned long *OUTPUT); | ||
12 | |||
8 | %inline %{ | 13 | %inline %{ |
14 | int pevent_read_number_field_32(struct format_field *f, void *data, unsigned long *hi, unsigned long *lo) | ||
15 | { | ||
16 | unsigned long long val64; | ||
17 | int ret; | ||
18 | ret = pevent_read_number_field(f, data, &val64); | ||
19 | *hi = (unsigned long)(val64>>32); | ||
20 | *lo = (unsigned long)((val64<<32)>>32); | ||
21 | return ret; | ||
22 | } | ||
9 | %} | 23 | %} |
10 | 24 | ||
25 | |||
11 | /* SWIG can't grok these, define them to nothing */ | 26 | /* SWIG can't grok these, define them to nothing */ |
12 | #define __trace | 27 | #define __trace |
13 | #define __attribute__(x) | 28 | #define __attribute__(x) |
diff --git a/tracecmd-test.py b/tracecmd-test.py deleted file mode 100644 index e35523b..0000000 --- a/tracecmd-test.py +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | from ctracecmd import * | ||
4 | |||
5 | # Let's move the following into a new Trace object constructor | ||
6 | filename = "trace.dat" | ||
7 | trace_file = open(filename) | ||
8 | handle = tracecmd_open(trace_file.fileno()) | ||
9 | tracecmd_read_headers(handle) | ||
10 | tracecmd_init_data(handle) | ||
11 | |||
12 | # These should be members, i.e. Trace.cpus | ||
13 | pe = tracecmd_get_pevent(handle) | ||
14 | cpus = tracecmd_cpus(handle) | ||
15 | print "Trace %s contains data for %d cpus" % (filename, cpus) | ||
16 | |||
17 | # FIXME: this doesn't print anything... | ||
18 | tracecmd_print_events(handle) | ||
19 | |||
20 | print "Cycling through the events for each CPU" | ||
21 | for cpu in range(0,cpus): | ||
22 | print "CPU", cpu | ||
23 | rec = tracecmd_read_data(handle, cpu) | ||
24 | while True: | ||
25 | if rec: | ||
26 | # these should be members of a Record object | ||
27 | pid = pevent_data_pid(pe, rec) | ||
28 | comm = pevent_data_comm_from_pid(pe, pid) | ||
29 | type = pevent_data_type(pe, rec) | ||
30 | event = pevent_data_event_from_type(pe, type) | ||
31 | print "\t%f %s: pid=%d comm=%s type=%d" % \ | ||
32 | (record_ts_get(rec), event_name_get(event), pid, comm, type) | ||
33 | |||
34 | rec = tracecmd_read_data(handle, cpu) | ||
35 | else: | ||
36 | break | ||
diff --git a/tracecmd.py b/tracecmd.py new file mode 100644 index 0000000..6520a48 --- /dev/null +++ b/tracecmd.py | |||
@@ -0,0 +1,135 @@ | |||
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | # | ||
18 | # 2009-Dec-17: Initial version by Darren Hart <dvhltc@us.ibm.com> | ||
19 | # | ||
20 | |||
21 | from ctracecmd import * | ||
22 | |||
23 | """ | ||
24 | Python interface to the tracecmd library for parsing ftrace traces | ||
25 | |||
26 | Python tracecmd applications should be written to this interface. It will be | ||
27 | updated as the tracecmd C API changes and try to minimze the impact to python | ||
28 | applications. The ctracecmd Python module is automatically generated using SWIG | ||
29 | and it is recommended applications not use it directly. | ||
30 | |||
31 | TODO: consider a complete class hierarchy of ftrace events... | ||
32 | """ | ||
33 | |||
34 | def _pevent_read_number_field(field, data): | ||
35 | ret,hi,lo = pevent_read_number_field_32(field, data) | ||
36 | if ret == 0: | ||
37 | return ret,long(long(hi).__lshift__(32)+lo) | ||
38 | return ret,None | ||
39 | |||
40 | |||
41 | class Event(object): | ||
42 | def __init__(self, trace, record): | ||
43 | self.trace = trace | ||
44 | self.rec = record | ||
45 | type = pevent_data_type(trace.pe, record) | ||
46 | self.ec = pevent_data_event_from_type(trace.pe, type) | ||
47 | |||
48 | def __str__(self): | ||
49 | return "%f %s: pid=%d comm=%s type=%d" % \ | ||
50 | (self.ts, self.name, self.num_field("common_pid"), self.comm, self.type) | ||
51 | |||
52 | |||
53 | # TODO: consider caching the results of the properties | ||
54 | @property | ||
55 | def comm(self): | ||
56 | return self.trace.comm_from_pid(self.pid) | ||
57 | |||
58 | @property | ||
59 | def name(self): | ||
60 | return event_name_get(self.ec) | ||
61 | |||
62 | @property | ||
63 | def pid(self): | ||
64 | return pevent_data_pid(self.trace.pe, self.rec) | ||
65 | |||
66 | @property | ||
67 | def ts(self): | ||
68 | # FIXME: this currently returns a float instead of a 64bit nsec value | ||
69 | return record_ts_get(self.rec) | ||
70 | |||
71 | @property | ||
72 | def type(self): | ||
73 | return pevent_data_type(self.trace.pe, self.rec) | ||
74 | |||
75 | def num_field(self, name): | ||
76 | # FIXME: need to find an elegant way to handle 64bit fields | ||
77 | f = pevent_find_any_field(self.ec, name) | ||
78 | ret,val = _pevent_read_number_field(f, record_data_get(self.rec)) | ||
79 | return val | ||
80 | |||
81 | |||
82 | class Trace(object): | ||
83 | """ | ||
84 | Trace object represents the trace file it is created with. | ||
85 | |||
86 | The Trace object aggregates the tracecmd structures and functions that are | ||
87 | used to manage the trace and extract events from it. | ||
88 | """ | ||
89 | def __init__(self, filename): | ||
90 | self.handle = None | ||
91 | self.pe = None | ||
92 | |||
93 | try: | ||
94 | file = open(filename) | ||
95 | self.handle = tracecmd_open(file.fileno()) | ||
96 | print "self.handle: ", self.handle | ||
97 | #FIXME: check if these throw exceptions automatically or if we have | ||
98 | # to check return codes manually | ||
99 | tracecmd_read_headers(self.handle) | ||
100 | tracecmd_init_data(self.handle) | ||
101 | self.pe = tracecmd_get_pevent(self.handle) | ||
102 | except: | ||
103 | return None | ||
104 | |||
105 | @property | ||
106 | def cpus(self): | ||
107 | return tracecmd_cpus(self.handle) | ||
108 | |||
109 | def read_event(self, cpu): | ||
110 | rec = tracecmd_read_data(self.handle, cpu) | ||
111 | if rec: | ||
112 | return Event(self, rec) | ||
113 | return None | ||
114 | |||
115 | def peek_event(self, cpu): | ||
116 | pass | ||
117 | |||
118 | def comm_from_pid(self, pid): | ||
119 | return pevent_data_comm_from_pid(self.pe, pid) | ||
120 | |||
121 | |||
122 | # Basic builtin test, execute module directly | ||
123 | if __name__ == "__main__": | ||
124 | t = Trace("trace.dat") | ||
125 | print "Trace contains data for %d cpus" % (t.cpus) | ||
126 | |||
127 | for cpu in range(0, t.cpus): | ||
128 | print "CPU %d" % (cpu) | ||
129 | ev = t.read_event(cpu) | ||
130 | while ev: | ||
131 | print "\t%s" % (ev) | ||
132 | ev = t.read_event(cpu) | ||
133 | |||
134 | |||
135 | |||