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' |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 18 | self._golo_devices = ['Nexus5x'] |
| 19 | if self.m.vars.builder_cfg.get('model') in self._golo_devices: |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 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 | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 76 | # Maps device type -> CPU ids that should be scaled for nanobench. |
| 77 | # Many devices have two (or more) different CPUs (e.g. big.LITTLE |
| 78 | # on Nexus5x). The CPUs listed are the biggest cpus on the device. |
| 79 | # The CPUs are grouped together, so we only need to scale one of them |
| 80 | # (the one listed) in order to scale them all. |
| 81 | # E.g. Nexus5x has cpu0-3 as one chip and cpu4-5 as the other. Thus, |
| 82 | # if one wants to run a single-threaded application (e.g. nanobench), one |
| 83 | # can disable cpu0-3 and scale cpu 4 to have only cpu4 and 5 at the same |
| 84 | # frequency. See also disable_for_nanobench. |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 85 | cpus_to_scale = { |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 86 | 'Nexus5x': [4], |
| 87 | 'NexusPlayer': [0, 2], # has 2 identical chips, so scale them both. |
| 88 | 'Pixel': [2], |
| 89 | 'Pixel2XL': [4] |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 90 | } |
| 91 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 92 | # Maps device type -> CPU ids that should be turned off when running |
| 93 | # single-threaded applications like nanobench. The devices listed have |
| 94 | # multiple, differnt CPUs. We notice a lot of noise that seems to be |
| 95 | # caused by nanobench running on the slow CPU, then the big CPU. By |
| 96 | # disabling this, we see less of that noise by forcing the same CPU |
| 97 | # to be used for the performance testing every time. |
| 98 | disable_for_nanobench = { |
| 99 | 'Nexus5x': range(0, 4), |
| 100 | 'Pixel': range(0, 2), |
| 101 | 'Pixel2XL': range(0, 4), |
| 102 | 'PixelC': range(0, 2) |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 103 | } |
| 104 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 105 | def _scale_for_dm(self): |
| 106 | device = self.m.vars.builder_cfg.get('model') |
| 107 | if (device in self.rootable_blacklist or |
Kevin Lubick | 082f00a | 2017-11-28 08:33:37 -0500 | [diff] [blame] | 108 | self.m.vars.internal_hardware_label): |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 109 | return |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 110 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 111 | # This is paranoia... any CPUs we disabled while running nanobench |
| 112 | # ought to be back online now that we've restarted the device. |
| 113 | for i in self.disable_for_nanobench.get(device, []): |
| 114 | self._set_cpu_online(i, 1) # enable |
| 115 | |
Kevin Lubick | 031e7cf | 2017-12-19 10:11:19 -0500 | [diff] [blame] | 116 | scale_up = self.cpus_to_scale.get(device, [0]) |
| 117 | # For big.LITTLE devices, make sure we scale the LITTLE cores up; |
| 118 | # there is a chance they are still in powersave mode from when |
| 119 | # swarming slows things down for cooling down and charging. |
| 120 | if 0 not in scale_up: |
| 121 | scale_up.append(0) |
| 122 | for i in scale_up: |
Kevin Lubick | 1763492 | 2017-12-12 08:14:19 -0500 | [diff] [blame] | 123 | # AndroidOne doesn't support ondemand governor. hotplug is similar. |
| 124 | if device == 'AndroidOne': |
| 125 | self._set_governor(i, 'hotplug') |
| 126 | else: |
| 127 | self._set_governor(i, 'ondemand') |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 128 | |
| 129 | def _scale_for_nanobench(self): |
| 130 | device = self.m.vars.builder_cfg.get('model') |
| 131 | if (device in self.rootable_blacklist or |
| 132 | self.m.vars.internal_hardware_label): |
| 133 | return |
| 134 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 135 | for i in self.cpus_to_scale.get(device, [0]): |
| 136 | self._set_governor(i, 'userspace') |
| 137 | self._scale_cpu(i, 0.6) |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 138 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 139 | for i in self.disable_for_nanobench.get(device, []): |
| 140 | self._set_cpu_online(i, 0) # disable |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 141 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 142 | |
| 143 | def _set_governor(self, cpu, gov): |
| 144 | self._ever_ran_adb = True |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 145 | self.m.run.with_retry(self.m.python.inline, |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 146 | "Set CPU %d's governor to %s" % (cpu, gov), |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 147 | 3, # attempts |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 148 | program=""" |
| 149 | import os |
| 150 | import subprocess |
| 151 | import sys |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 152 | import time |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 153 | ADB = sys.argv[1] |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 154 | cpu = int(sys.argv[2]) |
| 155 | gov = sys.argv[3] |
| 156 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 157 | log = subprocess.check_output([ADB, 'root']) |
| 158 | # check for message like 'adbd cannot run as root in production builds' |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 159 | print log |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 160 | if 'cannot' in log: |
| 161 | raise Exception('adb root failed') |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 162 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 163 | subprocess.check_output([ADB, 'shell', 'echo "%s" > ' |
| 164 | '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)]) |
| 165 | actual_gov = subprocess.check_output([ADB, 'shell', 'cat ' |
| 166 | '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip() |
Kevin Lubick | 1763492 | 2017-12-12 08:14:19 -0500 | [diff] [blame] | 167 | if actual_gov != gov: |
| 168 | raise Exception('(actual, expected) (%s, %s)' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 169 | % (actual_gov, gov)) |
| 170 | """, |
| 171 | args = [self.ADB_BINARY, cpu, gov], |
| 172 | infra_step=True, |
| 173 | timeout=30) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 174 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 175 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 176 | def _set_cpu_online(self, cpu, value): |
| 177 | """Set /sys/devices/system/cpu/cpu{N}/online to value (0 or 1).""" |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 178 | self._ever_ran_adb = True |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 179 | msg = 'Disabling' |
| 180 | if value: |
| 181 | msg = 'Enabling' |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 182 | self.m.run.with_retry(self.m.python.inline, |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 183 | '%s CPU %d' % (msg, cpu), |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 184 | 3, # attempts |
| 185 | program=""" |
| 186 | import os |
| 187 | import subprocess |
| 188 | import sys |
| 189 | import time |
| 190 | ADB = sys.argv[1] |
| 191 | cpu = int(sys.argv[2]) |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 192 | value = int(sys.argv[3]) |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 193 | |
| 194 | log = subprocess.check_output([ADB, 'root']) |
| 195 | # check for message like 'adbd cannot run as root in production builds' |
| 196 | print log |
| 197 | if 'cannot' in log: |
| 198 | raise Exception('adb root failed') |
| 199 | |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 200 | # If we try to echo 1 to an already online cpu, adb returns exit code 1. |
| 201 | # So, check the value before trying to write it. |
| 202 | prior_status = subprocess.check_output([ADB, 'shell', 'cat ' |
| 203 | '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip() |
| 204 | if prior_status == str(value): |
| 205 | print 'CPU %d online already %d' % (cpu, value) |
| 206 | sys.exit() |
| 207 | |
| 208 | subprocess.check_output([ADB, 'shell', 'echo %s > ' |
| 209 | '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)]) |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 210 | actual_status = subprocess.check_output([ADB, 'shell', 'cat ' |
| 211 | '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip() |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 212 | if actual_status != str(value): |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 213 | raise Exception('(actual, expected) (%s, %d)' |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 214 | % (actual_status, value)) |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 215 | """, |
Kevin Lubick | e918885 | 2017-12-14 09:47:05 -0500 | [diff] [blame] | 216 | args = [self.ADB_BINARY, cpu, value], |
Kevin Lubick | e3b0130 | 2017-12-12 15:57:20 -0500 | [diff] [blame] | 217 | infra_step=True, |
| 218 | timeout=30) |
| 219 | |
| 220 | |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 221 | def _scale_cpu(self, cpu, target_percent): |
| 222 | self._ever_ran_adb = True |
| 223 | self.m.run.with_retry(self.m.python.inline, |
| 224 | 'Scale CPU %d to %f' % (cpu, target_percent), |
| 225 | 3, # attempts |
| 226 | program=""" |
| 227 | import os |
| 228 | import subprocess |
| 229 | import sys |
| 230 | import time |
| 231 | ADB = sys.argv[1] |
| 232 | target_percent = float(sys.argv[2]) |
| 233 | cpu = int(sys.argv[3]) |
| 234 | log = subprocess.check_output([ADB, 'root']) |
| 235 | # check for message like 'adbd cannot run as root in production builds' |
| 236 | print log |
| 237 | if 'cannot' in log: |
| 238 | raise Exception('adb root failed') |
| 239 | |
| 240 | root = '/sys/devices/system/cpu/cpu%d/cpufreq' %cpu |
| 241 | |
| 242 | # All devices we test on give a list of their available frequencies. |
| 243 | available_freqs = subprocess.check_output([ADB, 'shell', |
| 244 | 'cat %s/scaling_available_frequencies' % root]) |
| 245 | |
| 246 | # Check for message like '/system/bin/sh: file not found' |
| 247 | if available_freqs and '/system/bin/sh' not in available_freqs: |
| 248 | available_freqs = sorted( |
| 249 | int(i) for i in available_freqs.strip().split()) |
| 250 | else: |
| 251 | raise Exception('Could not get list of available frequencies: %s' % |
| 252 | available_freqs) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 253 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 254 | maxfreq = available_freqs[-1] |
| 255 | target = int(round(maxfreq * target_percent)) |
| 256 | freq = maxfreq |
| 257 | for f in reversed(available_freqs): |
| 258 | if f <= target: |
| 259 | freq = f |
| 260 | break |
| 261 | |
| 262 | print 'Setting frequency to %d' % freq |
| 263 | |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 264 | # 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] | 265 | # We must set min first, because if we try to set max to be less than min |
| 266 | # (which sometimes happens after certain devices reboot) it returns a |
| 267 | # perplexing permissions error. |
Kevin Lubick | 4c6bde2 | 2017-12-05 15:54:19 -0500 | [diff] [blame] | 268 | subprocess.check_output([ADB, 'shell', 'echo 0 > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 269 | '%s/scaling_min_freq' % root]) |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 270 | subprocess.check_output([ADB, 'shell', 'echo %d > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 271 | '%s/scaling_max_freq' % (freq, root)]) |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 272 | subprocess.check_output([ADB, 'shell', 'echo %d > ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 273 | '%s/scaling_setspeed' % (freq, root)]) |
Kevin Lubick | 1c8092ac | 2017-11-30 08:35:29 -0500 | [diff] [blame] | 274 | time.sleep(5) |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 275 | actual_freq = subprocess.check_output([ADB, 'shell', 'cat ' |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 276 | '%s/scaling_cur_freq' % root]).strip() |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 277 | if actual_freq != str(freq): |
| 278 | raise Exception('(actual, expected) (%s, %d)' |
| 279 | % (actual_freq, freq)) |
Kevin Lubick | 7f5d5d2 | 2017-12-08 10:26:56 -0500 | [diff] [blame] | 280 | """, |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 281 | args = [self.ADB_BINARY, str(target_percent), cpu], |
Kevin Lubick | d1bbd5f | 2017-11-21 16:47:16 -0500 | [diff] [blame] | 282 | infra_step=True, |
| 283 | timeout=30) |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 284 | |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 285 | def compile(self, unused_target): |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 286 | compiler = self.m.vars.builder_cfg.get('compiler') |
| 287 | configuration = self.m.vars.builder_cfg.get('configuration') |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame] | 288 | extra_tokens = self.m.vars.extra_tokens |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 289 | os = self.m.vars.builder_cfg.get('os') |
| 290 | target_arch = self.m.vars.builder_cfg.get('target_arch') |
| 291 | |
| 292 | assert compiler == 'Clang' # At this rate we might not ever support GCC. |
| 293 | |
| 294 | extra_cflags = [] |
| 295 | if configuration == 'Debug': |
| 296 | extra_cflags.append('-O1') |
| 297 | |
| 298 | ndk_asset = 'android_ndk_linux' |
| 299 | if 'Mac' in os: |
| 300 | ndk_asset = 'android_ndk_darwin' |
| 301 | elif 'Win' in os: |
| 302 | ndk_asset = 'n' |
| 303 | |
| 304 | quote = lambda x: '"%s"' % x |
| 305 | args = { |
| 306 | 'ndk': quote(self.m.vars.slave_dir.join(ndk_asset)), |
| 307 | 'target_cpu': quote(target_arch), |
| 308 | } |
| 309 | |
| 310 | if configuration != 'Debug': |
| 311 | args['is_debug'] = 'false' |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame] | 312 | if 'Vulkan' in extra_tokens: |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 313 | args['ndk_api'] = 24 |
| 314 | args['skia_enable_vulkan_debug_layers'] = 'false' |
Eric Boren | fe40abc | 2017-07-20 10:21:38 -0400 | [diff] [blame] | 315 | |
| 316 | # If an Android API level is specified, use that. |
Ben Wagner | 37491d2 | 2017-12-13 13:00:47 -0500 | [diff] [blame] | 317 | for t in extra_tokens: |
| 318 | m = re.search(r'API(\d+)', t) |
| 319 | if m and len(m.groups()) == 1: |
| 320 | args['ndk_api'] = m.groups()[0] |
| 321 | break |
Eric Boren | fe40abc | 2017-07-20 10:21:38 -0400 | [diff] [blame] | 322 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 323 | if extra_cflags: |
| 324 | args['extra_cflags'] = repr(extra_cflags).replace("'", '"') |
| 325 | |
| 326 | gn_args = ' '.join('%s=%s' % (k,v) for (k,v) in sorted(args.iteritems())) |
| 327 | |
| 328 | gn = 'gn.exe' if 'Win' in os else 'gn' |
| 329 | ninja = 'ninja.exe' if 'Win' in os else 'ninja' |
| 330 | gn = self.m.vars.skia_dir.join('bin', gn) |
| 331 | |
| 332 | self._py('fetch-gn', self.m.vars.skia_dir.join('bin', 'fetch-gn')) |
| 333 | self._run('gn gen', gn, 'gen', self.out_dir, '--args=' + gn_args) |
Mike Klein | 7a13d87 | 2017-11-06 09:28:59 -0500 | [diff] [blame] | 334 | self._run('ninja', ninja, '-k', '0', '-C', self.out_dir) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 335 | |
| 336 | def install(self): |
| 337 | self._adb('mkdir ' + self.device_dirs.resource_dir, |
| 338 | 'shell', 'mkdir', '-p', self.device_dirs.resource_dir) |
| 339 | |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 340 | |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 341 | def cleanup_steps(self): |
| 342 | if self._ever_ran_adb: |
Kevin Lubick | 549638c | 2017-02-09 16:13:10 -0500 | [diff] [blame] | 343 | self.m.run(self.m.python.inline, 'dump log', program=""" |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 344 | import os |
| 345 | import subprocess |
| 346 | import sys |
| 347 | out = sys.argv[1] |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 348 | log = subprocess.check_output(['%s', 'logcat', '-d']) |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 349 | for line in log.split('\\n'): |
| 350 | tokens = line.split() |
| 351 | if len(tokens) == 11 and tokens[-7] == 'F' and tokens[-3] == 'pc': |
| 352 | addr, path = tokens[-2:] |
| 353 | local = os.path.join(out, os.path.basename(path)) |
| 354 | if os.path.exists(local): |
| 355 | sym = subprocess.check_output(['addr2line', '-Cfpe', local, addr]) |
| 356 | line = line.replace(addr, addr + ' ' + sym.strip()) |
| 357 | print line |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 358 | """ % self.ADB_BINARY, |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 359 | args=[self.m.vars.skia_out.join(self.m.vars.configuration)], |
| 360 | infra_step=True, |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 361 | timeout=300, |
Eric Boren | b82fdc7 | 2017-04-19 13:36:00 -0400 | [diff] [blame] | 362 | abort_on_failure=False) |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 363 | |
Kevin Lubick | 60bb2d5 | 2017-12-22 10:43:15 -0500 | [diff] [blame^] | 364 | # Only quarantine the bot if the first failed step |
Kevin Lubick | 65e8a71 | 2017-02-15 10:08:51 -0500 | [diff] [blame] | 365 | # is an infra step. If, instead, we did this for any infra failures, we |
Kevin Lubick | 60bb2d5 | 2017-12-22 10:43:15 -0500 | [diff] [blame^] | 366 | # would do this too much. For example, if a Nexus 10 died during dm |
Kevin Lubick | 65e8a71 | 2017-02-15 10:08:51 -0500 | [diff] [blame] | 367 | # and the following pull step would also fail "device not found" - causing |
| 368 | # us to run the shutdown command when the device was probably not in a |
| 369 | # broken state; it was just rebooting. |
| 370 | if (self.m.run.failed_steps and |
Kevin Lubick | 60bb2d5 | 2017-12-22 10:43:15 -0500 | [diff] [blame^] | 371 | isinstance(self.m.run.failed_steps[0], recipe_api.InfraFailure)): |
| 372 | self.m.file.write_text('Quarantining Bot', '~/force_quarantine', ' ') |
Kevin Lubick | 90e3cd7 | 2017-02-09 10:08:13 -0500 | [diff] [blame] | 373 | |
| 374 | if self._ever_ran_adb: |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 375 | self._adb('kill adb server', 'kill-server') |
| 376 | |
Eric Boren | 53262d0 | 2017-03-20 15:40:12 -0400 | [diff] [blame] | 377 | def step(self, name, cmd, **kwargs): |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 378 | if (cmd[0] == 'nanobench'): |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 379 | self._scale_for_nanobench() |
Kevin Lubick | bca95a5 | 2017-11-20 16:06:06 -0500 | [diff] [blame] | 380 | else: |
Kevin Lubick | f1585aa | 2017-12-12 07:33:48 -0500 | [diff] [blame] | 381 | self._scale_for_dm() |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 382 | app = self.m.vars.skia_out.join(self.m.vars.configuration, cmd[0]) |
| 383 | self._adb('push %s' % cmd[0], |
| 384 | 'push', app, self.m.vars.android_bin_dir) |
| 385 | |
| 386 | sh = '%s.sh' % cmd[0] |
| 387 | self.m.run.writefile(self.m.vars.tmp_dir.join(sh), |
| 388 | 'set -x; %s%s; echo $? >%src' % |
| 389 | (self.m.vars.android_bin_dir, subprocess.list2cmdline(map(str, cmd)), |
| 390 | self.m.vars.android_bin_dir)) |
| 391 | self._adb('push %s' % sh, |
| 392 | 'push', self.m.vars.tmp_dir.join(sh), self.m.vars.android_bin_dir) |
| 393 | |
| 394 | self._adb('clear log', 'logcat', '-c') |
| 395 | self.m.python.inline('%s' % cmd[0], """ |
| 396 | import subprocess |
| 397 | import sys |
| 398 | bin_dir = sys.argv[1] |
| 399 | sh = sys.argv[2] |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 400 | subprocess.check_call(['%s', 'shell', 'sh', bin_dir + sh]) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 401 | try: |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 402 | sys.exit(int(subprocess.check_output(['%s', 'shell', 'cat', |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 403 | bin_dir + 'rc']))) |
| 404 | except ValueError: |
| 405 | print "Couldn't read the return code. Probably killed for OOM." |
| 406 | sys.exit(1) |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 407 | """ % (self.ADB_BINARY, self.ADB_BINARY), |
| 408 | args=[self.m.vars.android_bin_dir, sh]) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 409 | |
| 410 | def copy_file_to_device(self, host, device): |
| 411 | self._adb('push %s %s' % (host, device), 'push', host, device) |
| 412 | |
| 413 | def copy_directory_contents_to_device(self, host, device): |
| 414 | # Copy the tree, avoiding hidden directories and resolving symlinks. |
Kevin Lubick | 549638c | 2017-02-09 16:13:10 -0500 | [diff] [blame] | 415 | self.m.run(self.m.python.inline, 'push %s/* %s' % (host, device), |
| 416 | program=""" |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 417 | import os |
| 418 | import subprocess |
| 419 | import sys |
| 420 | host = sys.argv[1] |
| 421 | device = sys.argv[2] |
| 422 | for d, _, fs in os.walk(host): |
| 423 | p = os.path.relpath(d, host) |
| 424 | if p != '.' and p.startswith('.'): |
| 425 | continue |
| 426 | for f in fs: |
| 427 | print os.path.join(p,f) |
Kevin Lubick | 587afc9 | 2017-10-12 12:21:47 -0400 | [diff] [blame] | 428 | subprocess.check_call(['%s', 'push', |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 429 | os.path.realpath(os.path.join(host, p, f)), |
| 430 | os.path.join(device, p, f)]) |
Kevin Lubick | 4fd283e | 2017-12-07 11:19:31 -0500 | [diff] [blame] | 431 | """ % self.ADB_BINARY, args=[host, device], infra_step=True) |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 432 | |
| 433 | def copy_directory_contents_to_host(self, device, host): |
| 434 | self._adb('pull %s %s' % (device, host), 'pull', device, host) |
| 435 | |
Eric Boren | bb05f70 | 2017-04-24 15:59:55 -0400 | [diff] [blame] | 436 | def read_file_on_device(self, path, **kwargs): |
| 437 | rv = self._adb('read %s' % path, |
| 438 | 'shell', 'cat', path, stdout=self.m.raw_io.output(), |
| 439 | **kwargs) |
| 440 | return rv.stdout.rstrip() if rv and rv.stdout else None |
Eric Boren | 7e97dc0 | 2017-02-02 09:02:37 -0500 | [diff] [blame] | 441 | |
| 442 | def remove_file_on_device(self, path): |
| 443 | self._adb('rm %s' % path, 'shell', 'rm', '-f', path) |
| 444 | |
| 445 | def create_clean_device_dir(self, path): |
| 446 | self._adb('rm %s' % path, 'shell', 'rm', '-rf', path) |
| 447 | self._adb('mkdir %s' % path, 'shell', 'mkdir', '-p', path) |