aboutsummaryrefslogtreecommitdiffstats
path: root/tracecmd.py
diff options
context:
space:
mode:
Diffstat (limited to 'tracecmd.py')
-rw-r--r--tracecmd.py167
1 files changed, 128 insertions, 39 deletions
diff --git a/tracecmd.py b/tracecmd.py
index 6b05e23..ad80ccd 100644
--- a/tracecmd.py
+++ b/tracecmd.py
@@ -18,6 +18,7 @@
18# 2009-Dec-17: Initial version by Darren Hart <dvhltc@us.ibm.com> 18# 2009-Dec-17: Initial version by Darren Hart <dvhltc@us.ibm.com>
19# 19#
20 20
21from functools import update_wrapper
21from ctracecmd import * 22from ctracecmd import *
22 23
23""" 24"""
@@ -31,13 +32,33 @@ and it is recommended applications not use it directly.
31TODO: consider a complete class hierarchy of ftrace events... 32TODO: consider a complete class hierarchy of ftrace events...
32""" 33"""
33 34
35def cached_property(func, name=None):
36 if name is None:
37 name = func.__name__
38 def _get(self):
39 try:
40 return self.__cached_properties[name]
41 except AttributeError:
42 self.__cached_properties = {}
43 except KeyError:
44 pass
45 value = func(self)
46 self.__cached_properties[name] = value
47 return value
48 update_wrapper(_get, func)
49 def _del(self):
50 self.__cached_properties.pop(name, None)
51 return property(_get, None, _del)
52
34class Event(object): 53class Event(object):
35 def __init__(self, trace, record, cpu): 54 """
36 self.trace = trace 55 This class can be used to access event data
37 self.rec = record 56 according to an event's record and format.
38 self.cpu = cpu 57 """
39 type = pevent_data_type(trace.pe, record) 58 def __init__(self, pevent, record, format):
40 self.format = pevent_data_event_from_type(trace.pe, type) 59 self._pevent = pevent
60 self._record = record
61 self._format = format
41 62
42 def __str__(self): 63 def __str__(self):
43 return "%d.%d CPU%d %s: pid=%d comm=%s type=%d" % \ 64 return "%d.%d CPU%d %s: pid=%d comm=%s type=%d" % \
@@ -45,35 +66,105 @@ class Event(object):
45 self.num_field("common_pid"), self.comm, self.type) 66 self.num_field("common_pid"), self.comm, self.type)
46 67
47 def __del__(self): 68 def __del__(self):
48 free_record(self.rec); 69 free_record(self._record)
70
71 def __getitem__(self, n):
72 f = pevent_find_field(self._format, n)
73 if f is None:
74 raise KeyError("no field '%s'" % n)
75 return Field(self._record, f)
49 76
77 def keys(self):
78 return py_format_get_keys(self._format)
50 79
51 # TODO: consider caching the results of the properties 80 @cached_property
52 @property
53 def comm(self): 81 def comm(self):
54 return self.trace.comm_from_pid(self.pid) 82 return pevent_data_comm_from_pid(self._pevent, self.pid)
55 83
56 @property 84 @cached_property
85 def cpu(self):
86 return record_cpu_get(self._record)
87
88 @cached_property
57 def name(self): 89 def name(self):
58 return event_format_name_get(self.format) 90 return event_format_name_get(self._format)
59 91
60 @property 92 @cached_property
61 def pid(self): 93 def pid(self):
62 return pevent_data_pid(self.trace.pe, self.rec) 94 return pevent_data_pid(self._pevent, self._record)
63 95
64 @property 96 @cached_property
65 def ts(self): 97 def ts(self):
66 return record_ts_get(self.rec) 98 return record_ts_get(self._record)
67 99
68 @property 100 @cached_property
69 def type(self): 101 def type(self):
70 return pevent_data_type(self.trace.pe, self.rec) 102 return pevent_data_type(self._pevent, self._record)
71 103
72 def num_field(self, name): 104 def num_field(self, name):
73 f = pevent_find_any_field(self.format, name) 105 f = pevent_find_any_field(self._format, name)
74 val = pevent_read_number_field_py(f, record_data_get(self.rec)) 106 if f is None:
107 return None
108 ret, val = pevent_read_number_field(f, record_data_get(self._record))
109 if ret:
110 return None
75 return val 111 return val
76 112
113 def str_field(self, name):
114 f = pevent_find_any_field(self._format, name)
115 if f is None:
116 return None
117 return py_field_get_str(f, self._record)
118
119class TraceSeq(object):
120 def __init__(self, trace_seq):
121 self._trace_seq = trace_seq
122
123 def puts(self, s):
124 return trace_seq_puts(self._trace_seq, s)
125
126class FieldError(Exception):
127 pass
128
129class Field(object):
130 def __init__(self, record, field):
131 self._record = record
132 self._field = field
133
134 @cached_property
135 def data(self):
136 return py_field_get_data(self._field, self._record)
137
138 def __long__(self):
139 ret, val = pevent_read_number_field(self._field,
140 record_data_get(self._record))
141 if ret:
142 raise FieldError("Not a number field")
143 return val
144 __int__ = __long__
145
146 def __str__(self):
147 return py_field_get_str(self._field, self._record)
148
149class PEvent(object):
150 def __init__(self, pevent):
151 self._pevent = pevent
152
153 def _handler(self, cb, s, record, event_fmt):
154 return cb(TraceSeq(s), Event(self._pevent, record, event_fmt))
155
156 def register_event_handler(self, subsys, event_name, callback):
157 l = lambda s, r, e: self._handler(callback, s, r, e)
158
159 py_pevent_register_event_handler(
160 self._pevent, -1, subsys, event_name, l)
161
162 @cached_property
163 def file_endian(self):
164 if pevent_is_file_bigendian(self._pevent):
165 return '>'
166 return '<'
167
77 168
78class FileFormatError(Exception): 169class FileFormatError(Exception):
79 pass 170 pass
@@ -86,45 +177,43 @@ class Trace(object):
86 used to manage the trace and extract events from it. 177 used to manage the trace and extract events from it.
87 """ 178 """
88 def __init__(self, filename): 179 def __init__(self, filename):
89 self.handle = tracecmd_open(filename) 180 self._handle = tracecmd_alloc(filename)
90 181
91 if tracecmd_read_headers(self.handle): 182 if tracecmd_read_headers(self._handle):
92 raise FileFormatError("Invalid headers") 183 raise FileFormatError("Invalid headers")
93 184
94 if tracecmd_init_data(self.handle): 185 if tracecmd_init_data(self._handle):
95 raise FileFormatError("Failed to init data") 186 raise FileFormatError("Failed to init data")
96 187
97 self.pe = tracecmd_get_pevent(self.handle) 188 self._pevent = tracecmd_get_pevent(self._handle)
98 189
99 @property 190 @cached_property
100 def cpus(self): 191 def cpus(self):
101 return tracecmd_cpus(self.handle) 192 return tracecmd_cpus(self._handle)
102 193
103 def read_event(self, cpu): 194 def read_event(self, cpu):
104 rec = tracecmd_read_data(self.handle, cpu) 195 rec = tracecmd_read_data(self._handle, cpu)
105 if rec: 196 if rec:
106 #rec.acquire() 197 type = pevent_data_type(self._pevent, rec)
107 #rec.thisown = 1 198 format = pevent_data_event_from_type(self._pevent, type)
108 return Event(self, rec, cpu) 199 # rec ownership goes over to Event instance
200 return Event(self._pevent, rec, format)
109 return None 201 return None
110 202
111 def read_event_at(self, offset): 203 def read_event_at(self, offset):
112 res = tracecmd_read_at(self.handle, offset) 204 res = tracecmd_read_at(self._handle, offset)
113 # SWIG only returns the CPU if the record is None for some reason 205 # SWIG only returns the CPU if the record is None for some reason
114 if isinstance(res, int): 206 if isinstance(res, int):
115 return None 207 return None
116 rec,cpu = res 208 rec, cpu = res
117 #rec.acquire() 209 type = pevent_data_type(self._pevent, rec)
118 #rec.thisown = 1 210 format = pevent_data_event_from_type(self._pevent, type)
119 ev = Event(self, rec, cpu) 211 # rec ownership goes over to Event instance
120 return ev 212 return Event(self._pevent, rec, format)
121 213
122 def peek_event(self, cpu): 214 def peek_event(self, cpu):
123 pass 215 pass
124 216
125 def comm_from_pid(self, pid):
126 return pevent_data_comm_from_pid(self.pe, pid)
127
128 217
129# Basic builtin test, execute module directly 218# Basic builtin test, execute module directly
130if __name__ == "__main__": 219if __name__ == "__main__":