xref: /aosp_15_r20/external/cronet/build/android/pylib/instrumentation/json_perf_parser.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1# Copyright 2013 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5
6"""A helper module for parsing JSON objects from perf tests results."""
7
8
9import json
10
11
12def GetAverageRunInfo(json_data, name):
13  """Summarizes TraceEvent JSON data for performance metrics.
14
15  Example JSON Inputs (More tags can be added but these are required):
16  Measuring Duration:
17  [
18    { "cat": "Java",
19      "ts": 10000000000,
20      "ph": "S",
21      "name": "TestTrace"
22    },
23    { "cat": "Java",
24      "ts": 10000004000,
25      "ph": "F",
26      "name": "TestTrace"
27    },
28    ...
29  ]
30
31  Measuring Call Frequency (FPS):
32  [
33    { "cat": "Java",
34      "ts": 10000000000,
35      "ph": "I",
36      "name": "TestTraceFPS"
37    },
38    { "cat": "Java",
39      "ts": 10000004000,
40      "ph": "I",
41      "name": "TestTraceFPS"
42    },
43    ...
44  ]
45
46  Args:
47    json_data: A list of dictonaries each representing a JSON object.
48    name: The 'name' tag to filter on in the JSON file.
49
50  Returns:
51    A dictionary of result data with the following tags:
52      min: The minimum value tracked.
53      max: The maximum value tracked.
54      average: The average of all the values tracked.
55      count: The number of times the category/name pair was tracked.
56      type: The type of tracking ('Instant' for instant tags and 'Span' for
57            begin/end tags.
58      category: The passed in category filter.
59      name: The passed in name filter.
60      data_points: A list of all of the times used to generate this data.
61      units: The units for the values being reported.
62
63  Raises:
64    Exception: if entry contains invalid data.
65  """
66
67  def EntryFilter(entry):
68    return entry['cat'] == 'Java' and entry['name'] == name
69  filtered_entries = [j for j in json_data if EntryFilter(j)]
70
71  result = {}
72
73  result['min'] = -1
74  result['max'] = -1
75  result['average'] = 0
76  result['count'] = 0
77  result['type'] = 'Unknown'
78  result['category'] = 'Java'
79  result['name'] = name
80  result['data_points'] = []
81  result['units'] = ''
82
83  total_sum = 0
84
85  last_val = 0
86  val_type = None
87  for entry in filtered_entries:
88    if not val_type:
89      if 'mem' in entry:
90        val_type = 'mem'
91
92        def GetVal(entry):
93          return entry['mem']
94
95        result['units'] = 'kb'
96      elif 'ts' in entry:
97        val_type = 'ts'
98
99        def GetVal(entry):
100          return float(entry['ts']) / 1000.0
101
102        result['units'] = 'ms'
103      else:
104        raise Exception('Entry did not contain valid value info: %s' % entry)
105
106    if not val_type in entry:
107      raise Exception('Entry did not contain expected value type "%s" '
108                      'information: %s' % (val_type, entry))
109    val = GetVal(entry)
110    if (entry['ph'] == 'S' and
111        (result['type'] == 'Unknown' or result['type'] == 'Span')):
112      result['type'] = 'Span'
113      last_val = val
114    elif ((entry['ph'] == 'F' and result['type'] == 'Span') or
115          (entry['ph'] == 'I' and (result['type'] == 'Unknown' or
116                                   result['type'] == 'Instant'))):
117      if last_val > 0:
118        delta = val - last_val
119        if result['min'] == -1 or result['min'] > delta:
120          result['min'] = delta
121        if result['max'] == -1 or result['max'] < delta:
122          result['max'] = delta
123        total_sum += delta
124        result['count'] += 1
125        result['data_points'].append(delta)
126      if entry['ph'] == 'I':
127        result['type'] = 'Instant'
128        last_val = val
129  if result['count'] > 0:
130    result['average'] = total_sum / result['count']
131
132  return result
133
134
135def GetAverageRunInfoFromJSONString(json_string, name):
136  """Returns the results from GetAverageRunInfo using a JSON string.
137
138  Args:
139    json_string: The string containing JSON.
140    name: The 'name' tag to filter on in the JSON file.
141
142  Returns:
143    See GetAverageRunInfo Returns section.
144  """
145  return GetAverageRunInfo(json.loads(json_string), name)
146
147
148def GetAverageRunInfoFromFile(json_file, name):
149  """Returns the results from GetAverageRunInfo using a JSON file.
150
151  Args:
152    json_file: The path to a JSON file.
153    name: The 'name' tag to filter on in the JSON file.
154
155  Returns:
156    See GetAverageRunInfo Returns section.
157  """
158  with open(json_file, 'r') as f:
159    data = f.read()
160    perf = json.loads(data)
161
162  return GetAverageRunInfo(perf, name)
163