#
# Copyright (C) International Business Machines Corp., 2009
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# 2009-Dec-17: Initial version by Darren Hart <dvhltc@us.ibm.com>
#
from ctracecmd import *
"""
Python interface to the tracecmd library for parsing ftrace traces
Python tracecmd applications should be written to this interface. It will be
updated as the tracecmd C API changes and try to minimze the impact to python
applications. The ctracecmd Python module is automatically generated using SWIG
and it is recommended applications not use it directly.
TODO: consider a complete class hierarchy of ftrace events...
"""
class Event(object):
def __init__(self, trace, record, cpu):
self.trace = trace
self.rec = record
self.cpu = cpu
type = pevent_data_type(trace.pe, record)
self.format = pevent_data_event_from_type(trace.pe, type)
def __str__(self):
return "%d.%d CPU%d %s: pid=%d comm=%s type=%d" % \
(self.ts/1000000000, self.ts%1000000000, self.cpu, self.name,
self.num_field("common_pid"), self.comm, self.type)
def __del__(self):
free_record(self.rec);
# TODO: consider caching the results of the properties
@property
def comm(self):
return self.trace.comm_from_pid(self.pid)
@property
def name(self):
return event_format_name_get(self.format)
@property
def pid(self):
return pevent_data_pid(self.trace.pe, self.rec)
@property
def ts(self):
return record_ts_get(self.rec)
@property
def type(self):
return pevent_data_type(self.trace.pe, self.rec)
def num_field(self, name):
f = pevent_find_any_field(self.format, name)
val = pevent_read_number_field_py(f, record_data_get(self.rec))
return val
class Trace(object):
"""
Trace object represents the trace file it is created with.
The Trace object aggregates the tracecmd structures and functions that are
used to manage the trace and extract events from it.
"""
def __init__(self, filename):
self.handle = None
self.pe = None
try:
self.handle = tracecmd_open(filename)
#FIXME: check if these throw exceptions automatically or if we have
# to check return codes manually
tracecmd_read_headers(self.handle)
tracecmd_init_data(self.handle)
self.pe = tracecmd_get_pevent(self.handle)
except:
return None
@property
def cpus(self):
return tracecmd_cpus(self.handle)
def read_event(self, cpu):
rec = tracecmd_read_data(self.handle, cpu)
if rec:
#rec.acquire()
#rec.thisown = 1
return Event(self, rec, cpu)
return None
def read_event_at(self, offset):
res = tracecmd_read_at(self.handle, offset)
# SWIG only returns the CPU if the record is None for some reason
if isinstance(res, int):
return None
rec,cpu = res
#rec.acquire()
#rec.thisown = 1
ev = Event(self, rec, cpu)
return ev
def peek_event(self, cpu):
pass
def comm_from_pid(self, pid):
return pevent_data_comm_from_pid(self.pe, pid)
# Basic builtin test, execute module directly
if __name__ == "__main__":
t = Trace("trace.dat")
print "Trace contains data for %d cpus" % (t.cpus)
for cpu in range(0, t.cpus):
print "CPU %d" % (cpu)
ev = t.read_event(cpu)
while ev:
print "\t%s" % (ev)
ev = t.read_event(cpu)