Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 1 | # Copyright 2016 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 | |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 5 | from recipe_engine import recipe_api |
| 6 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 7 | import default_flavor |
Eric Boren | fe40abc | 2017-07-20 10:21:38 -0400 | [diff] [blame] | 8 | import re |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 9 | import subprocess |
| 10 | |
| 11 | |
| 12 | """GN Android flavor utils, used for building Skia for Android with GN.""" |
| 13 | class GNAndroidFlavorUtils(default_flavor.DefaultFlavorUtils): |
| 14 | def __init__(self, m): |
| 15 | super(GNAndroidFlavorUtils, self).__init__(m) |
| 16 | self._ever_ran_adb = False |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 17 | self.ADB_BINARY = '/usr/bin/adb.1.0.35' |
| 18 | golo_devices = ['Nexus5x'] |
| 19 | if self.m.vars.builder_cfg.get('model') in golo_devices: |
| 20 | self.ADB_BINARY = '/opt/infra-android/tools/adb' |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 21 | |
| 22 | self.device_dirs = default_flavor.DeviceDirs( |
| 23 | dm_dir = self.m.vars.android_data_dir + 'dm_out', |
| 24 | perf_data_dir = self.m.vars.android_data_dir + 'perf', |
| 25 | resource_dir = self.m.vars.android_data_dir + 'resources', |
| 26 | images_dir = self.m.vars.android_data_dir + 'images', |
| 27 | skp_dir = self.m.vars.android_data_dir + 'skps', |
| 28 | svg_dir = self.m.vars.android_data_dir + 'svgs', |
| 29 | tmp_dir = self.m.vars.android_data_dir) |
| 30 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 31 | def _run(self, title, *cmd, **kwargs): |
Robert Iannucci | 297a7ef | 2017-05-12 19:09:38 -0700 | [diff] [blame] | 32 | with self.m.context(cwd=self.m.vars.skia_dir): |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 33 | return self.m.run(self.m.step, title, cmd=list(cmd), **kwargs) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 34 | |
| 35 | def _py(self, title, script, infra_step=True): |
Robert Iannucci | 297a7ef | 2017-05-12 19:09:38 -0700 | [diff] [blame] | 36 | with self.m.context(cwd=self.m.vars.skia_dir): |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 37 | return self.m.run(self.m.python, title, script=script, |
| 38 | infra_step=infra_step) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 39 | |
| 40 | def _adb(self, title, *cmd, **kwargs): |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 41 | # The only non-infra adb steps (dm / nanobench) happen to not use _adb(). |
| 42 | if 'infra_step' not in kwargs: |
| 43 | kwargs['infra_step'] = True |
Ben Wagner | cf9365a | 2017-09-08 14:06:38 -0400 | [diff] [blame] | 44 | |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 45 | self._ever_ran_adb = True |
Ben Wagner | cf9365a | 2017-09-08 14:06:38 -0400 | [diff] [blame] | 46 | attempts = 1 |
| 47 | flaky_devices = ['NexusPlayer', 'PixelC'] |
| 48 | if self.m.vars.builder_cfg.get('model') in flaky_devices: |
| 49 | attempts = 3 |
| 50 | |
| 51 | def wait_for_device(attempt): |
| 52 | self.m.run(self.m.step, |
| 53 | 'kill adb server after failure of \'%s\' (attempt %d)' % ( |
| 54 | title, attempt), |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 55 | cmd=[self.ADB_BINARY, 'kill-server'], |
Ben Wagner | cf9365a | 2017-09-08 14:06:38 -0400 | [diff] [blame] | 56 | infra_step=True, timeout=30, abort_on_failure=False, |
| 57 | fail_build_on_failure=False) |
Ben Wagner | 79a1256 | 2017-09-12 12:32:59 -0400 | [diff] [blame] | 58 | self.m.run(self.m.step, |
Ben Wagner | cf9365a | 2017-09-08 14:06:38 -0400 | [diff] [blame] | 59 | 'wait for device after failure of \'%s\' (attempt %d)' % ( |
| 60 | title, attempt), |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 61 | cmd=[self.ADB_BINARY, 'wait-for-device'], infra_step=True, |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 62 | timeout=180, abort_on_failure=False, |
| 63 | fail_build_on_failure=False) |
Ben Wagner | cf9365a | 2017-09-08 14:06:38 -0400 | [diff] [blame] | 64 | |
| 65 | with self.m.context(cwd=self.m.vars.skia_dir): |
Kevin Lubick | 7c1eae5 | 2017-10-13 12:57:49 -0400 | [diff] [blame] | 66 | return self.m.run.with_retry(self.m.step, title, attempts, |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 67 | cmd=[self.ADB_BINARY]+list(cmd), |
Kevin Lubick | 7c1eae5 | 2017-10-13 12:57:49 -0400 | [diff] [blame] | 68 | between_attempts_fn=wait_for_device, |
| 69 | **kwargs) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 70 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 71 | # A list of devices we can't root. If rooting fails and a device is not |
| 72 | # on the list, we fail the task to avoid perf inconsistencies. |
| 73 | rootable_blacklist = ['GalaxyS6', 'GalaxyS7_G930A', 'GalaxyS7_G930FD', |
| 74 | 'MotoG4', 'NVIDIA_Shield'] |
| 75 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 76 | # Maps device type -> cpu ids that need to be set when scaling, with the |
| 77 | # primary CPU being listed first. CPUs are configured together, |
| 78 | # for example, the Nexus 5x has cpu0-3 and cpu4-5 linked together, each |
| 79 | # group using the same configuration - anything that happens to cpu0, |
| 80 | # happens to cpu1-3. |
| 81 | # cpus at index 1+ will be clocked down to powersave during nanobench. |
| 82 | # TODO(kjlubick): determine this dynamically - should be able to look |
| 83 | # at which cores have the highest frequency and affected_cpus. |
| 84 | cpus_to_scale = { |
| 85 | 'Nexus5x': [4, 0], |
| 86 | 'NexusPlayer': [2, 0], |
| 87 | 'Pixel': [2, 0], |
| 88 | 'Pixel2XL': [4, 0] |
| 89 | } |
| 90 | |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 91 | # Maps device -> number of cores. TODO(kjlubick) if we want to do this |
| 92 | # long term, compute this dynamically. |
| 93 | total_cpus = { |
| 94 | 'AndroidOne': 4, |
| 95 | 'Nexus5': 4, |
| 96 | 'Nexus7': 4, |
| 97 | 'Nexus5x': 6, |
| 98 | 'NexusPlayer': 4, |
| 99 | 'Pixel': 4, |
| 100 | 'Pixel2XL': 8, |
| 101 | 'PixelC': 4, |
| 102 | } |
| 103 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 104 | def _scale_for_dm(self): |
| 105 | device = self.m.vars.builder_cfg.get('model') |
| 106 | if (device in self.rootable_blacklist or |
Kevin Lubick | 082f00a | 2017-11-28 08:33:37 -0500 | [diff] [blame] | 107 | self.m.vars.internal_hardware_label): |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 108 | return |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 109 | |
| 110 | for i in self.cpus_to_scale.get(device, [0]): |
Kevin Lubick | 1763492 | 2017-12-12 08:14:19 -0500 | [diff] [blame] | 111 | # AndroidOne doesn't support ondemand governor. hotplug is similar. |
| 112 | if device == 'AndroidOne': |
| 113 | self._set_governor(i, 'hotplug') |
| 114 | else: |
| 115 | self._set_governor(i, 'ondemand') |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 116 | |
| 117 | def _scale_for_nanobench(self): |
| 118 | device = self.m.vars.builder_cfg.get('model') |
| 119 | if (device in self.rootable_blacklist or |
| 120 | self.m.vars.internal_hardware_label): |
| 121 | return |
| 122 | |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 123 | # Scale just the first two cpus. |
| 124 | self._set_governor(0, 'userspace') |
| 125 | self._scale_cpu(0, 0.6) |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 126 | |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 127 | for i in range(2, self.total_cpus[device]): |
Kevin Lubick | 1763492 | 2017-12-12 08:14:19 -0500 | [diff] [blame] | 128 | # NexusPlayer only has "ondemand userspace interactive performance" |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 129 | self._disable_cpu(i) |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 130 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 131 | |
| 132 | def _set_governor(self, cpu, gov): |
| 133 | self._ever_ran_adb = True |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 134 | self.m.run.with_retry(self.m.python.inline, |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 135 | "Set CPU %d's governor to %s" % (cpu, gov), |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 136 | 3, # attempts |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 137 | program=""" |
| 138 | import os |
| 139 | import subprocess |
| 140 | import sys |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 141 | import time |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 142 | ADB = sys.argv[1] |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 143 | cpu = int(sys.argv[2]) |
| 144 | gov = sys.argv[3] |
| 145 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 146 | log = subprocess.check_output([ADB, 'root']) |
| 147 | # check for message like 'adbd cannot run as root in production builds' |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 148 | print log |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 149 | if 'cannot' in log: |
| 150 | raise Exception('adb root failed') |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 151 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 152 | subprocess.check_output([ADB, 'shell', 'echo "%s" > ' |
| 153 | '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)]) |
| 154 | actual_gov = subprocess.check_output([ADB, 'shell', 'cat ' |
| 155 | '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip() |
Kevin Lubick | 1763492 | 2017-12-12 08:14:19 -0500 | [diff] [blame] | 156 | if actual_gov != gov: |
| 157 | raise Exception('(actual, expected) (%s, %s)' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 158 | % (actual_gov, gov)) |
| 159 | """, |
| 160 | args = [self.ADB_BINARY, cpu, gov], |
| 161 | infra_step=True, |
| 162 | timeout=30) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 163 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 164 | |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 165 | def _disable_cpu(self, cpu): |
| 166 | self._ever_ran_adb = True |
| 167 | self.m.run.with_retry(self.m.python.inline, |
| 168 | 'Disabling CPU %d' % cpu, |
| 169 | 3, # attempts |
| 170 | program=""" |
| 171 | import os |
| 172 | import subprocess |
| 173 | import sys |
| 174 | import time |
| 175 | ADB = sys.argv[1] |
| 176 | cpu = int(sys.argv[2]) |
| 177 | |
| 178 | log = subprocess.check_output([ADB, 'root']) |
| 179 | # check for message like 'adbd cannot run as root in production builds' |
| 180 | print log |
| 181 | if 'cannot' in log: |
| 182 | raise Exception('adb root failed') |
| 183 | |
| 184 | subprocess.check_output([ADB, 'shell', 'echo 0 > ' |
| 185 | '/sys/devices/system/cpu/cpu%d/online' % cpu]) |
| 186 | actual_status = subprocess.check_output([ADB, 'shell', 'cat ' |
| 187 | '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip() |
| 188 | if actual_status != str(0): |
| 189 | raise Exception('(actual, expected) (%s, %d)' |
| 190 | % (actual_gov, gov)) |
| 191 | """, |
| 192 | args = [self.ADB_BINARY, cpu], |
| 193 | infra_step=True, |
| 194 | timeout=30) |
| 195 | |
| 196 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 197 | def _scale_cpu(self, cpu, target_percent): |
| 198 | self._ever_ran_adb = True |
| 199 | self.m.run.with_retry(self.m.python.inline, |
| 200 | 'Scale CPU %d to %f' % (cpu, target_percent), |
| 201 | 3, # attempts |
| 202 | program=""" |
| 203 | import os |
| 204 | import subprocess |
| 205 | import sys |
| 206 | import time |
| 207 | ADB = sys.argv[1] |
| 208 | target_percent = float(sys.argv[2]) |
| 209 | cpu = int(sys.argv[3]) |
| 210 | log = subprocess.check_output([ADB, 'root']) |
| 211 | # check for message like 'adbd cannot run as root in production builds' |
| 212 | print log |
| 213 | if 'cannot' in log: |
| 214 | raise Exception('adb root failed') |
| 215 | |
| 216 | root = '/sys/devices/system/cpu/cpu%d/cpufreq' %cpu |
| 217 | |
| 218 | # All devices we test on give a list of their available frequencies. |
| 219 | available_freqs = subprocess.check_output([ADB, 'shell', |
| 220 | 'cat %s/scaling_available_frequencies' % root]) |
| 221 | |
| 222 | # Check for message like '/system/bin/sh: file not found' |
| 223 | if available_freqs and '/system/bin/sh' not in available_freqs: |
| 224 | available_freqs = sorted( |
| 225 | int(i) for i in available_freqs.strip().split()) |
| 226 | else: |
| 227 | raise Exception('Could not get list of available frequencies: %s' % |
| 228 | available_freqs) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 229 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 230 | maxfreq = available_freqs[-1] |
| 231 | target = int(round(maxfreq * target_percent)) |
| 232 | freq = maxfreq |
| 233 | for f in reversed(available_freqs): |
| 234 | if f <= target: |
| 235 | freq = f |
| 236 | break |
| 237 | |
| 238 | print 'Setting frequency to %d' % freq |
| 239 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 240 | # If scaling_max_freq is lower than our attempted setting, it won't take. |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 241 | # We must set min first, because if we try to set max to be less than min |
| 242 | # (which sometimes happens after certain devices reboot) it returns a |
| 243 | # perplexing permissions error. |
Kevin Lubick | 4c6bde2 | 2017-12-05 15:54:19 -0500 | [diff] [blame] | 244 | subprocess.check_output([ADB, 'shell', 'echo 0 > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 245 | '%s/scaling_min_freq' % root]) |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 246 | subprocess.check_output([ADB, 'shell', 'echo %d > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 247 | '%s/scaling_max_freq' % (freq, root)]) |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 248 | subprocess.check_output([ADB, 'shell', 'echo %d > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 249 | '%s/scaling_setspeed' % (freq, root)]) |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 250 | time.sleep(5) |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 251 | actual_freq = subprocess.check_output([ADB, 'shell', 'cat ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 252 | '%s/scaling_cur_freq' % root]).strip() |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 253 | if actual_freq != str(freq): |
| 254 | raise Exception('(actual, expected) (%s, %d)' |
| 255 | % (actual_freq, freq)) |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 256 | """, |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 257 | args = [self.ADB_BINARY, str(target_percent), cpu], |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 258 | infra_step=True, |
| 259 | timeout=30) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 260 | |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 261 | def compile(self, unused_target): |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 262 | compiler = self.m.vars.builder_cfg.get('compiler') |
| 263 | configuration = self.m.vars.builder_cfg.get('configuration') |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame^] | 264 | extra_tokens = self.m.vars.extra_tokens |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 265 | os = self.m.vars.builder_cfg.get('os') |
| 266 | target_arch = self.m.vars.builder_cfg.get('target_arch') |
| 267 | |
| 268 | assert compiler == 'Clang' # At this rate we might not ever support GCC. |
| 269 | |
| 270 | extra_cflags = [] |
| 271 | if configuration == 'Debug': |
| 272 | extra_cflags.append('-O1') |
| 273 | |
| 274 | ndk_asset = 'android_ndk_linux' |
| 275 | if 'Mac' in os: |
| 276 | ndk_asset = 'android_ndk_darwin' |
| 277 | elif 'Win' in os: |
| 278 | ndk_asset = 'n' |
| 279 | |
| 280 | quote = lambda x: '"%s"' % x |
| 281 | args = { |
| 282 | 'ndk': quote(self.m.vars.slave_dir.join(ndk_asset)), |
| 283 | 'target_cpu': quote(target_arch), |
| 284 | } |
| 285 | |
| 286 | if configuration != 'Debug': |
| 287 | args['is_debug'] = 'false' |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame^] | 288 | if 'Vulkan' in extra_tokens: |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 289 | args['ndk_api'] = 24 |
| 290 | args['skia_enable_vulkan_debug_layers'] = 'false' |
Eric Boren | fe40abc | 2017-07-20 10:21:38 -0400 | [diff] [blame] | 291 | |
| 292 | # If an Android API level is specified, use that. |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame^] | 293 | for t in extra_tokens: |
| 294 | m = re.search(r'API(\d+)', t) |
| 295 | if m and len(m.groups()) == 1: |
| 296 | args['ndk_api'] = m.groups()[0] |
| 297 | break |
Eric Boren | fe40abc | 2017-07-20 10:21:38 -0400 | [diff] [blame] | 298 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 299 | if extra_cflags: |
| 300 | args['extra_cflags'] = repr(extra_cflags).replace("'", '"') |
| 301 | |
| 302 | gn_args = ' '.join('%s=%s' % (k,v) for (k,v) in sorted(args.iteritems())) |
| 303 | |
| 304 | gn = 'gn.exe' if 'Win' in os else 'gn' |
| 305 | ninja = 'ninja.exe' if 'Win' in os else 'ninja' |
| 306 | gn = self.m.vars.skia_dir.join('bin', gn) |
| 307 | |
| 308 | self._py('fetch-gn', self.m.vars.skia_dir.join('bin', 'fetch-gn')) |
| 309 | self._run('gn gen', gn, 'gen', self.out_dir, '--args=' + gn_args) |
Mike Klein | 7a13d87 | 2017-11-06 09:28:59 -0500 | [diff] [blame] | 310 | self._run('ninja', ninja, '-k', '0', '-C', self.out_dir) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 311 | |
| 312 | def install(self): |
| 313 | self._adb('mkdir ' + self.device_dirs.resource_dir, |
| 314 | 'shell', 'mkdir', '-p', self.device_dirs.resource_dir) |
| 315 | |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 316 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 317 | def cleanup_steps(self): |
| 318 | if self._ever_ran_adb: |
Kevin Lubick | 549638c | 2017-02-09 16:13:10 -0500 | [diff] [blame] | 319 | self.m.run(self.m.python.inline, 'dump log', program=""" |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 320 | import os |
| 321 | import subprocess |
| 322 | import sys |
| 323 | out = sys.argv[1] |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 324 | log = subprocess.check_output(['%s', 'logcat', '-d']) |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 325 | for line in log.split('\\n'): |
| 326 | tokens = line.split() |
| 327 | if len(tokens) == 11 and tokens[-7] == 'F' and tokens[-3] == 'pc': |
| 328 | addr, path = tokens[-2:] |
| 329 | local = os.path.join(out, os.path.basename(path)) |
| 330 | if os.path.exists(local): |
| 331 | sym = subprocess.check_output(['addr2line', '-Cfpe', local, addr]) |
| 332 | line = line.replace(addr, addr + ' ' + sym.strip()) |
| 333 | print line |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 334 | """ % self.ADB_BINARY, |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 335 | args=[self.m.vars.skia_out.join(self.m.vars.configuration)], |
| 336 | infra_step=True, |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 337 | timeout=300, |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 338 | abort_on_failure=False) |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 339 | |
Kevin Lubick | 65e8a71 | 2017-02-15 10:08:51 -0500 | [diff] [blame] | 340 | # Only shutdown the device and quarantine the bot if the first failed step |
| 341 | # is an infra step. If, instead, we did this for any infra failures, we |
| 342 | # would shutdown too much. For example, if a Nexus 10 died during dm |
| 343 | # and the following pull step would also fail "device not found" - causing |
| 344 | # us to run the shutdown command when the device was probably not in a |
| 345 | # broken state; it was just rebooting. |
| 346 | if (self.m.run.failed_steps and |
| 347 | isinstance(self.m.run.failed_steps[0], recipe_api.InfraFailure)): |
| 348 | self._adb('shut down device to quarantine bot', 'shell', 'reboot', '-p') |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 349 | |
| 350 | if self._ever_ran_adb: |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 351 | self._adb('kill adb server', 'kill-server') |
| 352 | |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 353 | def step(self, name, cmd, **kwargs): |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 354 | if (cmd[0] == 'nanobench'): |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 355 | self._scale_for_nanobench() |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 356 | else: |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 357 | self._scale_for_dm() |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 358 | app = self.m.vars.skia_out.join(self.m.vars.configuration, cmd[0]) |
| 359 | self._adb('push %s' % cmd[0], |
| 360 | 'push', app, self.m.vars.android_bin_dir) |
| 361 | |
| 362 | sh = '%s.sh' % cmd[0] |
| 363 | self.m.run.writefile(self.m.vars.tmp_dir.join(sh), |
| 364 | 'set -x; %s%s; echo $? >%src' % |
| 365 | (self.m.vars.android_bin_dir, subprocess.list2cmdline(map(str, cmd)), |
| 366 | self.m.vars.android_bin_dir)) |
| 367 | self._adb('push %s' % sh, |
| 368 | 'push', self.m.vars.tmp_dir.join(sh), self.m.vars.android_bin_dir) |
| 369 | |
| 370 | self._adb('clear log', 'logcat', '-c') |
| 371 | self.m.python.inline('%s' % cmd[0], """ |
| 372 | import subprocess |
| 373 | import sys |
| 374 | bin_dir = sys.argv[1] |
| 375 | sh = sys.argv[2] |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 376 | subprocess.check_call(['%s', 'shell', 'sh', bin_dir + sh]) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 377 | try: |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 378 | sys.exit(int(subprocess.check_output(['%s', 'shell', 'cat', |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 379 | bin_dir + 'rc']))) |
| 380 | except ValueError: |
| 381 | print "Couldn't read the return code. Probably killed for OOM." |
| 382 | sys.exit(1) |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 383 | """ % (self.ADB_BINARY, self.ADB_BINARY), |
| 384 | args=[self.m.vars.android_bin_dir, sh]) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 385 | |
| 386 | def copy_file_to_device(self, host, device): |
| 387 | self._adb('push %s %s' % (host, device), 'push', host, device) |
| 388 | |
| 389 | def copy_directory_contents_to_device(self, host, device): |
| 390 | # Copy the tree, avoiding hidden directories and resolving symlinks. |
Kevin Lubick | 549638c | 2017-02-09 16:13:10 -0500 | [diff] [blame] | 391 | self.m.run(self.m.python.inline, 'push %s/* %s' % (host, device), |
| 392 | program=""" |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 393 | import os |
| 394 | import subprocess |
| 395 | import sys |
| 396 | host = sys.argv[1] |
| 397 | device = sys.argv[2] |
| 398 | for d, _, fs in os.walk(host): |
| 399 | p = os.path.relpath(d, host) |
| 400 | if p != '.' and p.startswith('.'): |
| 401 | continue |
| 402 | for f in fs: |
| 403 | print os.path.join(p,f) |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 404 | subprocess.check_call(['%s', 'push', |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 405 | os.path.realpath(os.path.join(host, p, f)), |
| 406 | os.path.join(device, p, f)]) |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 407 | """ % self.ADB_BINARY, args=[host, device], infra_step=True) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 408 | |
| 409 | def copy_directory_contents_to_host(self, device, host): |
| 410 | self._adb('pull %s %s' % (device, host), 'pull', device, host) |
| 411 | |
Eric Boren | bb05f70 | 2017-04-24 15:59:55 -0400 | [diff] [blame] | 412 | def read_file_on_device(self, path, **kwargs): |
| 413 | rv = self._adb('read %s' % path, |
| 414 | 'shell', 'cat', path, stdout=self.m.raw_io.output(), |
| 415 | **kwargs) |
| 416 | return rv.stdout.rstrip() if rv and rv.stdout else None |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 417 | |
| 418 | def remove_file_on_device(self, path): |
| 419 | self._adb('rm %s' % path, 'shell', 'rm', '-f', path) |
| 420 | |
| 421 | def create_clean_device_dir(self, path): |
| 422 | self._adb('rm %s' % path, 'shell', 'rm', '-rf', path) |
| 423 | self._adb('mkdir %s' % path, 'shell', 'mkdir', '-p', path) |