From patchwork Thu Mar 1 13:25:40 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harsh Prateek Bora X-Patchwork-Id: 144006 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 273D9B6EF3 for ; Fri, 2 Mar 2012 00:26:40 +1100 (EST) Received: from localhost ([::1]:50144 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S361l-00037O-Du for incoming@patchwork.ozlabs.org; Thu, 01 Mar 2012 08:26:37 -0500 Received: from eggs.gnu.org ([208.118.235.92]:51112) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S361S-0002vU-KG for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:26:22 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S361J-0000Z5-Hd for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:26:18 -0500 Received: from e28smtp07.in.ibm.com ([122.248.162.7]:37228) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S361I-0000Y9-Gi for qemu-devel@nongnu.org; Thu, 01 Mar 2012 08:26:09 -0500 Received: from /spool/local by e28smtp07.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Thu, 1 Mar 2012 18:56:02 +0530 Received: from d28relay02.in.ibm.com (9.184.220.59) by e28smtp07.in.ibm.com (192.168.1.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Thu, 1 Mar 2012 18:55:44 +0530 Received: from d28av02.in.ibm.com (d28av02.in.ibm.com [9.184.220.64]) by d28relay02.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q21DPhwS3121190 for ; Thu, 1 Mar 2012 18:55:44 +0530 Received: from d28av02.in.ibm.com (loopback [127.0.0.1]) by d28av02.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q21DPgPE013311 for ; Fri, 2 Mar 2012 00:25:43 +1100 Received: from harshbora.in.ibm.com ([9.124.35.242]) by d28av02.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q21DPfJs013178; Fri, 2 Mar 2012 00:25:41 +1100 From: Harsh Prateek Bora To: qemu-devel@nongnu.org Date: Thu, 1 Mar 2012 18:55:40 +0530 Message-Id: <1330608340-9515-15-git-send-email-harsh@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.1.1 In-Reply-To: <1330608340-9515-1-git-send-email-harsh@linux.vnet.ibm.com> References: <1330608340-9515-1-git-send-email-harsh@linux.vnet.ibm.com> x-cbid: 12030113-8878-0000-0000-00000180FF3B X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 122.248.162.7 Cc: stefanha@gmail.com, vilanova@ac.upc.edu, aneesh.kumar@linux.vnet.ibm.com Subject: [Qemu-devel] [RFC PATCH v5 14/14] scripts/simpltrace.py changes: Support simplettrace v2 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Added support for Simpletrace v2 log format Signed-off-by: Harsh Prateek Bora --- scripts/simpletrace.py | 137 +++++++++++++++++++++++++++++++++--------------- 1 files changed, 94 insertions(+), 43 deletions(-) diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py index f55e5e6..05a7c4f 100755 --- a/scripts/simpletrace.py +++ b/scripts/simpletrace.py @@ -12,53 +12,78 @@ import struct import re import inspect +from tracetool import * header_event_id = 0xffffffffffffffff header_magic = 0xf2b177cb0aa429b4 -header_version = 0 +log_version = 0 dropped_event_id = 0xfffffffffffffffe -trace_fmt = '=QQQQQQQQ' -trace_len = struct.calcsize(trace_fmt) -event_re = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*') +log_header_fmt = '=QQQ' +rec_header_fmt = '=QQII' +trace_v1_fmt = '=QQQQQQQQ' +trace_v1_len = struct.calcsize(trace_v1_fmt) -def parse_events(fobj): - """Parse a trace-events file into {event_num: (name, arg1, ...)}.""" - - def get_argnames(args): - """Extract argument names from a parameter list.""" - return tuple(arg.split()[-1].lstrip('*') for arg in args.split(',')) - - events = {dropped_event_id: ('dropped', 'count')} - event_num = 0 - for line in fobj: - m = event_re.match(line.strip()) - if m is None: - continue - - disable, name, args = m.groups() - events[event_num] = (name,) + get_argnames(args) - event_num += 1 - return events - -def read_record(fobj): - """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" - s = fobj.read(trace_len) - if len(s) != trace_len: +def read_header(fobj, hfmt): + '''Read a trace record header''' + hlen = struct.calcsize(hfmt) + hdr = fobj.read(hlen) + if len(hdr) != hlen: return None - return struct.unpack(trace_fmt, s) + return struct.unpack(hfmt, hdr) -def read_trace_file(fobj): +def get_record(edict, rechdr, fobj): + """Deserialize a simpletrace v2 record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" + if rechdr is None: + return None + rec = (rechdr[0], rechdr[1]) + if rechdr[0] != dropped_event_id: + event_id = rechdr[0] + event = edict[event_id] + for type, name in event.args: + if type_is_string(type): + l = fobj.read(4) + (len,) = struct.unpack('=L', l) + s = fobj.read(len) + rec = rec + (s,) + else: + (value,) = struct.unpack('=Q', fobj.read(8)) + rec = rec + (value,) + else: + (value,) = struct.unpack('=Q', fobj.read(8)) + rec = rec + (value,) + return rec + + +def read_record(edict, fobj): + """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6).""" + if log_version == 0: + s = fobj.read(trace_v1_len) + if len(s) != trace_v1_len: + return None + return struct.unpack(trace_v1_fmt, s) + if log_version == 2: + rechdr = read_header(fobj, rec_header_fmt) + return get_record(edict, rechdr, fobj) # return tuple of record elements + +def read_trace_file(edict, fobj): """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6).""" - header = read_record(fobj) + global log_version + header = read_header(fobj, log_header_fmt) if header is None or \ header[0] != header_event_id or \ - header[1] != header_magic or \ - header[2] != header_version: - raise ValueError('not a trace file or incompatible version') + header[1] != header_magic: + raise ValueError('not a valid trace file') + if header[2] != 0 and \ + header[2] != 2: + raise ValueError('trace file version not supported') + + log_version = header[2] + if log_version == 0: + temp = fobj.read(40) # read unused header bytes while True: - rec = read_record(fobj) + rec = read_record(edict, fobj) if rec is None: break @@ -89,16 +114,28 @@ class Analyzer(object): def process(events, log, analyzer): """Invoke an analyzer on each event in a log.""" if isinstance(events, str): - events = parse_events(open(events, 'r')) + events = read_events(open(events, 'r')) if isinstance(log, str): log = open(log, 'rb') + enabled_events = [] + edict = {dropped_event_id: 'dropped_count'} + + for e in events: + if 'disable' not in e.properties: + enabled_events.append(e) + for num, event in enumerate(enabled_events): + edict[num] = event + def build_fn(analyzer, event): - fn = getattr(analyzer, event[0], None) + if isinstance(event, str): + return analyzer.catchall + + fn = getattr(analyzer, event.name, None) if fn is None: return analyzer.catchall - event_argcount = len(event) - 1 + event_argcount = len(event.args) fn_argcount = len(inspect.getargspec(fn)[0]) - 1 if fn_argcount == event_argcount + 1: # Include timestamp as first argument @@ -109,9 +146,9 @@ def process(events, log, analyzer): analyzer.begin() fn_cache = {} - for rec in read_trace_file(log): + for rec in read_trace_file(edict, log): event_num = rec[0] - event = events[event_num] + event = edict[event_num] if event_num not in fn_cache: fn_cache[event_num] = build_fn(analyzer, event) fn_cache[event_num](event, rec) @@ -128,7 +165,7 @@ def run(analyzer): sys.stderr.write('usage: %s \n' % sys.argv[0]) sys.exit(1) - events = parse_events(open(sys.argv[1], 'r')) + events = read_events(open(sys.argv[1], 'r')) process(events, sys.argv[2], analyzer) if __name__ == '__main__': @@ -137,15 +174,29 @@ if __name__ == '__main__': self.last_timestamp = None def catchall(self, event, rec): + i = 1 timestamp = rec[1] if self.last_timestamp is None: self.last_timestamp = timestamp delta_ns = timestamp - self.last_timestamp self.last_timestamp = timestamp - fields = [event[0], '%0.3f' % (delta_ns / 1000.0)] - for i in xrange(1, len(event)): - fields.append('%s=0x%x' % (event[i], rec[i + 1])) + if rec[0] == dropped_event_id: + fields = ['Dropped_Event', '%0.3f' % (delta_ns / 1000.0)] + fields.append('%s=0x%x' % ("dropped_events", rec[2])) + else: + fields = [event.name, '%0.3f' % (delta_ns / 1000.0)] + if log_version == 0: + for type, name in event.args: + fields.append('%s=0x%x' % (name, rec[i + 1])) + i += 1 + elif log_version == 2: + for type, name in event.args: + if type_is_string(type): + fields.append('%s=%s' % (name, rec[i + 1])) + else: + fields.append('%s=0x%x' % (name, rec[i + 1])) + i += 1 print ' '.join(fields) run(Formatter())