Home | History | Annotate | Download | only in tracing_build
      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 
      7 import collections
      8 import gzip
      9 import json
     10 
     11 
     12 def 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 
     20 def 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