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.
28 #pylint: disable=C0103,R0903
32 """Event factory: random access to Event objects
33 based on an underlying trace reader."""
35 def __init__(self, traceReader):
36 self.reader = traceReader
37 self.input = traceReader.raw_read()
39 self.idpfx = traceReader.prefix()
41 self.eventCount = len(self.input) / tsar_events.Event.EVENTSIZE
45 return "%s:%x" % (self.idpfx, utcb)
50 def print_status(self):
51 sys.stderr.write("\033[34;46m\033[s%s: %8d / %8d\033[u" %
52 (self.reader.zipFile.name, self.offset,
55 def _build(self, start):
56 """Get the Event object in the input stream
57 at the given position"""
59 if start >= len(self.input):
64 tsar_events.SyscallEvent,
65 tsar_events.PagefaultEvent,
66 tsar_events.SwifiEvent,
68 tsar_events.TrapEvent,
69 tsar_events.ThreadStartEvent,
70 tsar_events.ThreadStopEvent,
71 tsar_events.LockingEvent,
72 tsar_events.SHMLockingEvent,
73 tsar_events.BarnesEvent,
76 #print "Input: %d bytes" % len(self.input)
78 (tsc, utcb, typ) = struct.unpack_from("QIB", self.input[start:])
82 #print typ, self.uid(utcb)
85 return eventTypes[typ](self.input[start:], tsc, utcb,
88 print "Index error with event type %d" % typ
92 """Get the next event in stream
94 Allows iterating over the stream."""
95 start = self.offset * tsar_events.Event.EVENTSIZE
96 if (self.offset % 1000 == 0) or (self.offset == self.eventCount):
100 return self._build(start)
102 def eventAtOffset(self, offset):
103 """Get event at a specified offset.
105 Random access to the stream."""
106 start = offset * tsar_events.Event.EVENTSIZE
107 return self._build(start)
111 """Reader for zipped uu-encoded data"""
113 def __init__(self, logfile):
114 #tmp = tempfile.NamedTemporaryFile(mode="w+b")
115 # XXX also print UID here
116 tmp = file(logfile.readlines()[0].strip().split(" ")[2], "wb")
117 sys.stderr.write("UUDecoding %s -> %s\n" % (logfile.name, tmp.name))
119 uu.decode(logfile.name, tmp.name)
120 self.zipFile = gzip.open(tmp.name)
122 self.pfx = tmp.name.split(".")[0]
128 """Read the raw bytes from the underlying stream
131 bytes = self.zipFile.read(1024)
134 bytes = self.zipFile.read(1024)
135 sys.stderr.write("Read %d bytes.\n" % len(decomp))
142 Raw list of events from potentially multiple event stream sources
146 self.stream_index = 0
148 def addStream(self, eventFactory):
149 """Add another stream to the event sources"""
150 self.streams += [eventFactory]
153 """Reset the event list"""
154 for s in self.streams:
156 self.stream_index = 0
159 """Return the next event.
161 Continuously calling this function iterates over the associated
162 streams one at a time. Returns 'None' if no more events are to
166 if self.stream_index >= len(self.streams):
169 ev = self.streams[self.stream_index].nextEvent()
172 sys.stderr.write("\033[0m\n")
173 self.stream_index += 1
179 def print_plain(events):
180 """Plain dump of an event list"""
185 def print_pretty(events):
186 """Pretty-printed event list.
188 Prints a table. First column is a time stamp. Every other
189 colunm represents one distinct replica
194 # first run to determine UTCB IDs
196 if e.type != 0 and e.uid() not in ids:
201 print "\033[32m%14s" % "Timestamp",
203 print "| %20s" % ("UID %s" % i[0:16]),
211 # Uncomment if you need horizontal separators between events
213 #for i in range(len(ids)):
219 for line in e.pretty():
221 print "%14d" % (int(e.timestamp) - last_ts),
222 last_ts = int(e.timestamp)
227 idx = ids.index(e.uid())
229 for i in range(0, idx):
232 sys.stdout.write(" | %s" % line)
233 remainder = 21 - len(remove_vt100(line))
235 sys.stdout.write(" " * remainder)
236 for i in range(idx + 1, len(ids)):
242 def remove_vt100(line):
243 """Remoe any occurrence of a VT100 color sequence from a string"""
244 return re.sub("\033\[\d+(;\d+)?m", "", line)
247 def extractLogs(inputFile):
248 """Take a QEMU log file (Fiasco serial output) and extract the
249 UU-encoded trace dumps from it.
251 files = [] # list of trace files
252 inLogFile = False # are we currently operating on a dump?
254 for l in file(inputFile).readlines():
257 # start and end indicators
258 startmo = re.match("romain.*(begin 644 .*.gz)", v)
259 endmo = re.match("romain.*end", v)
262 curFile = tempfile.NamedTemporaryFile(mode="w+")
265 # Write lines belonging to the dump to temporary file.
266 # Remove L4Re's log prefix upfront
268 curFile.write(v.replace("romain | ", ""))
270 if inLogFile and endmo:
278 if len(sys.argv) < 2:
279 print "Need at least 1 argument"
283 evproc = tsar_rules.EventPreprocessor()
285 for f in extractLogs(sys.argv[1]):
286 sys.stderr.write("=== %s ===\n" % f.name)
287 f.seek(0) # need to reset file seek ptr
288 elist.addStream(EventFactory(TraceReader(f)))
294 events += [evproc.process(e)]
297 # events are not necessarily sorted by time right now!
298 events.sort(key=operator.attrgetter('timestamp'))
304 if __name__ == "__main__":