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