Flutter Engine
The Flutter Engine
perf_skottiewasm_lottieweb.py
Go to the documentation of this file.
1# Copyright 2019 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# Recipe which runs Skottie-WASM and Lottie-Web perf.
6
7import calendar
8import json
9import re
10
11PYTHON_VERSION_COMPATIBILITY = "PY3"
12
13# trim
14DEPS = [
15 'flavor',
16 'checkout',
17 'env',
18 'infra',
19 'recipe_engine/context',
20 'recipe_engine/file',
21 'recipe_engine/json',
22 'recipe_engine/path',
23 'recipe_engine/properties',
24 'recipe_engine/step',
25 'recipe_engine/time',
26 'run',
27 'vars',
28]
29
30LOTTIE_WEB_EXCLUDE = [
31 # See https://bugs.chromium.org/p/skia/issues/detail?id=9187#c4
32 'lottiefiles.com - Progress Success.json',
33 # Fails with "val2 is not defined".
34 'lottiefiles.com - VR.json',
35 'vr_animation.json',
36 # Times out.
37 'lottiefiles.com - Nudge.json',
38 'lottiefiles.com - Retweet.json',
39 # Trace file has majority main_frame_aborted terminations in it and < 25
40 # occurrences of submitted_frame + missed_frame.
41 # Static scenes (nothing animating)
42 'mask1.json',
43 'mask2.json',
44 'stacking.json',
45]
46
47SKOTTIE_WASM_EXCLUDE = [
48 # Trace file has majority main_frame_aborted terminations in it and < 25
49 # occurrences of submitted_frame + missed_frame.
50 # Below descriptions are added from fmalita@'s comments in
51 # https://skia-review.googlesource.com/c/skia/+/229419
52
53 # Static scenes (nothing animating)
54 'mask1.json',
55 'mask2.json',
56 'stacking.json',
57 # Static in Skottie only due to unsupported feature (expressions).
58 'dna.json',
59 'elephant_trunk_swing.json',
60 # Looks all static in both skottie/lottie, not sure why lottie doesn't abort
61 # as many frames.
62 'hexadots.json',
63 # Very short transition, mostly static.
64 'screenhole.json',
65 # Broken in Skottie due to unidentified missing feature.
66 'interleague_golf_logo.json',
67 'loading.json',
68 'lottiefiles.com - Loading 2.json',
69 'streetby_loading.json',
70 'streetby_test_loading.json',
71 # Times out
72 'beetle.json',
73 # Too slow? Doesn't provide enough frames for analysis b/325452373
74 'Name.json',
75]
76
77# These files work in SVG but not in Canvas.
78LOTTIE_WEB_CANVAS_EXCLUDE = LOTTIE_WEB_EXCLUDE + [
79 'Hello World.json',
80 'interactive_menu.json',
81 'Name.json',
82]
83
84
85def RunSteps(api):
86 api.vars.setup()
87 api.flavor.setup(None)
88 checkout_root = api.path.start_dir
89 buildername = api.properties['buildername']
90 node_path = api.path.start_dir.join('node', 'node', 'bin', 'node')
91 lottie_files = api.file.listdir(
92 'list lottie files', api.flavor.host_dirs.lotties_dir,
93 test_data=['lottie1.json', 'lottie2.json', 'lottie3.json', 'LICENSE'])
94
95 if 'SkottieWASM' in buildername:
96 source_type = 'skottie'
97 renderer = 'skottie-wasm'
98
99 perf_app_dir = checkout_root.join('skia', 'tools', 'skottie-wasm-perf')
100 canvaskit_js_path = api.vars.build_dir.join('canvaskit.js')
101 canvaskit_wasm_path = api.vars.build_dir.join('canvaskit.wasm')
102 skottie_wasm_js_path = perf_app_dir.join('skottie-wasm-perf.js')
103 perf_app_cmd = [
104 node_path, skottie_wasm_js_path,
105 '--canvaskit_js', canvaskit_js_path,
106 '--canvaskit_wasm', canvaskit_wasm_path,
107 ]
108 lottie_files = [x for x in lottie_files
109 if api.path.basename(x) not in SKOTTIE_WASM_EXCLUDE]
110 elif 'LottieWeb' in buildername:
111 source_type = 'lottie-web'
112 renderer = 'lottie-web'
113 if 'Canvas' in buildername:
114 backend = 'canvas'
115 lottie_files = [
116 x for x in lottie_files
117 if api.path.basename(x) not in LOTTIE_WEB_CANVAS_EXCLUDE]
118 else:
119 backend = 'svg'
120 lottie_files = [x for x in lottie_files
121 if api.path.basename(x) not in LOTTIE_WEB_EXCLUDE]
122
123 perf_app_dir = checkout_root.join('skia', 'tools', 'lottie-web-perf')
124 lottie_web_js_path = perf_app_dir.join('lottie-web-perf.js')
125 perf_app_cmd = [
126 node_path, lottie_web_js_path,
127 '--backend', backend,
128 ]
129 else:
130 raise Exception('Could not recognize the buildername %s' % buildername)
131
132 if api.vars.builder_cfg.get('cpu_or_gpu') == 'GPU':
133 perf_app_cmd.append('--use_gpu')
134
135 # Install prerequisites.
136 env_prefixes = {'PATH': [api.path.start_dir.join('node', 'node', 'bin')]}
137 with api.context(cwd=perf_app_dir, env_prefixes=env_prefixes):
138 api.step('npm install', cmd=['npm', 'install'])
139
140 perf_results = {}
141 output_dir = api.path.mkdtemp('g3_try')
142 # Run the perf_app_cmd on each lottie file and parse the trace files.
143 for _, lottie_file in enumerate(lottie_files):
144 lottie_filename = api.path.basename(lottie_file)
145 if not lottie_filename.endswith('.json'):
146 continue
147 output_file = output_dir.join(lottie_filename)
148 with api.context(cwd=perf_app_dir, env={'DISPLAY': ':0'}):
149 # This is occasionally flaky due to skbug.com/9207, adding retries.
150 attempts = 3
151 # Add output and input arguments to the cmd.
152 api.run.with_retry(api.step, 'Run perf cmd line app', attempts,
153 cmd=perf_app_cmd + [
154 '--input', lottie_file,
155 '--output', output_file,
156 ], infra_step=True)
157
158 perf_results[lottie_filename] = {
159 'gl': parse_trace(output_file, lottie_filename, api, renderer),
160 }
161
162 # Construct contents of the output JSON.
163 perf_json = {
164 'gitHash': api.properties['revision'],
165 'swarming_bot_id': api.vars.swarming_bot_id,
166 'swarming_task_id': api.vars.swarming_task_id,
167 'key': {
168 'bench_type': 'tracing',
169 'source_type': source_type,
170 },
171 'renderer': renderer,
172 'results': perf_results,
173 }
174 if api.vars.is_trybot:
175 perf_json['issue'] = api.vars.issue
176 perf_json['patchset'] = api.vars.patchset
177 perf_json['patch_storage'] = api.vars.patch_storage
178 # Add tokens from the builder name to the key.
179 reg = re.compile('Perf-(?P<os>[A-Za-z0-9_]+)-'
180 '(?P<compiler>[A-Za-z0-9_]+)-'
181 '(?P<model>[A-Za-z0-9_]+)-'
182 '(?P<cpu_or_gpu>[A-Z]+)-'
183 '(?P<cpu_or_gpu_value>[A-Za-z0-9_]+)-'
184 '(?P<arch>[A-Za-z0-9_]+)-'
185 '(?P<configuration>[A-Za-z0-9_]+)-'
186 'All(-(?P<extra_config>[A-Za-z0-9_]+)|)')
187 m = reg.match(api.properties['buildername'])
188 keys = ['os', 'compiler', 'model', 'cpu_or_gpu', 'cpu_or_gpu_value', 'arch',
189 'configuration', 'extra_config']
190 for k in keys:
191 perf_json['key'][k] = m.group(k)
192
193 # Create the output JSON file in perf_data_dir for the Upload task to upload.
194 api.file.ensure_directory(
195 'makedirs perf_dir',
196 api.flavor.host_dirs.perf_data_dir)
197 now = api.time.utcnow()
198 ts = int(calendar.timegm(now.utctimetuple()))
199 json_path = api.flavor.host_dirs.perf_data_dir.join(
200 'perf_%s_%d.json' % (api.properties['revision'], ts))
201 json_contents = json.dumps(
202 perf_json, indent=4, sort_keys=True, separators=(',', ': '))
203 api.file.write_text('write output JSON', json_path, json_contents)
204
205
206def parse_trace(trace_json, lottie_filename, api, renderer):
207 """parse_trace parses the specified trace JSON.
208
209 Parses the trace JSON and calculates the time of a single frame.
210 A dictionary is returned that has the following structure:
211 {
212 'frame_max_us': 100,
213 'frame_min_us': 90,
214 'frame_avg_us': 95,
215 }
216 """
217 script = api.infra.resource('parse_lottieweb_trace.py')
218 step_result = api.run(
219 api.step,
220 'parse %s trace' % lottie_filename,
221 cmd=['python3', script, trace_json, api.json.output(), renderer])
222
223 # Sanitize float outputs to 2 precision points.
224 output = dict(step_result.json.output)
225 output['frame_max_us'] = float("%.2f" % output['frame_max_us'])
226 output['frame_min_us'] = float("%.2f" % output['frame_min_us'])
227 output['frame_avg_us'] = float("%.2f" % output['frame_avg_us'])
228 return output
229
230
231def GenTests(api):
232 trace_output = """
233[{"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}]
234"""
235 parse_trace_json = {
236 'frame_avg_us': 179.71,
237 'frame_min_us': 141.17,
238 'frame_max_us': 218.25
239 }
240
241
242 skottie_cpu_buildername = ('Perf-Debian10-EMCC-GCE-CPU-AVX2-wasm-Release-All-'
243 'SkottieWASM')
244 yield (
245 api.test('skottie_wasm_perf') +
246 api.properties(buildername=skottie_cpu_buildername,
247 repository='https://skia.googlesource.com/skia.git',
248 revision='abc123',
249 path_config='kitchen',
250 trace_test_data=trace_output,
251 swarm_out_dir='[SWARM_OUT_DIR]') +
252 api.step_data('parse lottie1.json trace',
253 api.json.output(parse_trace_json)) +
254 api.step_data('parse lottie2.json trace',
255 api.json.output(parse_trace_json)) +
256 api.step_data('parse lottie3.json trace',
257 api.json.output(parse_trace_json))
258 )
259 yield (
260 api.test('skottie_wasm_perf_trybot') +
261 api.properties(buildername=skottie_cpu_buildername,
262 repository='https://skia.googlesource.com/skia.git',
263 revision='abc123',
264 path_config='kitchen',
265 trace_test_data=trace_output,
266 swarm_out_dir='[SWARM_OUT_DIR]',
267 patch_ref='89/456789/12',
268 patch_repo='https://skia.googlesource.com/skia.git',
269 patch_storage='gerrit',
270 patch_set=7,
271 patch_issue=1234,
272 gerrit_project='skia',
273 gerrit_url='https://skia-review.googlesource.com/') +
274 api.step_data('parse lottie1.json trace',
275 api.json.output(parse_trace_json)) +
276 api.step_data('parse lottie2.json trace',
277 api.json.output(parse_trace_json)) +
278 api.step_data('parse lottie3.json trace',
279 api.json.output(parse_trace_json))
280 )
281
282 skottie_gpu_buildername = ('Perf-Debian10-EMCC-NUC7i5BNK-GPU-IntelIris640-'
283 'wasm-Release-All-SkottieWASM')
284 yield (
285 api.test('skottie_wasm_perf_gpu') +
286 api.properties(buildername=skottie_gpu_buildername,
287 repository='https://skia.googlesource.com/skia.git',
288 revision='abc123',
289 path_config='kitchen',
290 trace_test_data=trace_output,
291 swarm_out_dir='[SWARM_OUT_DIR]') +
292 api.step_data('parse lottie1.json trace',
293 api.json.output(parse_trace_json)) +
294 api.step_data('parse lottie2.json trace',
295 api.json.output(parse_trace_json)) +
296 api.step_data('parse lottie3.json trace',
297 api.json.output(parse_trace_json))
298 )
299
300 lottieweb_cpu_buildername = ('Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-'
301 'All-LottieWeb')
302 yield (
303 api.test('lottie_web_perf') +
304 api.properties(buildername=lottieweb_cpu_buildername,
305 repository='https://skia.googlesource.com/skia.git',
306 revision='abc123',
307 path_config='kitchen',
308 trace_test_data=trace_output,
309 swarm_out_dir='[SWARM_OUT_DIR]') +
310 api.step_data('parse lottie1.json trace',
311 api.json.output(parse_trace_json)) +
312 api.step_data('parse lottie2.json trace',
313 api.json.output(parse_trace_json)) +
314 api.step_data('parse lottie3.json trace',
315 api.json.output(parse_trace_json))
316 )
317 yield (
318 api.test('lottie_web_perf_trybot') +
319 api.properties(buildername=lottieweb_cpu_buildername,
320 repository='https://skia.googlesource.com/skia.git',
321 revision='abc123',
322 path_config='kitchen',
323 trace_test_data=trace_output,
324 swarm_out_dir='[SWARM_OUT_DIR]',
325 patch_ref='89/456789/12',
326 patch_repo='https://skia.googlesource.com/skia.git',
327 patch_storage='gerrit',
328 patch_set=7,
329 patch_issue=1234,
330 gerrit_project='skia',
331 gerrit_url='https://skia-review.googlesource.com/') +
332 api.step_data('parse lottie1.json trace',
333 api.json.output(parse_trace_json)) +
334 api.step_data('parse lottie2.json trace',
335 api.json.output(parse_trace_json)) +
336 api.step_data('parse lottie3.json trace',
337 api.json.output(parse_trace_json))
338 )
339
340 lottieweb_canvas_cpu_buildername = (
341 'Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-All-LottieWeb_Canvas')
342 yield (
343 api.test('lottie_web_canvas_perf') +
344 api.properties(buildername=lottieweb_canvas_cpu_buildername,
345 repository='https://skia.googlesource.com/skia.git',
346 revision='abc123',
347 path_config='kitchen',
348 trace_test_data=trace_output,
349 swarm_out_dir='[SWARM_OUT_DIR]') +
350 api.step_data('parse lottie1.json trace',
351 api.json.output(parse_trace_json)) +
352 api.step_data('parse lottie2.json trace',
353 api.json.output(parse_trace_json)) +
354 api.step_data('parse lottie3.json trace',
355 api.json.output(parse_trace_json))
356 )
357 yield (
358 api.test('lottie_web_canvas_perf_trybot') +
359 api.properties(buildername=lottieweb_canvas_cpu_buildername,
360 repository='https://skia.googlesource.com/skia.git',
361 revision='abc123',
362 path_config='kitchen',
363 trace_test_data=trace_output,
364 swarm_out_dir='[SWARM_OUT_DIR]',
365 patch_ref='89/456789/12',
366 patch_repo='https://skia.googlesource.com/skia.git',
367 patch_storage='gerrit',
368 patch_set=7,
369 patch_issue=1234,
370 gerrit_project='skia',
371 gerrit_url='https://skia-review.googlesource.com/') +
372 api.step_data('parse lottie1.json trace',
373 api.json.output(parse_trace_json)) +
374 api.step_data('parse lottie2.json trace',
375 api.json.output(parse_trace_json)) +
376 api.step_data('parse lottie3.json trace',
377 api.json.output(parse_trace_json))
378 )
379
380 unrecognized_buildername = ('Perf-Debian10-none-GCE-CPU-AVX2-x86_64-Release-'
381 'All-Unrecognized')
382 yield (
383 api.test('unrecognized_builder') +
384 api.properties(buildername=unrecognized_buildername,
385 repository='https://skia.googlesource.com/skia.git',
386 revision='abc123',
387 path_config='kitchen',
388 swarm_out_dir='[SWARM_OUT_DIR]') +
389 api.expect_exception('Exception')
390 )
def GenTests(api)
Definition: full.py:111
def RunSteps(api)
Definition: full.py:18
def parse_trace(trace_json, lottie_filename, api)