1# Copyright 2018 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 analyzes a compiled binary for information (e.g. file size) 6 7DEPS = [ 8 'checkout', 9 'env', 10 'recipe_engine/context', 11 'recipe_engine/file', 12 'recipe_engine/path', 13 'recipe_engine/properties', 14 'recipe_engine/python', 15 'recipe_engine/raw_io', 16 'recipe_engine/step', 17 'run', 18 'vars', 19] 20 21def RunSteps(api): 22 api.vars.setup() 23 24 checkout_root = api.checkout.default_checkout_root 25 api.checkout.bot_update(checkout_root=checkout_root) 26 27 out_dir = api.vars.swarming_out_dir 28 # Any binaries to scan should be here. 29 bin_dir = api.vars.build_dir 30 31 api.file.ensure_directory('mkdirs out_dir', out_dir, mode=0777) 32 33 analyzed = 0 34 with api.context(cwd=bin_dir): 35 files = api.file.glob_paths( 36 'find WASM binaries', 37 bin_dir, 38 '*.wasm', 39 test_data=['pathkit.wasm']) 40 analyzed += len(files) 41 if files: 42 analyze_wasm_file(api, checkout_root, out_dir, files) 43 44 files = api.file.glob_paths( 45 'find JS files', 46 bin_dir, 47 '*.js', 48 test_data=['pathkit.js']) 49 analyzed += len(files) 50 if files: 51 analyze_web_file(api, checkout_root, out_dir, files) 52 53 files = api.file.glob_paths( 54 'find JS mem files', 55 bin_dir, 56 '*.js.mem', 57 test_data=['pathkit.js.mem']) 58 analyzed += len(files) 59 if files: 60 analyze_web_file(api, checkout_root, out_dir, files) 61 62 files = api.file.glob_paths( 63 'find flutter library', 64 bin_dir, 65 'libflutter.so', 66 test_data=['libflutter.so']) 67 analyzed += len(files) 68 if files: 69 analyze_flutter_lib(api, checkout_root, out_dir, files) 70 71 files = api.file.glob_paths( 72 'find skia library', 73 bin_dir, 74 'libskia.so', 75 test_data=['libskia.so']) 76 analyzed += len(files) 77 if files: 78 analyze_cpp_lib(api, checkout_root, out_dir, files) 79 80 files = api.file.glob_paths( 81 'find skottie_tool', 82 bin_dir, 83 'skottie_tool', 84 test_data=['skottie_tool']) 85 analyzed += len(files) 86 if files: 87 make_treemap(api, checkout_root, out_dir, files) 88 89 if not analyzed: # pragma: nocover 90 raise Exception('No files were analyzed!') 91 92 93def keys_and_props(api): 94 keys = [] 95 keys_blacklist = ['role'] 96 for k in sorted(api.vars.builder_cfg.keys()): 97 if not k in keys_blacklist: 98 keys.extend([k, api.vars.builder_cfg[k]]) 99 keystr = ' '.join(keys) 100 101 props = [ 102 'gitHash', api.properties['revision'], 103 'swarming_bot_id', api.vars.swarming_bot_id, 104 'swarming_task_id', api.vars.swarming_task_id, 105 ] 106 107 if api.vars.is_trybot: 108 props.extend([ 109 'issue', str(api.vars.issue), 110 'patchset', str(api.vars.patchset), 111 'patch_storage', api.vars.patch_storage, 112 ]) 113 propstr = ' '.join(props) 114 return (keystr, propstr) 115 116 117# Get the raw and gzipped size of the given file 118def analyze_web_file(api, checkout_root, out_dir, files): 119 (keystr, propstr) = keys_and_props(api) 120 121 for f in files: 122 skia_dir = checkout_root.join('skia') 123 with api.context(cwd=skia_dir): 124 script = skia_dir.join('infra', 'bots', 'buildstats', 125 'buildstats_web.py') 126 api.run(api.python, 'Analyze %s' % f, script=script, 127 args=[f, out_dir, keystr, propstr]) 128 129 130# Get the raw size and a few metrics from bloaty 131def analyze_cpp_lib(api, checkout_root, out_dir, files): 132 (keystr, propstr) = keys_and_props(api) 133 bloaty_exe = api.path['start_dir'].join('bloaty', 'bloaty') 134 135 for f in files: 136 skia_dir = checkout_root.join('skia') 137 with api.context(cwd=skia_dir): 138 script = skia_dir.join('infra', 'bots', 'buildstats', 139 'buildstats_cpp.py') 140 api.run(api.python, 'Analyze %s' % f, script=script, 141 args=[f, out_dir, keystr, propstr, bloaty_exe]) 142 143 144# Get the size of skia in flutter and a few metrics from bloaty 145def analyze_flutter_lib(api, checkout_root, out_dir, files): 146 (keystr, propstr) = keys_and_props(api) 147 bloaty_exe = api.path['start_dir'].join('bloaty', 'bloaty') 148 149 for f in files: 150 151 skia_dir = checkout_root.join('skia') 152 with api.context(cwd=skia_dir): 153 stripped = api.vars.build_dir.join('libflutter_stripped.so') 154 script = skia_dir.join('infra', 'bots', 'buildstats', 155 'buildstats_flutter.py') 156 step_data = api.run(api.python, 'Analyze flutter', script=script, 157 args=[stripped, out_dir, keystr, propstr, bloaty_exe, 158 f], 159 stdout=api.raw_io.output()) 160 if step_data and step_data.stdout: 161 magic_seperator = '#$%^&*' 162 sections = step_data.stdout.split(magic_seperator) 163 result = api.step.active_result 164 logs = result.presentation.logs 165 # Skip section 0 because it's everything before first print, 166 # which is probably the empty string. 167 logs['bloaty_file_symbol_short'] = sections[1].split('\n') 168 logs['bloaty_file_symbol_full'] = sections[2].split('\n') 169 logs['bloaty_symbol_file_short'] = sections[3].split('\n') 170 logs['bloaty_symbol_file_full'] = sections[4].split('\n') 171 logs['perf_json'] = sections[5].split('\n') 172 173 174# Get the size of skia in flutter and a few metrics from bloaty 175def analyze_wasm_file(api, checkout_root, out_dir, files): 176 (keystr, propstr) = keys_and_props(api) 177 bloaty_exe = api.path['start_dir'].join('bloaty', 'bloaty') 178 179 for f in files: 180 181 skia_dir = checkout_root.join('skia') 182 with api.context(cwd=skia_dir): 183 script = skia_dir.join('infra', 'bots', 'buildstats', 184 'buildstats_wasm.py') 185 step_data = api.run(api.python, 'Analyze wasm', script=script, 186 args=[f, out_dir, keystr, propstr, bloaty_exe], 187 stdout=api.raw_io.output()) 188 if step_data and step_data.stdout: 189 magic_seperator = '#$%^&*' 190 sections = step_data.stdout.split(magic_seperator) 191 result = api.step.active_result 192 logs = result.presentation.logs 193 # Skip section 0 because it's everything before first print, 194 # which is probably the empty string. 195 logs['bloaty_symbol_short'] = sections[1].split('\n') 196 logs['bloaty_symbol_full'] = sections[2].split('\n') 197 logs['perf_json'] = sections[3].split('\n') 198 199 200# make a zip file containing an HTML treemap of the files 201def make_treemap(api, checkout_root, out_dir, files): 202 for f in files: 203 env = {'DOCKER_CONFIG': '/home/chrome-bot/.docker'} 204 with api.env(env): 205 skia_dir = checkout_root.join('skia') 206 with api.context(cwd=skia_dir): 207 script = skia_dir.join('infra', 'bots', 'buildstats', 208 'make_treemap.py') 209 api.run(api.python, 'Make code size treemap', 210 script=script, 211 args=[f, out_dir], 212 stdout=api.raw_io.output()) 213 214 215def GenTests(api): 216 builder = 'BuildStats-Debian9-EMCC-wasm-Release-PathKit' 217 yield ( 218 api.test('normal_bot') + 219 api.properties(buildername=builder, 220 repository='https://skia.googlesource.com/skia.git', 221 revision='abc123', 222 swarm_out_dir='[SWARM_OUT_DIR]', 223 path_config='kitchen') + 224 api.step_data('get swarming bot id', 225 stdout=api.raw_io.output('skia-bot-123')) + 226 api.step_data('get swarming task id', 227 stdout=api.raw_io.output('123456abc')) + 228 api.step_data('Analyze wasm', 229 stdout=api.raw_io.output(sample_wasm)) + 230 api.step_data('Analyze flutter', 231 stdout=api.raw_io.output(sample_flutter)) 232 ) 233 234 yield ( 235 api.test('trybot') + 236 api.properties(buildername=builder, 237 repository='https://skia.googlesource.com/skia.git', 238 revision='abc123', 239 swarm_out_dir='[SWARM_OUT_DIR]', 240 patch_repo='https://skia.googlesource.com/skia.git', 241 path_config='kitchen') + 242 api.step_data('get swarming bot id', 243 stdout=api.raw_io.output('skia-bot-123')) + 244 api.step_data('get swarming task id', 245 stdout=api.raw_io.output('123456abc')) + 246 api.properties(patch_storage='gerrit') + 247 api.properties.tryserver( 248 buildername=builder, 249 gerrit_project='skia', 250 gerrit_url='https://skia-review.googlesource.com/', 251 ) + 252 api.step_data('Analyze wasm', 253 stdout=api.raw_io.output(sample_wasm)) + 254 api.step_data('Analyze flutter', 255 stdout=api.raw_io.output(sample_flutter)) 256 ) 257 258sample_wasm = """ 259#$%^&* 260Report A 261 Total size: 50 bytes 262#$%^&* 263Report B 264 Total size: 60 bytes 265#$%^&* 266{ 267 "some": "json" 268} 269""" 270 271sample_flutter = """ 272#$%^&* 273Report A 274 Total size: 50 bytes 275#$%^&* 276Report B 277 Total size: 60 bytes 278#$%^&* 279Report C 280 Total size: 70 bytes 281#$%^&* 282Report D 283 Total size: 80 bytes 284#$%^&* 285{ 286 "some": "json" 287} 288""" 289