2 # -*- coding: iso-8859-1 -*-
5 # TSAR - Trace Sequence AnalyzeR
7 # Tool to extract and analyze Romain event logs
9 # (c) 2012-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
10 # economic rights: Technische Universität Dresden (Germany)
12 # This file is part of TUD:OS and distributed under the terms of the
13 # GNU General Public License 2.
14 # Please see the COPYING-GPL-2 file for details.
29 """Event factory: random access to Event objects
30 based on an underlying trace reader."""
32 def __init__(self, traceReader):
33 self.input = traceReader.raw_read()
35 self.idpfx = traceReader.prefix()
38 return "%s:%x" % (self.idpfx, utcb)
43 def _build(self, start):
44 """Get the Event object in the input stream
45 at the given position"""
47 if start >= len(self.input):
52 tsar_events.SyscallEvent,
53 tsar_events.PagefaultEvent,
54 tsar_events.SwifiEvent,
56 tsar_events.TrapEvent,
57 tsar_events.ThreadStartEvent,
58 tsar_events.ThreadStopEvent,
61 #print "Input: %d bytes" % len(bytes)
63 (tsc, utcb, typ) = struct.unpack_from("QIB", self.input[start:])
66 return eventTypes[typ](self.input[start:], tsc, utcb,
69 print "Index error with event type %d" % typ
73 """Get the next event in stream
75 Allows iterating over the stream."""
76 start = self.offset * tsar_events.Event.EVENTSIZE
78 return self._build(start)
80 def eventAtOffset(self, offset):
81 """Get event at a specified offset.
83 Random access to the stream."""
84 start = offset * tsar_events.Event.EVENTSIZE
85 return self._build(start)
89 """Reader for zipped uu-encoded data"""
91 def __init__(self, logfile):
92 tmp = tempfile.NamedTemporaryFile(mode="w+b")
93 # XXX also print UID here
94 print "UUDecoding %s -> %s" % (logfile.name, tmp.name)
95 uu.decode(logfile.name, tmp.name)
96 self.zipFile = gzip.open(tmp.name)
98 self.pfx = os.path.splitext(os.path.basename(logfile.name))[0]
104 """Read the raw bytes from the underlying stream
107 bytes = self.zipFile.read(1024)
110 bytes = self.zipFile.read(1024)
111 print "Read %d bytes." % len(decomp)
118 Raw list of events from potentially multiple event stream sources
122 self.stream_index = 0
124 def addStream(self, eventFactory):
125 """Add another stream to the event sources"""
126 self.streams += [eventFactory]
129 """Reset the event list"""
130 for s in self.streams:
132 self.stream_index = 0
135 """Return the next event.
137 Continuously calling this function iterates over the associated
138 streams one at a time. Returns 'None' if no more events are to
142 if self.stream_index >= len(self.streams):
145 ev = self.streams[self.stream_index].nextEvent()
148 self.stream_index += 1
154 def print_plain(events):
155 """Plain dump of an event list"""
160 def print_pretty(events):
161 """Pretty-printed event list.
163 Prints a table. First column is a time stamp. Every other
164 colunm represents one distinct replica
168 # first run to determine UTCB IDs
170 if e.uid() not in ids:
175 print "\033[32m%14s" % "Timestamp",
177 print "| %20s" % ("UID %s" % i[0:16]),
183 for line in e.pretty():
190 idx = ids.index(e.uid())
192 for i in range(0, idx):
195 if e.type == tsar_events.Event.TRAP_TYPE and e.is_start:
196 print "| \033[33m%20s\033[0m" % line,
198 print "| %20s" % line,
199 for i in range(idx + 1, len(ids)):
205 def remove_vt100(line):
206 """Remoe any occurrence of a VT100 color sequence from a string"""
207 return re.sub("\033\[\d+(;\d+)?m", "", line)
210 def extractLogs(inputFile):
211 """Take a QEMU log file (Fiasco serial output) and extract the
212 UU-encoded trace dumps from it.
214 files = [] # list of trace files
215 inLogFile = False # are we currently operating on a dump?
217 for l in file(inputFile).readlines():
220 # start and end indicators
221 startmo = re.match("romain.*(begin 644 .*.gz)", v)
222 endmo = re.match("romain.*end", v)
225 curFile = tempfile.NamedTemporaryFile(mode="w+")
228 # Write lines belonging to the dump to temporary file.
229 # Remove L4Re's log prefix upfront
231 curFile.write(v.replace("romain | ", ""))
233 if inLogFile and endmo:
241 if len(sys.argv) < 2:
242 print "Need at least 1 argument"
247 for f in extractLogs(sys.argv[1]):
248 print "=== %s ===" % f.name
249 f.seek(0) # need to reset file seek ptr
250 elist.addStream(EventFactory(TraceReader(f)))
259 # events are not necessarily sorted by time right now!
260 events.sort(key=operator.attrgetter('ts'))
266 if __name__ == "__main__":