1 # Copyright 2016 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 import math 5 import json 6 7 8 class ParsedTraceEvents(object): 9 def __init__(self, events = None, trace_filename = None): 10 """ 11 Utility class for filtering and manipulating trace data. 12 13 events -- An iterable object containing trace events 14 trace_filename -- A file object that contains a complete trace. 15 16 """ 17 if trace_filename and events: 18 raise Exception("Provide either a trace file or event list") 19 if not trace_filename and events == None: 20 raise Exception("Provide either a trace file or event list") 21 22 if trace_filename: 23 f = open(trace_filename, 'r') 24 t = f.read() 25 f.close() 26 27 # If the event data begins with a [, then we know it should end with a ]. 28 # The reason we check for this is because some tracing implementations 29 # cannot guarantee that a ']' gets written to the trace file. So, we are 30 # forgiving and if this is obviously the case, we fix it up before 31 # throwing the string at JSON.parse. 32 if t[0] == '[': 33 n = len(t); 34 if t[n - 1] != ']' and t[n - 1] != '\n': 35 t = t + ']' 36 elif t[n - 2] != ']' and t[n - 1] == '\n': 37 t = t + ']' 38 elif t[n - 3] != ']' and t[n - 2] == '\r' and t[n - 1] == '\n': 39 t = t + ']' 40 41 try: 42 events = json.loads(t) 43 except ValueError: 44 raise Exception("Corrupt trace, did not parse. Value: %s" % t) 45 46 if 'traceEvents' in events: 47 events = events['traceEvents'] 48 49 if not hasattr(events, '__iter__'): 50 raise Exception, 'events must be iteraable.' 51 self.events = events 52 self.pids = None 53 self.tids = None 54 55 def __len__(self): 56 return len(self.events) 57 58 def __getitem__(self, i): 59 return self.events[i] 60 61 def __setitem__(self, i, v): 62 self.events[i] = v 63 64 def __repr__(self): 65 return "[%s]" % ",\n ".join([repr(e) for e in self.events]) 66 67 def findProcessIds(self): 68 if self.pids: 69 return self.pids 70 pids = set() 71 for e in self.events: 72 if "pid" in e and e["pid"]: 73 pids.add(e["pid"]) 74 self.pids = list(pids) 75 return self.pids 76 77 def findThreadIds(self): 78 if self.tids: 79 return self.tids 80 tids = set() 81 for e in self.events: 82 if "tid" in e and e["tid"]: 83 tids.add(e["tid"]) 84 self.tids = list(tids) 85 return self.tids 86 87 def findEventsOnProcess(self, pid): 88 return ParsedTraceEvents([e for e in self.events if e["pid"] == pid]) 89 90 def findEventsOnThread(self, tid): 91 return ParsedTraceEvents( 92 [e for e in self.events if e["ph"] != "M" and e["tid"] == tid]) 93 94 def findByPhase(self, ph): 95 return ParsedTraceEvents([e for e in self.events if e["ph"] == ph]) 96 97 def findByName(self, n): 98 return ParsedTraceEvents([e for e in self.events if e["name"] == n]) 99