1cb93a386Sopenharmony_ci# Copyright 2019 The Chromium Authors. All rights reserved.
2cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
3cb93a386Sopenharmony_ci# found in the LICENSE file.
4cb93a386Sopenharmony_ci
5cb93a386Sopenharmony_ci# Recipe which runs Skottie-WASM and Lottie-Web perf.
6cb93a386Sopenharmony_ci
7cb93a386Sopenharmony_ciimport calendar
8cb93a386Sopenharmony_ciimport json
9cb93a386Sopenharmony_ciimport re
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ciPYTHON_VERSION_COMPATIBILITY = "PY2+3"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci# trim
14cb93a386Sopenharmony_ciDEPS = [
15cb93a386Sopenharmony_ci  'flavor',
16cb93a386Sopenharmony_ci  'checkout',
17cb93a386Sopenharmony_ci  'env',
18cb93a386Sopenharmony_ci  'infra',
19cb93a386Sopenharmony_ci  'recipe_engine/context',
20cb93a386Sopenharmony_ci  'recipe_engine/file',
21cb93a386Sopenharmony_ci  'recipe_engine/json',
22cb93a386Sopenharmony_ci  'recipe_engine/path',
23cb93a386Sopenharmony_ci  'recipe_engine/properties',
24cb93a386Sopenharmony_ci  'recipe_engine/python',
25cb93a386Sopenharmony_ci  'recipe_engine/step',
26cb93a386Sopenharmony_ci  'recipe_engine/time',
27cb93a386Sopenharmony_ci  'run',
28cb93a386Sopenharmony_ci  'vars',
29cb93a386Sopenharmony_ci]
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ciLOTTIE_WEB_EXCLUDE = [
32cb93a386Sopenharmony_ci  # See https://bugs.chromium.org/p/skia/issues/detail?id=9187#c4
33cb93a386Sopenharmony_ci  'lottiefiles.com - Progress Success.json',
34cb93a386Sopenharmony_ci  # Fails with "val2 is not defined".
35cb93a386Sopenharmony_ci  'lottiefiles.com - VR.json',
36cb93a386Sopenharmony_ci  'vr_animation.json',
37cb93a386Sopenharmony_ci  # Times out.
38cb93a386Sopenharmony_ci  'lottiefiles.com - Nudge.json',
39cb93a386Sopenharmony_ci  'lottiefiles.com - Retweet.json',
40cb93a386Sopenharmony_ci  # Trace file has majority main_frame_aborted terminations in it and < 25
41cb93a386Sopenharmony_ci  # occurrences of submitted_frame + missed_frame.
42cb93a386Sopenharmony_ci  # Static scenes (nothing animating)
43cb93a386Sopenharmony_ci  'mask1.json',
44cb93a386Sopenharmony_ci  'mask2.json',
45cb93a386Sopenharmony_ci  'stacking.json',
46cb93a386Sopenharmony_ci]
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ciSKOTTIE_WASM_EXCLUDE = [
49cb93a386Sopenharmony_ci  # Trace file has majority main_frame_aborted terminations in it and < 25
50cb93a386Sopenharmony_ci  # occurrences of submitted_frame + missed_frame.
51cb93a386Sopenharmony_ci  # Below descriptions are added from fmalita@'s comments in
52cb93a386Sopenharmony_ci  # https://skia-review.googlesource.com/c/skia/+/229419
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci  # Static scenes (nothing animating)
55cb93a386Sopenharmony_ci  'mask1.json',
56cb93a386Sopenharmony_ci  'mask2.json',
57cb93a386Sopenharmony_ci  'stacking.json',
58cb93a386Sopenharmony_ci  # Static in Skottie only due to unsupported feature (expressions).
59cb93a386Sopenharmony_ci  'dna.json',
60cb93a386Sopenharmony_ci  'elephant_trunk_swing.json',
61cb93a386Sopenharmony_ci  # Looks all static in both skottie/lottie, not sure why lottie doesn't abort
62cb93a386Sopenharmony_ci  # as many frames.
63cb93a386Sopenharmony_ci  'hexadots.json',
64cb93a386Sopenharmony_ci  # Very short transition, mostly static.
65cb93a386Sopenharmony_ci  'screenhole.json',
66cb93a386Sopenharmony_ci  # Broken in Skottie due to unidentified missing feature.
67cb93a386Sopenharmony_ci  'interleague_golf_logo.json',
68cb93a386Sopenharmony_ci  'loading.json',
69cb93a386Sopenharmony_ci  'lottiefiles.com - Loading 2.json',
70cb93a386Sopenharmony_ci  'streetby_loading.json',
71cb93a386Sopenharmony_ci  'streetby_test_loading.json',
72cb93a386Sopenharmony_ci  # Times out
73cb93a386Sopenharmony_ci  'beetle.json',
74cb93a386Sopenharmony_ci]
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci# These files work in SVG but not in Canvas.
77cb93a386Sopenharmony_ciLOTTIE_WEB_CANVAS_EXCLUDE = LOTTIE_WEB_EXCLUDE + [
78cb93a386Sopenharmony_ci  'Hello World.json',
79cb93a386Sopenharmony_ci  'interactive_menu.json',
80cb93a386Sopenharmony_ci  'Name.json',
81cb93a386Sopenharmony_ci]
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_cidef RunSteps(api):
85cb93a386Sopenharmony_ci  api.vars.setup()
86cb93a386Sopenharmony_ci  api.flavor.setup(None)
87cb93a386Sopenharmony_ci  checkout_root = api.path['start_dir']
88cb93a386Sopenharmony_ci  buildername = api.properties['buildername']
89cb93a386Sopenharmony_ci  node_path = api.path['start_dir'].join('node', 'node', 'bin', 'node')
90cb93a386Sopenharmony_ci  lottie_files = api.file.listdir(
91cb93a386Sopenharmony_ci      'list lottie files', api.flavor.host_dirs.lotties_dir,
92cb93a386Sopenharmony_ci      test_data=['lottie1.json', 'lottie2.json', 'lottie3.json', 'LICENSE'])
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci  if 'SkottieWASM' in buildername:
95cb93a386Sopenharmony_ci    source_type = 'skottie'
96cb93a386Sopenharmony_ci    renderer = 'skottie-wasm'
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    perf_app_dir = checkout_root.join('skia', 'tools', 'skottie-wasm-perf')
99cb93a386Sopenharmony_ci    canvaskit_js_path = api.vars.build_dir.join('canvaskit.js')
100cb93a386Sopenharmony_ci    canvaskit_wasm_path = api.vars.build_dir.join('canvaskit.wasm')
101cb93a386Sopenharmony_ci    skottie_wasm_js_path = perf_app_dir.join('skottie-wasm-perf.js')
102cb93a386Sopenharmony_ci    perf_app_cmd = [
103cb93a386Sopenharmony_ci        node_path, skottie_wasm_js_path,
104cb93a386Sopenharmony_ci        '--canvaskit_js', canvaskit_js_path,
105cb93a386Sopenharmony_ci        '--canvaskit_wasm', canvaskit_wasm_path,
106cb93a386Sopenharmony_ci    ]
107cb93a386Sopenharmony_ci    lottie_files = [x for x in lottie_files
108cb93a386Sopenharmony_ci                    if api.path.basename(x) not in SKOTTIE_WASM_EXCLUDE]
109cb93a386Sopenharmony_ci  elif 'LottieWeb' in buildername:
110cb93a386Sopenharmony_ci    source_type = 'lottie-web'
111cb93a386Sopenharmony_ci    renderer = 'lottie-web'
112cb93a386Sopenharmony_ci    if 'Canvas' in buildername:
113cb93a386Sopenharmony_ci      backend = 'canvas'
114cb93a386Sopenharmony_ci      lottie_files = [
115cb93a386Sopenharmony_ci          x for x in lottie_files
116cb93a386Sopenharmony_ci          if api.path.basename(x) not in LOTTIE_WEB_CANVAS_EXCLUDE]
117cb93a386Sopenharmony_ci    else:
118cb93a386Sopenharmony_ci      backend = 'svg'
119cb93a386Sopenharmony_ci      lottie_files = [x for x in lottie_files
120cb93a386Sopenharmony_ci                      if api.path.basename(x) not in LOTTIE_WEB_EXCLUDE]
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci    perf_app_dir = checkout_root.join('skia', 'tools', 'lottie-web-perf')
123cb93a386Sopenharmony_ci    lottie_web_js_path = perf_app_dir.join('lottie-web-perf.js')
124cb93a386Sopenharmony_ci    perf_app_cmd = [
125cb93a386Sopenharmony_ci        node_path, lottie_web_js_path,
126cb93a386Sopenharmony_ci        '--backend', backend,
127cb93a386Sopenharmony_ci    ]
128cb93a386Sopenharmony_ci  else:
129cb93a386Sopenharmony_ci    raise Exception('Could not recognize the buildername %s' % buildername)
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci  if api.vars.builder_cfg.get('cpu_or_gpu') == 'GPU':
132cb93a386Sopenharmony_ci    perf_app_cmd.append('--use_gpu')
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_ci  # Install prerequisites.
135cb93a386Sopenharmony_ci  env_prefixes = {'PATH': [api.path['start_dir'].join('node', 'node', 'bin')]}
136cb93a386Sopenharmony_ci  with api.context(cwd=perf_app_dir, env_prefixes=env_prefixes):
137cb93a386Sopenharmony_ci    api.step('npm install', cmd=['npm', 'install'])
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci  perf_results = {}
140cb93a386Sopenharmony_ci  output_dir = api.path.mkdtemp('g3_try')
141cb93a386Sopenharmony_ci  # Run the perf_app_cmd on each lottie file and parse the trace files.
142cb93a386Sopenharmony_ci  for _, lottie_file in enumerate(lottie_files):
143cb93a386Sopenharmony_ci    lottie_filename = api.path.basename(lottie_file)
144cb93a386Sopenharmony_ci    if not lottie_filename.endswith('.json'):
145cb93a386Sopenharmony_ci      continue
146cb93a386Sopenharmony_ci    output_file = output_dir.join(lottie_filename)
147cb93a386Sopenharmony_ci    with api.context(cwd=perf_app_dir, env={'DISPLAY': ':0'}):
148cb93a386Sopenharmony_ci      # This is occasionally flaky due to skbug.com/9207, adding retries.
149cb93a386Sopenharmony_ci      attempts = 3
150cb93a386Sopenharmony_ci      # Add output and input arguments to the cmd.
151cb93a386Sopenharmony_ci      api.run.with_retry(api.step, 'Run perf cmd line app', attempts,
152cb93a386Sopenharmony_ci                         cmd=perf_app_cmd + [
153cb93a386Sopenharmony_ci                             '--input', lottie_file,
154cb93a386Sopenharmony_ci                             '--output', output_file,
155cb93a386Sopenharmony_ci                         ], infra_step=True)
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci    perf_results[lottie_filename] = {
158cb93a386Sopenharmony_ci        'gl': parse_trace(output_file, lottie_filename, api, renderer),
159cb93a386Sopenharmony_ci    }
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_ci  # Construct contents of the output JSON.
162cb93a386Sopenharmony_ci  perf_json = {
163cb93a386Sopenharmony_ci      'gitHash': api.properties['revision'],
164cb93a386Sopenharmony_ci      'swarming_bot_id': api.vars.swarming_bot_id,
165cb93a386Sopenharmony_ci      'swarming_task_id': api.vars.swarming_task_id,
166cb93a386Sopenharmony_ci      'key': {
167cb93a386Sopenharmony_ci        'bench_type': 'tracing',
168cb93a386Sopenharmony_ci        'source_type': source_type,
169cb93a386Sopenharmony_ci      },
170cb93a386Sopenharmony_ci      'renderer': renderer,
171cb93a386Sopenharmony_ci      'results': perf_results,
172cb93a386Sopenharmony_ci  }
173cb93a386Sopenharmony_ci  if api.vars.is_trybot:
174cb93a386Sopenharmony_ci    perf_json['issue'] = api.vars.issue
175cb93a386Sopenharmony_ci    perf_json['patchset'] = api.vars.patchset
176cb93a386Sopenharmony_ci    perf_json['patch_storage'] = api.vars.patch_storage
177cb93a386Sopenharmony_ci  # Add tokens from the builder name to the key.
178cb93a386Sopenharmony_ci  reg = re.compile('Perf-(?P<os>[A-Za-z0-9_]+)-'
179cb93a386Sopenharmony_ci                   '(?P<compiler>[A-Za-z0-9_]+)-'
180cb93a386Sopenharmony_ci                   '(?P<model>[A-Za-z0-9_]+)-'
181cb93a386Sopenharmony_ci                   '(?P<cpu_or_gpu>[A-Z]+)-'
182cb93a386Sopenharmony_ci                   '(?P<cpu_or_gpu_value>[A-Za-z0-9_]+)-'
183cb93a386Sopenharmony_ci                   '(?P<arch>[A-Za-z0-9_]+)-'
184cb93a386Sopenharmony_ci                   '(?P<configuration>[A-Za-z0-9_]+)-'
185cb93a386Sopenharmony_ci                   'All(-(?P<extra_config>[A-Za-z0-9_]+)|)')
186cb93a386Sopenharmony_ci  m = reg.match(api.properties['buildername'])
187cb93a386Sopenharmony_ci  keys = ['os', 'compiler', 'model', 'cpu_or_gpu', 'cpu_or_gpu_value', 'arch',
188cb93a386Sopenharmony_ci          'configuration', 'extra_config']
189cb93a386Sopenharmony_ci  for k in keys:
190cb93a386Sopenharmony_ci    perf_json['key'][k] = m.group(k)
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci  # Create the output JSON file in perf_data_dir for the Upload task to upload.
193cb93a386Sopenharmony_ci  api.file.ensure_directory(
194cb93a386Sopenharmony_ci      'makedirs perf_dir',
195cb93a386Sopenharmony_ci      api.flavor.host_dirs.perf_data_dir)
196cb93a386Sopenharmony_ci  now = api.time.utcnow()
197cb93a386Sopenharmony_ci  ts = int(calendar.timegm(now.utctimetuple()))
198cb93a386Sopenharmony_ci  json_path = api.flavor.host_dirs.perf_data_dir.join(
199cb93a386Sopenharmony_ci      'perf_%s_%d.json' % (api.properties['revision'], ts))
200cb93a386Sopenharmony_ci  json_contents = json.dumps(
201cb93a386Sopenharmony_ci      perf_json, indent=4, sort_keys=True, separators=(',', ': '))
202cb93a386Sopenharmony_ci  api.file.write_text('write output JSON', json_path, json_contents)
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_cidef parse_trace(trace_json, lottie_filename, api, renderer):
206cb93a386Sopenharmony_ci  """parse_trace parses the specified trace JSON.
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci  Parses the trace JSON and calculates the time of a single frame.
209cb93a386Sopenharmony_ci  A dictionary is returned that has the following structure:
210cb93a386Sopenharmony_ci  {
211cb93a386Sopenharmony_ci    'frame_max_us': 100,
212cb93a386Sopenharmony_ci    'frame_min_us': 90,
213cb93a386Sopenharmony_ci    'frame_avg_us': 95,
214cb93a386Sopenharmony_ci  }
215cb93a386Sopenharmony_ci  """
216cb93a386Sopenharmony_ci  step_result = api.run(
217cb93a386Sopenharmony_ci      api.python.inline,
218cb93a386Sopenharmony_ci      'parse %s trace' % lottie_filename,
219cb93a386Sopenharmony_ci      program="""
220cb93a386Sopenharmony_ci  import json
221cb93a386Sopenharmony_ci  import sys
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ci  trace_output = sys.argv[1]
224cb93a386Sopenharmony_ci  with open(trace_output, 'r') as f:
225cb93a386Sopenharmony_ci    trace_json = json.load(f)
226cb93a386Sopenharmony_ci  output_json_file = sys.argv[2]
227cb93a386Sopenharmony_ci  renderer = sys.argv[3]  # Unused for now but might be useful in the future.
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_ci  # Output data about the GPU that was used.
230cb93a386Sopenharmony_ci  print('GPU data:')
231cb93a386Sopenharmony_ci  print(trace_json['metadata'].get('gpu-gl-renderer'))
232cb93a386Sopenharmony_ci  print(trace_json['metadata'].get('gpu-driver'))
233cb93a386Sopenharmony_ci  print(trace_json['metadata'].get('gpu-gl-vendor'))
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci  erroneous_termination_statuses = [
236cb93a386Sopenharmony_ci      'replaced_by_new_reporter_at_same_stage',
237cb93a386Sopenharmony_ci      'did_not_produce_frame',
238cb93a386Sopenharmony_ci  ]
239cb93a386Sopenharmony_ci  accepted_termination_statuses = [
240cb93a386Sopenharmony_ci      'missed_frame',
241cb93a386Sopenharmony_ci      'submitted_frame',
242cb93a386Sopenharmony_ci      'main_frame_aborted'
243cb93a386Sopenharmony_ci  ]
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci  current_frame_duration = 0
246cb93a386Sopenharmony_ci  total_frames = 0
247cb93a386Sopenharmony_ci  frame_id_to_start_ts = {}
248cb93a386Sopenharmony_ci  # Will contain tuples of frame_ids and their duration and status.
249cb93a386Sopenharmony_ci  completed_frame_id_and_duration_status = []
250cb93a386Sopenharmony_ci  # Will contain tuples of drawn frame_ids and their duration.
251cb93a386Sopenharmony_ci  drawn_frame_id_and_duration = []
252cb93a386Sopenharmony_ci  for trace in trace_json['traceEvents']:
253cb93a386Sopenharmony_ci    if 'PipelineReporter' in trace['name']:
254cb93a386Sopenharmony_ci      frame_id = trace['id']
255cb93a386Sopenharmony_ci      args = trace.get('args')
256cb93a386Sopenharmony_ci      if args and args.get('step') == 'BeginImplFrameToSendBeginMainFrame':
257cb93a386Sopenharmony_ci        frame_id_to_start_ts[frame_id] = trace['ts']
258cb93a386Sopenharmony_ci      elif args and (args.get('termination_status') in
259cb93a386Sopenharmony_ci                     accepted_termination_statuses):
260cb93a386Sopenharmony_ci        if not frame_id_to_start_ts.get(frame_id):
261cb93a386Sopenharmony_ci          print('[No start ts found for %s]' % frame_id)
262cb93a386Sopenharmony_ci          continue
263cb93a386Sopenharmony_ci        current_frame_duration = trace['ts'] - frame_id_to_start_ts[frame_id]
264cb93a386Sopenharmony_ci        total_frames += 1
265cb93a386Sopenharmony_ci        completed_frame_id_and_duration_status.append(
266cb93a386Sopenharmony_ci            (frame_id, current_frame_duration, args['termination_status']))
267cb93a386Sopenharmony_ci        if(args['termination_status'] == 'missed_frame' or
268cb93a386Sopenharmony_ci         args['termination_status'] == 'submitted_frame'):
269cb93a386Sopenharmony_ci          drawn_frame_id_and_duration.append((frame_id, current_frame_duration))
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci        # We are done with this frame_id so remove it from the dict.
272cb93a386Sopenharmony_ci        frame_id_to_start_ts.pop(frame_id)
273cb93a386Sopenharmony_ci        print('%d (%s with %s): %d' % (
274cb93a386Sopenharmony_ci            total_frames, frame_id, args['termination_status'],
275cb93a386Sopenharmony_ci            current_frame_duration))
276cb93a386Sopenharmony_ci      elif args and (args.get('termination_status') in
277cb93a386Sopenharmony_ci                     erroneous_termination_statuses):
278cb93a386Sopenharmony_ci        # Invalidate previously collected results for this frame_id.
279cb93a386Sopenharmony_ci        if frame_id_to_start_ts.get(frame_id):
280cb93a386Sopenharmony_ci          print('[Invalidating %s due to %s]' % (
281cb93a386Sopenharmony_ci              frame_id, args['termination_status']))
282cb93a386Sopenharmony_ci          frame_id_to_start_ts.pop(frame_id)
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_ci  # Calculate metrics for total completed frames.
285cb93a386Sopenharmony_ci  total_completed_frames = len(completed_frame_id_and_duration_status)
286cb93a386Sopenharmony_ci  if total_completed_frames < 25:
287cb93a386Sopenharmony_ci    raise Exception('Even with 3 loops found only %d frames' %
288cb93a386Sopenharmony_ci                    total_completed_frames)
289cb93a386Sopenharmony_ci  # Get frame avg/min/max for the middle 25 frames.
290cb93a386Sopenharmony_ci  start = (total_completed_frames - 25)/2
291cb93a386Sopenharmony_ci  print('Got %d total completed frames. Using indexes [%d, %d).' % (
292cb93a386Sopenharmony_ci      total_completed_frames, start, start+25))
293cb93a386Sopenharmony_ci  frame_max = 0
294cb93a386Sopenharmony_ci  frame_min = 0
295cb93a386Sopenharmony_ci  frame_cumulative = 0
296cb93a386Sopenharmony_ci  aborted_frames = 0
297cb93a386Sopenharmony_ci  for frame_id, duration, status in (
298cb93a386Sopenharmony_ci      completed_frame_id_and_duration_status[start:start+25]):
299cb93a386Sopenharmony_ci    frame_max = max(frame_max, duration)
300cb93a386Sopenharmony_ci    frame_min = min(frame_min, duration) if frame_min else duration
301cb93a386Sopenharmony_ci    frame_cumulative += duration
302cb93a386Sopenharmony_ci    if status == 'main_frame_aborted':
303cb93a386Sopenharmony_ci      aborted_frames += 1
304cb93a386Sopenharmony_ci
305cb93a386Sopenharmony_ci  perf_results = {}
306cb93a386Sopenharmony_ci  perf_results['frame_max_us'] = frame_max
307cb93a386Sopenharmony_ci  perf_results['frame_min_us'] = frame_min
308cb93a386Sopenharmony_ci  perf_results['frame_avg_us'] = frame_cumulative/25
309cb93a386Sopenharmony_ci  perf_results['aborted_frames'] = aborted_frames
310cb93a386Sopenharmony_ci
311cb93a386Sopenharmony_ci  # Now calculate metrics for only drawn frames.
312cb93a386Sopenharmony_ci  drawn_frame_max = 0
313cb93a386Sopenharmony_ci  drawn_frame_min = 0
314cb93a386Sopenharmony_ci  drawn_frame_cumulative = 0
315cb93a386Sopenharmony_ci  total_drawn_frames = len(drawn_frame_id_and_duration)
316cb93a386Sopenharmony_ci  if total_drawn_frames < 25:
317cb93a386Sopenharmony_ci    raise Exception('Even with 3 loops found only %d drawn frames' %
318cb93a386Sopenharmony_ci                    total_drawn_frames)
319cb93a386Sopenharmony_ci  # Get drawn frame avg/min/max from the middle 25 frames.
320cb93a386Sopenharmony_ci  start = (total_drawn_frames - 25)/2
321cb93a386Sopenharmony_ci  print('Got %d total drawn frames. Using indexes [%d-%d).' % (
322cb93a386Sopenharmony_ci        total_drawn_frames, start, start+25))
323cb93a386Sopenharmony_ci  for frame_id, duration in drawn_frame_id_and_duration[start:start+25]:
324cb93a386Sopenharmony_ci    drawn_frame_max = max(drawn_frame_max, duration)
325cb93a386Sopenharmony_ci    drawn_frame_min = (min(drawn_frame_min, duration)
326cb93a386Sopenharmony_ci                       if drawn_frame_min else duration)
327cb93a386Sopenharmony_ci    drawn_frame_cumulative += duration
328cb93a386Sopenharmony_ci  # Add metrics to perf_results.
329cb93a386Sopenharmony_ci  perf_results['drawn_frame_max_us'] = drawn_frame_max
330cb93a386Sopenharmony_ci  perf_results['drawn_frame_min_us'] = drawn_frame_min
331cb93a386Sopenharmony_ci  perf_results['drawn_frame_avg_us'] = drawn_frame_cumulative/25
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_ci  print('Final perf_results dict: %s' % perf_results)
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci  # Write perf_results to the output json.
336cb93a386Sopenharmony_ci  with open(output_json_file, 'w') as f:
337cb93a386Sopenharmony_ci    f.write(json.dumps(perf_results))
338cb93a386Sopenharmony_ci  """, args=[trace_json, api.json.output(), renderer])
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci  # Sanitize float outputs to 2 precision points.
341cb93a386Sopenharmony_ci  output = dict(step_result.json.output)
342cb93a386Sopenharmony_ci  output['frame_max_us'] = float("%.2f" % output['frame_max_us'])
343cb93a386Sopenharmony_ci  output['frame_min_us'] = float("%.2f" % output['frame_min_us'])
344cb93a386Sopenharmony_ci  output['frame_avg_us'] = float("%.2f" % output['frame_avg_us'])
345cb93a386Sopenharmony_ci  return output
346cb93a386Sopenharmony_ci
347cb93a386Sopenharmony_ci
348cb93a386Sopenharmony_cidef GenTests(api):
349cb93a386Sopenharmony_ci  trace_output = """
350cb93a386Sopenharmony_ci[{"ph":"X","name":"void skottie::Animation::seek(SkScalar)","ts":452,"dur":2.57,"tid":1,"pid":0},{"ph":"X","name":"void SkCanvas::drawPaint(const SkPaint &)","ts":473,"dur":2.67e+03,"tid":1,"pid":0},{"ph":"X","name":"void skottie::Animation::seek(SkScalar)","ts":3.15e+03,"dur":2.25,"tid":1,"pid":0},{"ph":"X","name":"void skottie::Animation::render(SkCanvas *, const SkRect *, RenderFlags) const","ts":3.15e+03,"dur":216,"tid":1,"pid":0},{"ph":"X","name":"void SkCanvas::drawPath(const SkPath &, const SkPaint &)","ts":3.35e+03,"dur":15.1,"tid":1,"pid":0},{"ph":"X","name":"void skottie::Animation::seek(SkScalar)","ts":3.37e+03,"dur":1.17,"tid":1,"pid":0},{"ph":"X","name":"void skottie::Animation::render(SkCanvas *, const SkRect *, RenderFlags) const","ts":3.37e+03,"dur":140,"tid":1,"pid":0}]
351cb93a386Sopenharmony_ci"""
352cb93a386Sopenharmony_ci  parse_trace_json = {
353cb93a386Sopenharmony_ci      'frame_avg_us': 179.71,
354cb93a386Sopenharmony_ci      'frame_min_us': 141.17,
355cb93a386Sopenharmony_ci      'frame_max_us': 218.25
356cb93a386Sopenharmony_ci  }
357cb93a386Sopenharmony_ci
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_ci  skottie_cpu_buildername = ('Perf-Debian10-EMCC-GCE-CPU-AVX2-wasm-Release-All-'
360cb93a386Sopenharmony_ci                             'SkottieWASM')
361cb93a386Sopenharmony_ci  yield (
362cb93a386Sopenharmony_ci      api.test('skottie_wasm_perf') +
363cb93a386Sopenharmony_ci      api.properties(buildername=skottie_cpu_buildername,
364cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
365cb93a386Sopenharmony_ci                     revision='abc123',
366cb93a386Sopenharmony_ci                     path_config='kitchen',
367cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
368cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
369cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
370cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
371cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
372cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
373cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
374cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
375cb93a386Sopenharmony_ci  )
376cb93a386Sopenharmony_ci  yield (
377cb93a386Sopenharmony_ci      api.test('skottie_wasm_perf_trybot') +
378cb93a386Sopenharmony_ci      api.properties(buildername=skottie_cpu_buildername,
379cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
380cb93a386Sopenharmony_ci                     revision='abc123',
381cb93a386Sopenharmony_ci                     path_config='kitchen',
382cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
383cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]',
384cb93a386Sopenharmony_ci                     patch_ref='89/456789/12',
385cb93a386Sopenharmony_ci                     patch_repo='https://skia.googlesource.com/skia.git',
386cb93a386Sopenharmony_ci                     patch_storage='gerrit',
387cb93a386Sopenharmony_ci                     patch_set=7,
388cb93a386Sopenharmony_ci                     patch_issue=1234,
389cb93a386Sopenharmony_ci                     gerrit_project='skia',
390cb93a386Sopenharmony_ci                     gerrit_url='https://skia-review.googlesource.com/') +
391cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
392cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
393cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
394cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
395cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
396cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
397cb93a386Sopenharmony_ci  )
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci  skottie_gpu_buildername = ('Perf-Debian10-EMCC-NUC7i5BNK-GPU-IntelIris640-'
400cb93a386Sopenharmony_ci                             'wasm-Release-All-SkottieWASM')
401cb93a386Sopenharmony_ci  yield (
402cb93a386Sopenharmony_ci      api.test('skottie_wasm_perf_gpu') +
403cb93a386Sopenharmony_ci      api.properties(buildername=skottie_gpu_buildername,
404cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
405cb93a386Sopenharmony_ci                     revision='abc123',
406cb93a386Sopenharmony_ci                     path_config='kitchen',
407cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
408cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
409cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
410cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
411cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
412cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
413cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
414cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
415cb93a386Sopenharmony_ci  )
416cb93a386Sopenharmony_ci
417cb93a386Sopenharmony_ci  lottieweb_cpu_buildername = ('Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-'
418cb93a386Sopenharmony_ci                               'All-LottieWeb')
419cb93a386Sopenharmony_ci  yield (
420cb93a386Sopenharmony_ci      api.test('lottie_web_perf') +
421cb93a386Sopenharmony_ci      api.properties(buildername=lottieweb_cpu_buildername,
422cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
423cb93a386Sopenharmony_ci                     revision='abc123',
424cb93a386Sopenharmony_ci                     path_config='kitchen',
425cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
426cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
427cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
428cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
429cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
430cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
431cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
432cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
433cb93a386Sopenharmony_ci  )
434cb93a386Sopenharmony_ci  yield (
435cb93a386Sopenharmony_ci      api.test('lottie_web_perf_trybot') +
436cb93a386Sopenharmony_ci      api.properties(buildername=lottieweb_cpu_buildername,
437cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
438cb93a386Sopenharmony_ci                     revision='abc123',
439cb93a386Sopenharmony_ci                     path_config='kitchen',
440cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
441cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]',
442cb93a386Sopenharmony_ci                     patch_ref='89/456789/12',
443cb93a386Sopenharmony_ci                     patch_repo='https://skia.googlesource.com/skia.git',
444cb93a386Sopenharmony_ci                     patch_storage='gerrit',
445cb93a386Sopenharmony_ci                     patch_set=7,
446cb93a386Sopenharmony_ci                     patch_issue=1234,
447cb93a386Sopenharmony_ci                     gerrit_project='skia',
448cb93a386Sopenharmony_ci                     gerrit_url='https://skia-review.googlesource.com/') +
449cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
450cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
451cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
452cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
453cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
454cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
455cb93a386Sopenharmony_ci  )
456cb93a386Sopenharmony_ci
457cb93a386Sopenharmony_ci  lottieweb_canvas_cpu_buildername = (
458cb93a386Sopenharmony_ci      'Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-All-LottieWeb_Canvas')
459cb93a386Sopenharmony_ci  yield (
460cb93a386Sopenharmony_ci      api.test('lottie_web_canvas_perf') +
461cb93a386Sopenharmony_ci      api.properties(buildername=lottieweb_canvas_cpu_buildername,
462cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
463cb93a386Sopenharmony_ci                     revision='abc123',
464cb93a386Sopenharmony_ci                     path_config='kitchen',
465cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
466cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
467cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
468cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
469cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
470cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
471cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
472cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
473cb93a386Sopenharmony_ci  )
474cb93a386Sopenharmony_ci  yield (
475cb93a386Sopenharmony_ci      api.test('lottie_web_canvas_perf_trybot') +
476cb93a386Sopenharmony_ci      api.properties(buildername=lottieweb_canvas_cpu_buildername,
477cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
478cb93a386Sopenharmony_ci                     revision='abc123',
479cb93a386Sopenharmony_ci                     path_config='kitchen',
480cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
481cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]',
482cb93a386Sopenharmony_ci                     patch_ref='89/456789/12',
483cb93a386Sopenharmony_ci                     patch_repo='https://skia.googlesource.com/skia.git',
484cb93a386Sopenharmony_ci                     patch_storage='gerrit',
485cb93a386Sopenharmony_ci                     patch_set=7,
486cb93a386Sopenharmony_ci                     patch_issue=1234,
487cb93a386Sopenharmony_ci                     gerrit_project='skia',
488cb93a386Sopenharmony_ci                     gerrit_url='https://skia-review.googlesource.com/') +
489cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
490cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
491cb93a386Sopenharmony_ci      api.step_data('parse lottie2.json trace',
492cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
493cb93a386Sopenharmony_ci      api.step_data('parse lottie3.json trace',
494cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
495cb93a386Sopenharmony_ci  )
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci  unrecognized_buildername = ('Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-'
498cb93a386Sopenharmony_ci                              'All-Unrecognized')
499cb93a386Sopenharmony_ci  yield (
500cb93a386Sopenharmony_ci      api.test('unrecognized_builder') +
501cb93a386Sopenharmony_ci      api.properties(buildername=unrecognized_buildername,
502cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
503cb93a386Sopenharmony_ci                     revision='abc123',
504cb93a386Sopenharmony_ci                     path_config='kitchen',
505cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
506cb93a386Sopenharmony_ci      api.expect_exception('Exception')
507cb93a386Sopenharmony_ci  )
508