json_perf_parser.py revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""A helper module for parsing JSON objects from perf tests results."""
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import json
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetAverageRunInfo(json_data, name):
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Summarizes TraceEvent JSON data for performance metrics.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Example JSON Inputs (More tags can be added but these are required):
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Measuring Duration:
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "cat": "Java",
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ts": 10000000000,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ph": "S",
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name": "TestTrace"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "cat": "Java",
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ts": 10000004000,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ph": "F",
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name": "TestTrace"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ...
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ]
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Measuring Call Frequency (FPS):
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "cat": "Java",
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ts": 10000000000,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ph": "I",
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name": "TestTraceFPS"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { "cat": "Java",
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ts": 10000004000,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ph": "I",
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name": "TestTraceFPS"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ...
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ]
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json_data: A list of dictonaries each representing a JSON object.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name: The 'name' tag to filter on in the JSON file.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    A dictionary of result data with the following tags:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      min: The minimum value tracked.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max: The maximum value tracked.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      average: The average of all the values tracked.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      count: The number of times the category/name pair was tracked.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type: The type of tracking ('Instant' for instant tags and 'Span' for
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            begin/end tags.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      category: The passed in category filter.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name: The passed in name filter.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_points: A list of all of the times used to generate this data.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      units: The units for the values being reported.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Raises:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Exception: if entry contains invalid data.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def EntryFilter(entry):
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return entry['cat'] == 'Java' and entry['name'] == name
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filtered_entries = filter(EntryFilter, json_data)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result = {}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['min'] = -1
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['max'] = -1
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['average'] = 0
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['count'] = 0
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['type'] = 'Unknown'
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['category'] = 'Java'
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['name'] = name
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['data_points'] = []
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result['units'] = ''
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  total_sum = 0
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_val = 0
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  val_type = None
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for entry in filtered_entries:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not val_type:
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if 'mem' in entry:
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        val_type = 'mem'
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        def GetVal(entry):
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return entry['mem']
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result['units'] = 'kb'
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif 'ts' in entry:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        val_type = 'ts'
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        def GetVal(entry):
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return float(entry['ts']) / 1000.0
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result['units'] = 'ms'
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise Exception('Entry did not contain valid value info: %s' % entry)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not val_type in entry:
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise Exception('Entry did not contain expected value type "%s" '
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      'information: %s' % (val_type, entry))
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    val = GetVal(entry)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry['ph'] == 'S' and
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (result['type'] == 'Unknown' or result['type'] == 'Span')):
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result['type'] = 'Span'
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_val = val
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif ((entry['ph'] == 'F' and result['type'] == 'Span') or
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (entry['ph'] == 'I' and (result['type'] == 'Unknown' or
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   result['type'] == 'Instant'))):
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if last_val > 0:
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        delta = val - last_val
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if result['min'] == -1 or result['min'] > delta:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          result['min'] = delta
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if result['max'] == -1 or result['max'] < delta:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          result['max'] = delta
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        total_sum += delta
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result['count'] += 1
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result['data_points'].append(delta)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if entry['ph'] == 'I':
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result['type'] = 'Instant'
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        last_val = val
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if result['count'] > 0: result['average'] = total_sum / result['count']
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetAverageRunInfoFromJSONString(json_string, name):
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns the results from GetAverageRunInfo using a JSON string.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json_string: The string containing JSON.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name: The 'name' tag to filter on in the JSON file.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    See GetAverageRunInfo Returns section.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAverageRunInfo(json.loads(json_string), name)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetAverageRunInfoFromFile(json_file, name):
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns the results from GetAverageRunInfo using a JSON file.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    json_file: The path to a JSON file.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    name: The 'name' tag to filter on in the JSON file.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    See GetAverageRunInfo Returns section.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  with open(json_file, 'r') as f:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    data = f.read()
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perf = json.loads(data)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetAverageRunInfo(perf, name)
161