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 5"""Filters a big trace keeping only the last memory-infra dumps.""" 6 7import collections 8import gzip 9import json 10 11 12def FormatBytes(value): 13 units = ['B', 'KiB', 'MiB', 'GiB'] 14 while abs(value) >= 1024 and len(units) > 1: 15 value /= 1024 16 units = units.pop(0) 17 return '%3.1f %s' % (value, units[0]) 18 19 20def Main(argv): 21 if len(argv) < 2: 22 print 'Usage: %s trace.json[.gz]' % argv[0] 23 return 1 24 25 in_path = argv[1] 26 if in_path.lower().endswith('.gz'): 27 fin = gzip.open(in_path, 'rb') 28 else: 29 fin = open(in_path, 'r') 30 with fin: 31 print 'Loading trace (can take 1 min on a z620 for a 1GB trace)...' 32 trace = json.load(fin) 33 print 'Done. Read ' + FormatBytes(fin.tell()) 34 35 print 'Filtering events' 36 phase_count = collections.defaultdict(int) 37 out_events = [] 38 global_dumps = collections.OrderedDict() 39 if isinstance(trace, dict): 40 in_events = trace.get('traceEvents', []) 41 elif isinstance(trace, list) and isinstance(trace[0], dict): 42 in_events = trace 43 44 for evt in in_events: 45 phase = evt.get('ph', '?') 46 phase_count[phase] += 1 47 48 # Drop all diagnostic events for memory-infra debugging. 49 if phase not in ('v', 'V') and evt.get('cat', '').endswith('memory-infra'): 50 continue 51 52 # pass-through all the other non-memory-infra events 53 if phase != 'v': 54 out_events.append(evt) 55 continue 56 57 # Recreate the global dump groups 58 event_id = evt['id'] 59 global_dumps.setdefault(event_id, []) 60 global_dumps[event_id].append(evt) 61 62 63 print 'Detected %d memory-infra global dumps' % len(global_dumps) 64 if global_dumps: 65 max_procs = max(len(x) for x in global_dumps.itervalues()) 66 print 'Max number of processes seen: %d' % max_procs 67 68 ndumps = 2 69 print 'Preserving the last %d memory-infra dumps' % ndumps 70 detailed_dumps = [] 71 non_detailed_dumps = [] 72 for global_dump in global_dumps.itervalues(): 73 try: 74 level_of_detail = global_dump[0]['args']['dumps']['level_of_detail'] 75 except KeyError: 76 level_of_detail = None 77 if level_of_detail == 'detailed': 78 detailed_dumps.append(global_dump) 79 else: 80 non_detailed_dumps.append(global_dump) 81 82 dumps_to_preserve = detailed_dumps[-ndumps:] 83 ndumps -= len(dumps_to_preserve) 84 if ndumps: 85 dumps_to_preserve += non_detailed_dumps[-ndumps:] 86 87 for global_dump in dumps_to_preserve: 88 out_events += global_dump 89 90 print '\nEvents histogram for the original trace (count by phase)' 91 print '--------------------------------------------------------' 92 for phase, count in sorted(phase_count.items(), key=lambda x: x[1]): 93 print '%s %d' % (phase, count) 94 95 out_path = in_path.split('.json')[0] + '-filtered.json' 96 print '\nWriting filtered trace to ' + out_path, 97 with open(out_path, 'w') as fout: 98 json.dump({'traceEvents': out_events}, fout) 99 num_bytes_written = fout.tell() 100 print ' (%s written)' % FormatBytes(num_bytes_written) 101