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 DM with trace flag on lottie files and then parses the
6cb93a386Sopenharmony_ci# trace output into output JSON files to ingest to perf.skia.org.
7cb93a386Sopenharmony_ci# Design doc: go/skottie-tracing
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ciimport calendar
11cb93a386Sopenharmony_ciimport json
12cb93a386Sopenharmony_ciimport re
13cb93a386Sopenharmony_ciimport string
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciPYTHON_VERSION_COMPATIBILITY = "PY2+3"
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciDEPS = [
18cb93a386Sopenharmony_ci  'flavor',
19cb93a386Sopenharmony_ci  'recipe_engine/context',
20cb93a386Sopenharmony_ci  'recipe_engine/file',
21cb93a386Sopenharmony_ci  'recipe_engine/json',
22cb93a386Sopenharmony_ci  'recipe_engine/path',
23cb93a386Sopenharmony_ci  'recipe_engine/step',
24cb93a386Sopenharmony_ci  'recipe_engine/time',
25cb93a386Sopenharmony_ci  'recipe_engine/properties',
26cb93a386Sopenharmony_ci  'recipe_engine/python',
27cb93a386Sopenharmony_ci  'recipe_engine/raw_io',
28cb93a386Sopenharmony_ci  'run',
29cb93a386Sopenharmony_ci  'vars',
30cb93a386Sopenharmony_ci]
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ciSEEK_TRACE_NAME = 'skottie::Animation::seek'
33cb93a386Sopenharmony_ciRENDER_TRACE_NAME = 'skottie::Animation::render'
34cb93a386Sopenharmony_ciEXPECTED_DM_FRAMES = 25
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_cidef perf_steps(api):
38cb93a386Sopenharmony_ci  """Run DM on lottie files with tracing turned on and then parse the output."""
39cb93a386Sopenharmony_ci  api.flavor.create_clean_device_dir(
40cb93a386Sopenharmony_ci        api.flavor.device_dirs.dm_dir)
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci  lottie_files = api.file.listdir(
43cb93a386Sopenharmony_ci      'list lottie files', api.flavor.host_dirs.lotties_dir,
44cb93a386Sopenharmony_ci      test_data=['lottie1.json', 'lottie(test)\'!2.json', 'lottie 3!.json',
45cb93a386Sopenharmony_ci                 'LICENSE'])
46cb93a386Sopenharmony_ci  perf_results = {}
47cb93a386Sopenharmony_ci  # Run DM on each lottie file and parse the trace files.
48cb93a386Sopenharmony_ci  for idx, lottie_file in enumerate(lottie_files):
49cb93a386Sopenharmony_ci    lottie_filename = api.path.basename(lottie_file)
50cb93a386Sopenharmony_ci    if not lottie_filename.endswith('.json'):
51cb93a386Sopenharmony_ci      continue
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ci    trace_output_path = api.flavor.device_path_join(
54cb93a386Sopenharmony_ci        api.flavor.device_dirs.dm_dir, '%s.json' % (idx + 1))
55cb93a386Sopenharmony_ci    # See go/skottie-tracing for how these flags were selected.
56cb93a386Sopenharmony_ci    dm_args = [
57cb93a386Sopenharmony_ci      'dm',
58cb93a386Sopenharmony_ci      '--resourcePath', api.flavor.device_dirs.resource_dir,
59cb93a386Sopenharmony_ci      '--lotties', api.flavor.device_dirs.lotties_dir,
60cb93a386Sopenharmony_ci      '--src', 'lottie',
61cb93a386Sopenharmony_ci      '--nonativeFonts',
62cb93a386Sopenharmony_ci      '--verbose',
63cb93a386Sopenharmony_ci      '--traceMatch', 'skottie',  # recipe can OOM without this.
64cb93a386Sopenharmony_ci      '--trace', trace_output_path,
65cb93a386Sopenharmony_ci      '--match', get_trace_match(
66cb93a386Sopenharmony_ci          lottie_filename, 'Android' in api.properties['buildername']),
67cb93a386Sopenharmony_ci    ]
68cb93a386Sopenharmony_ci    if api.vars.builder_cfg.get('cpu_or_gpu') == 'GPU':
69cb93a386Sopenharmony_ci      dm_args.extend(['--config', 'gles', '--nocpu'])
70cb93a386Sopenharmony_ci    elif api.vars.builder_cfg.get('cpu_or_gpu') == 'CPU':
71cb93a386Sopenharmony_ci      dm_args.extend(['--config', '8888', '--nogpu'])
72cb93a386Sopenharmony_ci    api.run(api.flavor.step, 'dm', cmd=dm_args, abort_on_failure=False)
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    trace_test_data = api.properties.get('trace_test_data', '{}')
75cb93a386Sopenharmony_ci    trace_file_content = api.flavor.read_file_on_device(trace_output_path)
76cb93a386Sopenharmony_ci    if not trace_file_content and trace_test_data:
77cb93a386Sopenharmony_ci      trace_file_content = trace_test_data
78cb93a386Sopenharmony_ci
79cb93a386Sopenharmony_ci    perf_results[lottie_filename] = {
80cb93a386Sopenharmony_ci        'gles': parse_trace(trace_file_content, lottie_filename, api),
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci    api.flavor.remove_file_on_device(trace_output_path)
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci  # Construct contents of the output JSON.
85cb93a386Sopenharmony_ci  perf_json = {
86cb93a386Sopenharmony_ci      'gitHash': api.properties['revision'],
87cb93a386Sopenharmony_ci      'swarming_bot_id': api.vars.swarming_bot_id,
88cb93a386Sopenharmony_ci      'swarming_task_id': api.vars.swarming_task_id,
89cb93a386Sopenharmony_ci      'renderer': 'skottie',
90cb93a386Sopenharmony_ci      'key': {
91cb93a386Sopenharmony_ci        'bench_type': 'tracing',
92cb93a386Sopenharmony_ci        'source_type': 'skottie',
93cb93a386Sopenharmony_ci      },
94cb93a386Sopenharmony_ci      'results': perf_results,
95cb93a386Sopenharmony_ci  }
96cb93a386Sopenharmony_ci  if api.vars.is_trybot:
97cb93a386Sopenharmony_ci    perf_json['issue'] = api.vars.issue
98cb93a386Sopenharmony_ci    perf_json['patchset'] = api.vars.patchset
99cb93a386Sopenharmony_ci    perf_json['patch_storage'] = api.vars.patch_storage
100cb93a386Sopenharmony_ci  # Add tokens from the builder name to the key.
101cb93a386Sopenharmony_ci  reg = re.compile('Perf-(?P<os>[A-Za-z0-9_]+)-'
102cb93a386Sopenharmony_ci                   '(?P<compiler>[A-Za-z0-9_]+)-'
103cb93a386Sopenharmony_ci                   '(?P<model>[A-Za-z0-9_]+)-'
104cb93a386Sopenharmony_ci                   '(?P<cpu_or_gpu>[A-Z]+)-'
105cb93a386Sopenharmony_ci                   '(?P<cpu_or_gpu_value>[A-Za-z0-9_]+)-'
106cb93a386Sopenharmony_ci                   '(?P<arch>[A-Za-z0-9_]+)-'
107cb93a386Sopenharmony_ci                   '(?P<configuration>[A-Za-z0-9_]+)-'
108cb93a386Sopenharmony_ci                   'All(-(?P<extra_config>[A-Za-z0-9_]+)|)')
109cb93a386Sopenharmony_ci  m = reg.match(api.properties['buildername'])
110cb93a386Sopenharmony_ci  keys = ['os', 'compiler', 'model', 'cpu_or_gpu', 'cpu_or_gpu_value', 'arch',
111cb93a386Sopenharmony_ci          'configuration', 'extra_config']
112cb93a386Sopenharmony_ci  for k in keys:
113cb93a386Sopenharmony_ci    perf_json['key'][k] = m.group(k)
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci  # Create the output JSON file in perf_data_dir for the Upload task to upload.
116cb93a386Sopenharmony_ci  api.file.ensure_directory(
117cb93a386Sopenharmony_ci      'makedirs perf_dir',
118cb93a386Sopenharmony_ci      api.flavor.host_dirs.perf_data_dir)
119cb93a386Sopenharmony_ci  now = api.time.utcnow()
120cb93a386Sopenharmony_ci  ts = int(calendar.timegm(now.utctimetuple()))
121cb93a386Sopenharmony_ci  json_path = api.flavor.host_dirs.perf_data_dir.join(
122cb93a386Sopenharmony_ci      'perf_%s_%d.json' % (api.properties['revision'], ts))
123cb93a386Sopenharmony_ci  json_contents = json.dumps(
124cb93a386Sopenharmony_ci      perf_json, indent=4, sort_keys=True, separators=(',', ': '))
125cb93a386Sopenharmony_ci  api.file.write_text('write output JSON', json_path, json_contents)
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_cidef get_trace_match(lottie_filename, is_android):
129cb93a386Sopenharmony_ci  """Returns the DM regex to match the specified lottie file name."""
130cb93a386Sopenharmony_ci  trace_match = '^%s$' % lottie_filename
131cb93a386Sopenharmony_ci  if is_android and ' ' not in trace_match:
132cb93a386Sopenharmony_ci    # Punctuation characters confuse DM when shelled out over adb, so escape
133cb93a386Sopenharmony_ci    # them. Do not need to do this when there is a space in the match because
134cb93a386Sopenharmony_ci    # subprocess.list2cmdline automatically adds quotes in that case.
135cb93a386Sopenharmony_ci    for sp_char in string.punctuation:
136cb93a386Sopenharmony_ci      if sp_char == '\\':
137cb93a386Sopenharmony_ci        # No need to escape the escape char.
138cb93a386Sopenharmony_ci        continue
139cb93a386Sopenharmony_ci      trace_match = trace_match.replace(sp_char, '\%s' % sp_char)
140cb93a386Sopenharmony_ci  return trace_match
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_cidef parse_trace(trace_json, lottie_filename, api):
144cb93a386Sopenharmony_ci  """parse_trace parses the specified trace JSON.
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci  Parses the trace JSON and calculates the time of a single frame. Frame time is
147cb93a386Sopenharmony_ci  considered the same as seek time + render time.
148cb93a386Sopenharmony_ci  Note: The first seek is ignored because it is a constructor call.
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ci  A dictionary is returned that has the following structure:
151cb93a386Sopenharmony_ci  {
152cb93a386Sopenharmony_ci    'frame_max_us': 100,
153cb93a386Sopenharmony_ci    'frame_min_us': 90,
154cb93a386Sopenharmony_ci    'frame_avg_us': 95,
155cb93a386Sopenharmony_ci  }
156cb93a386Sopenharmony_ci  """
157cb93a386Sopenharmony_ci  step_result = api.run(
158cb93a386Sopenharmony_ci      api.python.inline,
159cb93a386Sopenharmony_ci      'parse %s trace' % lottie_filename,
160cb93a386Sopenharmony_ci      program="""
161cb93a386Sopenharmony_ci  import json
162cb93a386Sopenharmony_ci  import sys
163cb93a386Sopenharmony_ci
164cb93a386Sopenharmony_ci  trace_output = sys.argv[1]
165cb93a386Sopenharmony_ci  trace_json = json.loads(trace_output)
166cb93a386Sopenharmony_ci  lottie_filename = sys.argv[2]
167cb93a386Sopenharmony_ci  output_json_file = sys.argv[3]
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci  perf_results = {}
170cb93a386Sopenharmony_ci  frame_max = 0
171cb93a386Sopenharmony_ci  frame_min = 0
172cb93a386Sopenharmony_ci  frame_cumulative = 0
173cb93a386Sopenharmony_ci  current_frame_duration = 0
174cb93a386Sopenharmony_ci  total_frames = 0
175cb93a386Sopenharmony_ci  frame_start = False
176cb93a386Sopenharmony_ci  for trace in trace_json:
177cb93a386Sopenharmony_ci    if '%s' in trace['name']:
178cb93a386Sopenharmony_ci      if frame_start:
179cb93a386Sopenharmony_ci        raise Exception('We got consecutive Animation::seek without a ' +
180cb93a386Sopenharmony_ci                        'render. Something is wrong.')
181cb93a386Sopenharmony_ci      frame_start = True
182cb93a386Sopenharmony_ci      current_frame_duration = trace['dur']
183cb93a386Sopenharmony_ci    elif '%s' in trace['name']:
184cb93a386Sopenharmony_ci      if not frame_start:
185cb93a386Sopenharmony_ci        raise Exception('We got an Animation::render without a seek first. ' +
186cb93a386Sopenharmony_ci                        'Something is wrong.')
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci      current_frame_duration += trace['dur']
189cb93a386Sopenharmony_ci      frame_start = False
190cb93a386Sopenharmony_ci      total_frames += 1
191cb93a386Sopenharmony_ci      frame_max = max(frame_max, current_frame_duration)
192cb93a386Sopenharmony_ci      frame_min = (min(frame_min, current_frame_duration)
193cb93a386Sopenharmony_ci                   if frame_min else current_frame_duration)
194cb93a386Sopenharmony_ci      frame_cumulative += current_frame_duration
195cb93a386Sopenharmony_ci
196cb93a386Sopenharmony_ci  expected_dm_frames = %d
197cb93a386Sopenharmony_ci  if total_frames != expected_dm_frames:
198cb93a386Sopenharmony_ci    raise Exception(
199cb93a386Sopenharmony_ci        'Got ' + str(total_frames) + ' frames instead of ' +
200cb93a386Sopenharmony_ci        str(expected_dm_frames))
201cb93a386Sopenharmony_ci  perf_results['frame_max_us'] = frame_max
202cb93a386Sopenharmony_ci  perf_results['frame_min_us'] = frame_min
203cb93a386Sopenharmony_ci  perf_results['frame_avg_us'] = frame_cumulative/total_frames
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ci  # Write perf_results to the output json.
206cb93a386Sopenharmony_ci  with open(output_json_file, 'w') as f:
207cb93a386Sopenharmony_ci    f.write(json.dumps(perf_results))
208cb93a386Sopenharmony_ci  """ % (SEEK_TRACE_NAME, RENDER_TRACE_NAME, EXPECTED_DM_FRAMES),
209cb93a386Sopenharmony_ci  args=[trace_json, lottie_filename, api.json.output()])
210cb93a386Sopenharmony_ci
211cb93a386Sopenharmony_ci  # Sanitize float outputs to 2 precision points.
212cb93a386Sopenharmony_ci  output = dict(step_result.json.output)
213cb93a386Sopenharmony_ci  output['frame_max_us'] = float("%.2f" % output['frame_max_us'])
214cb93a386Sopenharmony_ci  output['frame_min_us'] = float("%.2f" % output['frame_min_us'])
215cb93a386Sopenharmony_ci  output['frame_avg_us'] = float("%.2f" % output['frame_avg_us'])
216cb93a386Sopenharmony_ci  return output
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_cidef RunSteps(api):
220cb93a386Sopenharmony_ci  api.vars.setup()
221cb93a386Sopenharmony_ci  api.file.ensure_directory('makedirs tmp_dir', api.vars.tmp_dir)
222cb93a386Sopenharmony_ci  api.flavor.setup('dm')
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci  with api.context():
225cb93a386Sopenharmony_ci    try:
226cb93a386Sopenharmony_ci      api.flavor.install(resources=True, lotties=True)
227cb93a386Sopenharmony_ci      perf_steps(api)
228cb93a386Sopenharmony_ci    finally:
229cb93a386Sopenharmony_ci      api.flavor.cleanup_steps()
230cb93a386Sopenharmony_ci    api.run.check_failure()
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_cidef GenTests(api):
234cb93a386Sopenharmony_ci  trace_output = """
235cb93a386Sopenharmony_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}]
236cb93a386Sopenharmony_ci"""
237cb93a386Sopenharmony_ci  dm_json_test_data = """
238cb93a386Sopenharmony_ci{
239cb93a386Sopenharmony_ci  "gitHash": "bac53f089dbc473862bc5a2e328ba7600e0ed9c4",
240cb93a386Sopenharmony_ci  "swarming_bot_id": "skia-rpi-094",
241cb93a386Sopenharmony_ci  "swarming_task_id": "438f11c0e19eab11",
242cb93a386Sopenharmony_ci  "key": {
243cb93a386Sopenharmony_ci    "arch": "arm",
244cb93a386Sopenharmony_ci    "compiler": "Clang",
245cb93a386Sopenharmony_ci    "cpu_or_gpu": "GPU",
246cb93a386Sopenharmony_ci    "cpu_or_gpu_value": "Mali400MP2",
247cb93a386Sopenharmony_ci    "extra_config": "Android",
248cb93a386Sopenharmony_ci    "model": "AndroidOne",
249cb93a386Sopenharmony_ci    "os": "Android"
250cb93a386Sopenharmony_ci   },
251cb93a386Sopenharmony_ci   "results": {
252cb93a386Sopenharmony_ci   }
253cb93a386Sopenharmony_ci}
254cb93a386Sopenharmony_ci"""
255cb93a386Sopenharmony_ci  parse_trace_json = {
256cb93a386Sopenharmony_ci      'frame_avg_us': 179.71,
257cb93a386Sopenharmony_ci      'frame_min_us': 141.17,
258cb93a386Sopenharmony_ci      'frame_max_us': 218.25
259cb93a386Sopenharmony_ci  }
260cb93a386Sopenharmony_ci  android_buildername = ('Perf-Android-Clang-AndroidOne-GPU-Mali400MP2-arm-'
261cb93a386Sopenharmony_ci                         'Release-All-Android_SkottieTracing')
262cb93a386Sopenharmony_ci  gpu_buildername = ('Perf-Debian10-Clang-NUC7i5BNK-GPU-IntelIris640-x86_64-'
263cb93a386Sopenharmony_ci                     'Release-All-SkottieTracing')
264cb93a386Sopenharmony_ci  cpu_buildername = ('Perf-Debian10-Clang-GCE-CPU-AVX2-x86_64-Release-All-'
265cb93a386Sopenharmony_ci                     'SkottieTracing')
266cb93a386Sopenharmony_ci  yield (
267cb93a386Sopenharmony_ci      api.test(android_buildername) +
268cb93a386Sopenharmony_ci      api.properties(buildername=android_buildername,
269cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
270cb93a386Sopenharmony_ci                     revision='abc123',
271cb93a386Sopenharmony_ci                     task_id='abc123',
272cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
273cb93a386Sopenharmony_ci                     dm_json_test_data=dm_json_test_data,
274cb93a386Sopenharmony_ci                     path_config='kitchen',
275cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
276cb93a386Sopenharmony_ci      api.step_data('parse lottie(test)\'!2.json trace',
277cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
278cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
279cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
280cb93a386Sopenharmony_ci      api.step_data('parse lottie 3!.json trace',
281cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
282cb93a386Sopenharmony_ci  )
283cb93a386Sopenharmony_ci  yield (
284cb93a386Sopenharmony_ci      api.test(gpu_buildername) +
285cb93a386Sopenharmony_ci      api.properties(buildername=gpu_buildername,
286cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
287cb93a386Sopenharmony_ci                     revision='abc123',
288cb93a386Sopenharmony_ci                     task_id='abc123',
289cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
290cb93a386Sopenharmony_ci                     dm_json_test_data=dm_json_test_data,
291cb93a386Sopenharmony_ci                     path_config='kitchen',
292cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
293cb93a386Sopenharmony_ci      api.step_data('parse lottie(test)\'!2.json trace',
294cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
295cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
296cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
297cb93a386Sopenharmony_ci      api.step_data('parse lottie 3!.json trace',
298cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
299cb93a386Sopenharmony_ci  )
300cb93a386Sopenharmony_ci  yield (
301cb93a386Sopenharmony_ci      api.test(cpu_buildername) +
302cb93a386Sopenharmony_ci      api.properties(buildername=cpu_buildername,
303cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
304cb93a386Sopenharmony_ci                     revision='abc123',
305cb93a386Sopenharmony_ci                     task_id='abc123',
306cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
307cb93a386Sopenharmony_ci                     dm_json_test_data=dm_json_test_data,
308cb93a386Sopenharmony_ci                     path_config='kitchen',
309cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
310cb93a386Sopenharmony_ci      api.step_data('parse lottie(test)\'!2.json trace',
311cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
312cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
313cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
314cb93a386Sopenharmony_ci      api.step_data('parse lottie 3!.json trace',
315cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
316cb93a386Sopenharmony_ci  )
317cb93a386Sopenharmony_ci  yield (
318cb93a386Sopenharmony_ci      api.test('skottietracing_parse_trace_error') +
319cb93a386Sopenharmony_ci      api.properties(buildername=android_buildername,
320cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
321cb93a386Sopenharmony_ci                     revision='abc123',
322cb93a386Sopenharmony_ci                     task_id='abc123',
323cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
324cb93a386Sopenharmony_ci                     dm_json_test_data=dm_json_test_data,
325cb93a386Sopenharmony_ci                     path_config='kitchen',
326cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]') +
327cb93a386Sopenharmony_ci      api.step_data('parse lottie 3!.json trace',
328cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json), retcode=1)
329cb93a386Sopenharmony_ci  )
330cb93a386Sopenharmony_ci  yield (
331cb93a386Sopenharmony_ci      api.test('skottietracing_trybot') +
332cb93a386Sopenharmony_ci      api.properties(buildername=android_buildername,
333cb93a386Sopenharmony_ci                     repository='https://skia.googlesource.com/skia.git',
334cb93a386Sopenharmony_ci                     revision='abc123',
335cb93a386Sopenharmony_ci                     task_id='abc123',
336cb93a386Sopenharmony_ci                     trace_test_data=trace_output,
337cb93a386Sopenharmony_ci                     dm_json_test_data=dm_json_test_data,
338cb93a386Sopenharmony_ci                     path_config='kitchen',
339cb93a386Sopenharmony_ci                     swarm_out_dir='[SWARM_OUT_DIR]',
340cb93a386Sopenharmony_ci                     patch_ref='89/456789/12',
341cb93a386Sopenharmony_ci                     patch_repo='https://skia.googlesource.com/skia.git',
342cb93a386Sopenharmony_ci                     patch_storage='gerrit',
343cb93a386Sopenharmony_ci                     patch_set=7,
344cb93a386Sopenharmony_ci                     patch_issue=1234,
345cb93a386Sopenharmony_ci                     gerrit_project='skia',
346cb93a386Sopenharmony_ci                     gerrit_url='https://skia-review.googlesource.com/') +
347cb93a386Sopenharmony_ci      api.step_data('parse lottie(test)\'!2.json trace',
348cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
349cb93a386Sopenharmony_ci      api.step_data('parse lottie1.json trace',
350cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json)) +
351cb93a386Sopenharmony_ci      api.step_data('parse lottie 3!.json trace',
352cb93a386Sopenharmony_ci                    api.json.output(parse_trace_json))
353cb93a386Sopenharmony_ci  )
354