1*b7c941bbSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*b7c941bbSAndroid Build Coastguard Worker# 3*b7c941bbSAndroid Build Coastguard Worker# Copyright 2021 - The Android Open Source Project 4*b7c941bbSAndroid Build Coastguard Worker# 5*b7c941bbSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*b7c941bbSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*b7c941bbSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*b7c941bbSAndroid Build Coastguard Worker# 9*b7c941bbSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*b7c941bbSAndroid Build Coastguard Worker# 11*b7c941bbSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*b7c941bbSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*b7c941bbSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*b7c941bbSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*b7c941bbSAndroid Build Coastguard Worker# limitations under the License. 16*b7c941bbSAndroid Build Coastguard Worker 17*b7c941bbSAndroid Build Coastguard Worker"""Incremental dEQP 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard WorkerThis script will run a subset of dEQP test on device to get dEQP dependency. 20*b7c941bbSAndroid Build Coastguard Worker 21*b7c941bbSAndroid Build Coastguard WorkerUsage 1: Compare with a base build to check if any dEQP dependency has 22*b7c941bbSAndroid Build Coastguard Workerchanged. Output a decision if dEQP could be skipped, and a cts-tradefed 23*b7c941bbSAndroid Build Coastguard Workercommand to be used based on the decision. 24*b7c941bbSAndroid Build Coastguard Worker 25*b7c941bbSAndroid Build Coastguard Workerpython3 incremental_deqp.py -s [device serial] -t [test directory] -b 26*b7c941bbSAndroid Build Coastguard Worker[base build target file] -c [current build target file] 27*b7c941bbSAndroid Build Coastguard Worker 28*b7c941bbSAndroid Build Coastguard WorkerUsage 2: Generate a file containing a list of dEQP dependencies for the 29*b7c941bbSAndroid Build Coastguard Workerbuild on device. 30*b7c941bbSAndroid Build Coastguard Worker 31*b7c941bbSAndroid Build Coastguard Workerpython3 incremental_deqp.py -s [device serial] -t [test directory] 32*b7c941bbSAndroid Build Coastguard Worker--generate_deps_only 33*b7c941bbSAndroid Build Coastguard Worker 34*b7c941bbSAndroid Build Coastguard Worker""" 35*b7c941bbSAndroid Build Coastguard Workerimport argparse 36*b7c941bbSAndroid Build Coastguard Workerimport importlib 37*b7c941bbSAndroid Build Coastguard Workerimport json 38*b7c941bbSAndroid Build Coastguard Workerimport logging 39*b7c941bbSAndroid Build Coastguard Workerimport os 40*b7c941bbSAndroid Build Coastguard Workerimport pkgutil 41*b7c941bbSAndroid Build Coastguard Workerimport re 42*b7c941bbSAndroid Build Coastguard Workerimport subprocess 43*b7c941bbSAndroid Build Coastguard Workerimport tempfile 44*b7c941bbSAndroid Build Coastguard Workerimport time 45*b7c941bbSAndroid Build Coastguard Workerimport uuid 46*b7c941bbSAndroid Build Coastguard Workerfrom target_file_handler import TargetFileHandler 47*b7c941bbSAndroid Build Coastguard Workerfrom custom_build_file_handler import CustomBuildFileHandler 48*b7c941bbSAndroid Build Coastguard Workerfrom zipfile import ZipFile 49*b7c941bbSAndroid Build Coastguard Worker 50*b7c941bbSAndroid Build Coastguard Worker 51*b7c941bbSAndroid Build Coastguard WorkerDEFAULT_CTS_XML = ('<?xml version="1.0" encoding="utf-8"?>\n' 52*b7c941bbSAndroid Build Coastguard Worker '<configuration description="Runs CTS from a pre-existing CTS installation">\n' 53*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-common" />\n' 54*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-exclude" />\n' 55*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-exclude-instant" />\n' 56*b7c941bbSAndroid Build Coastguard Worker ' <option name="enable-token-sharding" ' 57*b7c941bbSAndroid Build Coastguard Worker 'value="true" />\n' 58*b7c941bbSAndroid Build Coastguard Worker ' <option name="plan" value="cts" />\n' 59*b7c941bbSAndroid Build Coastguard Worker '</configuration>\n') 60*b7c941bbSAndroid Build Coastguard Worker 61*b7c941bbSAndroid Build Coastguard WorkerINCREMENTAL_DEQP_XML = ('<?xml version="1.0" encoding="utf-8"?>\n' 62*b7c941bbSAndroid Build Coastguard Worker '<configuration description="Runs CTS with incremental dEQP">\n' 63*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-common" />\n' 64*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-exclude" />\n' 65*b7c941bbSAndroid Build Coastguard Worker ' <include name="cts-exclude-instant" />\n' 66*b7c941bbSAndroid Build Coastguard Worker ' <option name="enable-token-sharding" ' 67*b7c941bbSAndroid Build Coastguard Worker 'value="true" />\n' 68*b7c941bbSAndroid Build Coastguard Worker ' <option name="compatibility:exclude-filter" ' 69*b7c941bbSAndroid Build Coastguard Worker 'value="CtsDeqpTestCases" />\n' 70*b7c941bbSAndroid Build Coastguard Worker ' <option name="plan" value="cts" />\n' 71*b7c941bbSAndroid Build Coastguard Worker '</configuration>\n') 72*b7c941bbSAndroid Build Coastguard Worker 73*b7c941bbSAndroid Build Coastguard WorkerREPORT_FILENAME = 'incremental_dEQP_report.json' 74*b7c941bbSAndroid Build Coastguard Worker 75*b7c941bbSAndroid Build Coastguard Workerlogger = logging.getLogger() 76*b7c941bbSAndroid Build Coastguard Worker 77*b7c941bbSAndroid Build Coastguard Worker 78*b7c941bbSAndroid Build Coastguard Workerclass AtsError(Exception): 79*b7c941bbSAndroid Build Coastguard Worker """Error when running incremental dEQP with Android Test Station""" 80*b7c941bbSAndroid Build Coastguard Worker pass 81*b7c941bbSAndroid Build Coastguard Worker 82*b7c941bbSAndroid Build Coastguard Workerclass AdbError(Exception): 83*b7c941bbSAndroid Build Coastguard Worker """Error when running adb command.""" 84*b7c941bbSAndroid Build Coastguard Worker pass 85*b7c941bbSAndroid Build Coastguard Worker 86*b7c941bbSAndroid Build Coastguard Workerclass TestError(Exception): 87*b7c941bbSAndroid Build Coastguard Worker """Error when running dEQP test.""" 88*b7c941bbSAndroid Build Coastguard Worker pass 89*b7c941bbSAndroid Build Coastguard Worker 90*b7c941bbSAndroid Build Coastguard Workerclass TestResourceError(Exception): 91*b7c941bbSAndroid Build Coastguard Worker """Error with test resource. """ 92*b7c941bbSAndroid Build Coastguard Worker pass 93*b7c941bbSAndroid Build Coastguard Worker 94*b7c941bbSAndroid Build Coastguard Workerclass BuildHelper(object): 95*b7c941bbSAndroid Build Coastguard Worker """Helper class for analyzing build.""" 96*b7c941bbSAndroid Build Coastguard Worker 97*b7c941bbSAndroid Build Coastguard Worker def __init__(self, custom_handler=False): 98*b7c941bbSAndroid Build Coastguard Worker """Init BuildHelper. 99*b7c941bbSAndroid Build Coastguard Worker 100*b7c941bbSAndroid Build Coastguard Worker Args: 101*b7c941bbSAndroid Build Coastguard Worker custom_handler: use custom build handler. 102*b7c941bbSAndroid Build Coastguard Worker """ 103*b7c941bbSAndroid Build Coastguard Worker self._build_file_handler = TargetFileHandler 104*b7c941bbSAndroid Build Coastguard Worker if custom_handler: 105*b7c941bbSAndroid Build Coastguard Worker self._build_file_handler = CustomBuildFileHandler 106*b7c941bbSAndroid Build Coastguard Worker 107*b7c941bbSAndroid Build Coastguard Worker 108*b7c941bbSAndroid Build Coastguard Worker def compare_base_build_with_current_build(self, deqp_deps, current_build_file, 109*b7c941bbSAndroid Build Coastguard Worker base_build_file): 110*b7c941bbSAndroid Build Coastguard Worker """Compare the difference of current build and base build with dEQP dependency. 111*b7c941bbSAndroid Build Coastguard Worker 112*b7c941bbSAndroid Build Coastguard Worker If the difference doesn't involve dEQP dependency, current build could skip dEQP test if 113*b7c941bbSAndroid Build Coastguard Worker base build has passed test. 114*b7c941bbSAndroid Build Coastguard Worker 115*b7c941bbSAndroid Build Coastguard Worker Args: 116*b7c941bbSAndroid Build Coastguard Worker deqp_deps: a set of dEQP dependency. 117*b7c941bbSAndroid Build Coastguard Worker current_build_file: current build's file name. 118*b7c941bbSAndroid Build Coastguard Worker base_build_file: base build's file name. 119*b7c941bbSAndroid Build Coastguard Worker Returns: 120*b7c941bbSAndroid Build Coastguard Worker True if current build could skip dEQP, otherwise False. 121*b7c941bbSAndroid Build Coastguard Worker Dictionary of changed dependencies and their details. 122*b7c941bbSAndroid Build Coastguard Worker """ 123*b7c941bbSAndroid Build Coastguard Worker print('Comparing base build and current build...') 124*b7c941bbSAndroid Build Coastguard Worker current_build_handler = self._build_file_handler(current_build_file) 125*b7c941bbSAndroid Build Coastguard Worker current_build_hash = current_build_handler.get_file_hash(deqp_deps) 126*b7c941bbSAndroid Build Coastguard Worker 127*b7c941bbSAndroid Build Coastguard Worker base_build_handler = self._build_file_handler(base_build_file) 128*b7c941bbSAndroid Build Coastguard Worker base_build_hash = base_build_handler.get_file_hash(deqp_deps) 129*b7c941bbSAndroid Build Coastguard Worker 130*b7c941bbSAndroid Build Coastguard Worker return self._compare_build_hash(current_build_hash, base_build_hash) 131*b7c941bbSAndroid Build Coastguard Worker 132*b7c941bbSAndroid Build Coastguard Worker 133*b7c941bbSAndroid Build Coastguard Worker def compare_base_build_with_device_files(self, deqp_deps, adb, base_build_file): 134*b7c941bbSAndroid Build Coastguard Worker """Compare the difference of files on device and base build with dEQP dependency. 135*b7c941bbSAndroid Build Coastguard Worker 136*b7c941bbSAndroid Build Coastguard Worker If the difference doesn't involve dEQP dependency, current build could skip dEQP test if 137*b7c941bbSAndroid Build Coastguard Worker base build has passed test. 138*b7c941bbSAndroid Build Coastguard Worker 139*b7c941bbSAndroid Build Coastguard Worker Args: 140*b7c941bbSAndroid Build Coastguard Worker deqp_deps: a set of dEQP dependency. 141*b7c941bbSAndroid Build Coastguard Worker adb: an instance of AdbHelper for current device under test. 142*b7c941bbSAndroid Build Coastguard Worker base_build_file: base build file name. 143*b7c941bbSAndroid Build Coastguard Worker Returns: 144*b7c941bbSAndroid Build Coastguard Worker True if current build could skip dEQP, otherwise False. 145*b7c941bbSAndroid Build Coastguard Worker Dictionary of changed dependencies and their details. 146*b7c941bbSAndroid Build Coastguard Worker """ 147*b7c941bbSAndroid Build Coastguard Worker print('Comparing base build and current build on the device...') 148*b7c941bbSAndroid Build Coastguard Worker # Get current build's hash. 149*b7c941bbSAndroid Build Coastguard Worker current_build_hash = dict() 150*b7c941bbSAndroid Build Coastguard Worker for dep in deqp_deps: 151*b7c941bbSAndroid Build Coastguard Worker content = adb.run_shell_command('cat ' + dep) 152*b7c941bbSAndroid Build Coastguard Worker current_build_hash[dep] = hash(content) 153*b7c941bbSAndroid Build Coastguard Worker 154*b7c941bbSAndroid Build Coastguard Worker base_build_handler = self._build_file_handler(base_build_file) 155*b7c941bbSAndroid Build Coastguard Worker base_build_hash = base_build_handler.get_file_hash(deqp_deps) 156*b7c941bbSAndroid Build Coastguard Worker 157*b7c941bbSAndroid Build Coastguard Worker return self._compare_build_hash(current_build_hash, base_build_hash) 158*b7c941bbSAndroid Build Coastguard Worker 159*b7c941bbSAndroid Build Coastguard Worker def get_system_fingerprint(self, build_file): 160*b7c941bbSAndroid Build Coastguard Worker """Get build fingerprint in SYSTEM partition. 161*b7c941bbSAndroid Build Coastguard Worker 162*b7c941bbSAndroid Build Coastguard Worker Returns: 163*b7c941bbSAndroid Build Coastguard Worker String of build fingerprint. 164*b7c941bbSAndroid Build Coastguard Worker """ 165*b7c941bbSAndroid Build Coastguard Worker return self._build_file_handler(build_file).get_system_fingerprint() 166*b7c941bbSAndroid Build Coastguard Worker 167*b7c941bbSAndroid Build Coastguard Worker 168*b7c941bbSAndroid Build Coastguard Worker def _compare_build_hash(self, current_build_hash, base_build_hash): 169*b7c941bbSAndroid Build Coastguard Worker """Compare the hash value of current build and base build. 170*b7c941bbSAndroid Build Coastguard Worker 171*b7c941bbSAndroid Build Coastguard Worker Args: 172*b7c941bbSAndroid Build Coastguard Worker current_build_hash: map of current build where key is file name, and value is content hash. 173*b7c941bbSAndroid Build Coastguard Worker base_build_hash: map of base build where key is file name and value is content hash. 174*b7c941bbSAndroid Build Coastguard Worker Returns: 175*b7c941bbSAndroid Build Coastguard Worker Boolean about if two builds' hash is the same. 176*b7c941bbSAndroid Build Coastguard Worker Dictionary of changed dependencies and their details. 177*b7c941bbSAndroid Build Coastguard Worker """ 178*b7c941bbSAndroid Build Coastguard Worker changes = {} 179*b7c941bbSAndroid Build Coastguard Worker if current_build_hash == base_build_hash: 180*b7c941bbSAndroid Build Coastguard Worker print('Done!') 181*b7c941bbSAndroid Build Coastguard Worker return True, changes 182*b7c941bbSAndroid Build Coastguard Worker 183*b7c941bbSAndroid Build Coastguard Worker for key, val in current_build_hash.items(): 184*b7c941bbSAndroid Build Coastguard Worker if key not in base_build_hash: 185*b7c941bbSAndroid Build Coastguard Worker detail = 'File:{build_file} was not found in base build'.format(build_file=key) 186*b7c941bbSAndroid Build Coastguard Worker changes[key] = detail 187*b7c941bbSAndroid Build Coastguard Worker logger.info(detail) 188*b7c941bbSAndroid Build Coastguard Worker elif base_build_hash[key] != val: 189*b7c941bbSAndroid Build Coastguard Worker detail = ('Detected dEQP dependency file difference:{deps}. Base build hash:{base}, ' 190*b7c941bbSAndroid Build Coastguard Worker 'current build hash:{current}'.format(deps=key, base=base_build_hash[key], 191*b7c941bbSAndroid Build Coastguard Worker current=val)) 192*b7c941bbSAndroid Build Coastguard Worker changes[key] = detail 193*b7c941bbSAndroid Build Coastguard Worker logger.info(detail) 194*b7c941bbSAndroid Build Coastguard Worker 195*b7c941bbSAndroid Build Coastguard Worker print('Done!') 196*b7c941bbSAndroid Build Coastguard Worker return False, changes 197*b7c941bbSAndroid Build Coastguard Worker 198*b7c941bbSAndroid Build Coastguard Worker 199*b7c941bbSAndroid Build Coastguard Workerclass AdbHelper(object): 200*b7c941bbSAndroid Build Coastguard Worker """Helper class for running adb.""" 201*b7c941bbSAndroid Build Coastguard Worker 202*b7c941bbSAndroid Build Coastguard Worker def __init__(self, device_serial=None): 203*b7c941bbSAndroid Build Coastguard Worker """Initialize AdbHelper. 204*b7c941bbSAndroid Build Coastguard Worker 205*b7c941bbSAndroid Build Coastguard Worker Args: 206*b7c941bbSAndroid Build Coastguard Worker device_serial: A string of device serial number, optional. 207*b7c941bbSAndroid Build Coastguard Worker """ 208*b7c941bbSAndroid Build Coastguard Worker self._device_serial = device_serial 209*b7c941bbSAndroid Build Coastguard Worker 210*b7c941bbSAndroid Build Coastguard Worker def _run_adb_command(self, *args): 211*b7c941bbSAndroid Build Coastguard Worker """Run adb command.""" 212*b7c941bbSAndroid Build Coastguard Worker adb_cmd = ['adb'] 213*b7c941bbSAndroid Build Coastguard Worker if self._device_serial: 214*b7c941bbSAndroid Build Coastguard Worker adb_cmd.extend(['-s', self._device_serial]) 215*b7c941bbSAndroid Build Coastguard Worker adb_cmd.extend(args) 216*b7c941bbSAndroid Build Coastguard Worker adb_cmd = ' '.join(adb_cmd) 217*b7c941bbSAndroid Build Coastguard Worker completed = subprocess.run(adb_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 218*b7c941bbSAndroid Build Coastguard Worker if completed.returncode != 0: 219*b7c941bbSAndroid Build Coastguard Worker raise AdbError('adb command: {cmd} failed with error: {error}' 220*b7c941bbSAndroid Build Coastguard Worker .format(cmd=adb_cmd, error=completed.stderr)) 221*b7c941bbSAndroid Build Coastguard Worker 222*b7c941bbSAndroid Build Coastguard Worker return completed.stdout 223*b7c941bbSAndroid Build Coastguard Worker 224*b7c941bbSAndroid Build Coastguard Worker def push_file(self, source_file, destination_file): 225*b7c941bbSAndroid Build Coastguard Worker """Push a file from device to host. 226*b7c941bbSAndroid Build Coastguard Worker 227*b7c941bbSAndroid Build Coastguard Worker Args: 228*b7c941bbSAndroid Build Coastguard Worker source_file: A string representing file to push. 229*b7c941bbSAndroid Build Coastguard Worker destination_file: A string representing target on device to push to. 230*b7c941bbSAndroid Build Coastguard Worker """ 231*b7c941bbSAndroid Build Coastguard Worker return self._run_adb_command('push', source_file, destination_file) 232*b7c941bbSAndroid Build Coastguard Worker 233*b7c941bbSAndroid Build Coastguard Worker def pull_file(self, source_file, destination_file): 234*b7c941bbSAndroid Build Coastguard Worker """Pull a file to device. 235*b7c941bbSAndroid Build Coastguard Worker 236*b7c941bbSAndroid Build Coastguard Worker Args: 237*b7c941bbSAndroid Build Coastguard Worker source_file: A string representing file on device to pull. 238*b7c941bbSAndroid Build Coastguard Worker destination_file: A string representing target on host to pull to. 239*b7c941bbSAndroid Build Coastguard Worker """ 240*b7c941bbSAndroid Build Coastguard Worker return self._run_adb_command('pull', source_file, destination_file) 241*b7c941bbSAndroid Build Coastguard Worker 242*b7c941bbSAndroid Build Coastguard Worker def get_fingerprint(self): 243*b7c941bbSAndroid Build Coastguard Worker """Get fingerprint of the device.""" 244*b7c941bbSAndroid Build Coastguard Worker return self._run_adb_command('shell', 'getprop ro.build.fingerprint').decode("utf-8").strip() 245*b7c941bbSAndroid Build Coastguard Worker 246*b7c941bbSAndroid Build Coastguard Worker def run_shell_command(self, command): 247*b7c941bbSAndroid Build Coastguard Worker """Run a adb shell command. 248*b7c941bbSAndroid Build Coastguard Worker 249*b7c941bbSAndroid Build Coastguard Worker Args: 250*b7c941bbSAndroid Build Coastguard Worker command: A string of command to run, executed through 'adb shell' 251*b7c941bbSAndroid Build Coastguard Worker """ 252*b7c941bbSAndroid Build Coastguard Worker return self._run_adb_command('shell', command) 253*b7c941bbSAndroid Build Coastguard Worker 254*b7c941bbSAndroid Build Coastguard Worker 255*b7c941bbSAndroid Build Coastguard Workerclass DeqpDependencyCollector(object): 256*b7c941bbSAndroid Build Coastguard Worker """Collect dEQP dependency from device under test.""" 257*b7c941bbSAndroid Build Coastguard Worker 258*b7c941bbSAndroid Build Coastguard Worker def __init__(self, work_dir, test_dir, adb): 259*b7c941bbSAndroid Build Coastguard Worker """Init DeqpDependencyCollector. 260*b7c941bbSAndroid Build Coastguard Worker 261*b7c941bbSAndroid Build Coastguard Worker Args: 262*b7c941bbSAndroid Build Coastguard Worker work_dir: path of directory for saving script result and logs. 263*b7c941bbSAndroid Build Coastguard Worker test_dir: path of directory for incremental dEQP test file. 264*b7c941bbSAndroid Build Coastguard Worker adb: an instance of AdbHelper. 265*b7c941bbSAndroid Build Coastguard Worker """ 266*b7c941bbSAndroid Build Coastguard Worker self._work_dir = work_dir 267*b7c941bbSAndroid Build Coastguard Worker self._test_dir = test_dir 268*b7c941bbSAndroid Build Coastguard Worker self._adb = adb 269*b7c941bbSAndroid Build Coastguard Worker # dEQP dependency with pattern below are not an actual file: 270*b7c941bbSAndroid Build Coastguard Worker # files has prefix /data/ are not system files, e.g. intermediate files. 271*b7c941bbSAndroid Build Coastguard Worker # [vdso] is virtual dynamic shared object. 272*b7c941bbSAndroid Build Coastguard Worker # /dmabuf is a temporary file. 273*b7c941bbSAndroid Build Coastguard Worker self._exclude_deqp_pattern = re.compile('(^/data/|^\[vdso\]|^/dmabuf)') 274*b7c941bbSAndroid Build Coastguard Worker 275*b7c941bbSAndroid Build Coastguard Worker def check_test_log(self, test_file, log_file): 276*b7c941bbSAndroid Build Coastguard Worker """Check test's log to see if all tests are executed. 277*b7c941bbSAndroid Build Coastguard Worker 278*b7c941bbSAndroid Build Coastguard Worker Args: 279*b7c941bbSAndroid Build Coastguard Worker test_file: Name of test .txt file. 280*b7c941bbSAndroid Build Coastguard Worker log_content: Name of log file. 281*b7c941bbSAndroid Build Coastguard Worker Returns: 282*b7c941bbSAndroid Build Coastguard Worker True if all tests are executed, otherwise False. 283*b7c941bbSAndroid Build Coastguard Worker """ 284*b7c941bbSAndroid Build Coastguard Worker test_cnt = 0 285*b7c941bbSAndroid Build Coastguard Worker with open(test_file, 'r') as f: 286*b7c941bbSAndroid Build Coastguard Worker for _ in f: 287*b7c941bbSAndroid Build Coastguard Worker test_cnt += 1 288*b7c941bbSAndroid Build Coastguard Worker 289*b7c941bbSAndroid Build Coastguard Worker executed_test_cnt = 0 290*b7c941bbSAndroid Build Coastguard Worker 291*b7c941bbSAndroid Build Coastguard Worker with open(log_file, 'r') as f: 292*b7c941bbSAndroid Build Coastguard Worker for line in f: 293*b7c941bbSAndroid Build Coastguard Worker # 'NotSupported' status means test is not supported in device. 294*b7c941bbSAndroid Build Coastguard Worker # TODO(yichunli): Check with graphics team if failed test is allowed. 295*b7c941bbSAndroid Build Coastguard Worker if ('StatusCode="Pass"' in line or 'StatusCode="NotSupported"' in line or 296*b7c941bbSAndroid Build Coastguard Worker 'StatusCode="Fail"' in line): 297*b7c941bbSAndroid Build Coastguard Worker executed_test_cnt += 1 298*b7c941bbSAndroid Build Coastguard Worker return executed_test_cnt == test_cnt 299*b7c941bbSAndroid Build Coastguard Worker 300*b7c941bbSAndroid Build Coastguard Worker def update_dependency(self, deps, dump): 301*b7c941bbSAndroid Build Coastguard Worker """Parse perf dump file and update dEQP dependency. 302*b7c941bbSAndroid Build Coastguard Worker 303*b7c941bbSAndroid Build Coastguard Worker Below is an example of how dump file looks like: 304*b7c941bbSAndroid Build Coastguard Worker 630 record comm: type 3, misc 0, size 64 305*b7c941bbSAndroid Build Coastguard Worker 631 pid 23365, tid 23365, comm simpleperf 306*b7c941bbSAndroid Build Coastguard Worker 632 sample_id: pid 0, tid 0 307*b7c941bbSAndroid Build Coastguard Worker 633 sample_id: time 0 308*b7c941bbSAndroid Build Coastguard Worker 634 sample_id: id 23804 309*b7c941bbSAndroid Build Coastguard Worker 635 sample_id: cpu 0, res 0 310*b7c941bbSAndroid Build Coastguard Worker ....... 311*b7c941bbSAndroid Build Coastguard Worker 684 record comm: type 3, misc 8192, size 64 312*b7c941bbSAndroid Build Coastguard Worker 685 pid 23365, tid 23365, comm deqp-binary64 313*b7c941bbSAndroid Build Coastguard Worker 686 sample_id: pid 23365, tid 23365 314*b7c941bbSAndroid Build Coastguard Worker 687 sample_id: time 595063921159958 315*b7c941bbSAndroid Build Coastguard Worker 688 sample_id: id 23808 316*b7c941bbSAndroid Build Coastguard Worker 689 sample_id: cpu 4, res 0 317*b7c941bbSAndroid Build Coastguard Worker ....... 318*b7c941bbSAndroid Build Coastguard Worker 698 record mmap2: type 10, misc 8194, size 136 319*b7c941bbSAndroid Build Coastguard Worker 699 pid 23365, tid 23365, addr 0x58b817b000, len 0x3228000 320*b7c941bbSAndroid Build Coastguard Worker 700 pgoff 0x0, maj 253, min 9, ino 14709, ino_generation 2575019956 321*b7c941bbSAndroid Build Coastguard Worker 701 prot 1, flags 6146, filename /data/local/tmp/deqp-binary64 322*b7c941bbSAndroid Build Coastguard Worker 702 sample_id: pid 23365, tid 23365 323*b7c941bbSAndroid Build Coastguard Worker 703 sample_id: time 595063921188552 324*b7c941bbSAndroid Build Coastguard Worker 704 sample_id: id 23808 325*b7c941bbSAndroid Build Coastguard Worker 705 sample_id: cpu 4, res 0 326*b7c941bbSAndroid Build Coastguard Worker 327*b7c941bbSAndroid Build Coastguard Worker Args: 328*b7c941bbSAndroid Build Coastguard Worker deps: a set of string containing dEQP dependency. 329*b7c941bbSAndroid Build Coastguard Worker dump: perf dump file's name. 330*b7c941bbSAndroid Build Coastguard Worker """ 331*b7c941bbSAndroid Build Coastguard Worker binary_executed = False 332*b7c941bbSAndroid Build Coastguard Worker correct_mmap = False 333*b7c941bbSAndroid Build Coastguard Worker with open(dump, 'r') as f: 334*b7c941bbSAndroid Build Coastguard Worker for line in f: 335*b7c941bbSAndroid Build Coastguard Worker # It means dEQP binary starts to be executed. 336*b7c941bbSAndroid Build Coastguard Worker if re.search(' comm .*deqp-binary', line): 337*b7c941bbSAndroid Build Coastguard Worker binary_executed = True 338*b7c941bbSAndroid Build Coastguard Worker if not binary_executed: 339*b7c941bbSAndroid Build Coastguard Worker continue 340*b7c941bbSAndroid Build Coastguard Worker # We get a new perf event 341*b7c941bbSAndroid Build Coastguard Worker if not line.startswith(' '): 342*b7c941bbSAndroid Build Coastguard Worker # mmap with misc 1 is not for deqp binary. 343*b7c941bbSAndroid Build Coastguard Worker correct_mmap = line.startswith('record mmap') and 'misc 1,' not in line 344*b7c941bbSAndroid Build Coastguard Worker # Get file name in memory map. 345*b7c941bbSAndroid Build Coastguard Worker if 'filename' in line and correct_mmap: 346*b7c941bbSAndroid Build Coastguard Worker deps_file = line[line.find('filename') + 9:].strip() 347*b7c941bbSAndroid Build Coastguard Worker if not re.search(self._exclude_deqp_pattern, deps_file): 348*b7c941bbSAndroid Build Coastguard Worker deps.add(deps_file) 349*b7c941bbSAndroid Build Coastguard Worker 350*b7c941bbSAndroid Build Coastguard Worker 351*b7c941bbSAndroid Build Coastguard Worker def get_test_binary_name(self, test_name): 352*b7c941bbSAndroid Build Coastguard Worker """Get dEQP binary's name based on test name. 353*b7c941bbSAndroid Build Coastguard Worker 354*b7c941bbSAndroid Build Coastguard Worker Args: 355*b7c941bbSAndroid Build Coastguard Worker test_name: name of test. 356*b7c941bbSAndroid Build Coastguard Worker Returns: 357*b7c941bbSAndroid Build Coastguard Worker dEQP binary's name. 358*b7c941bbSAndroid Build Coastguard Worker """ 359*b7c941bbSAndroid Build Coastguard Worker if test_name.endswith('32'): 360*b7c941bbSAndroid Build Coastguard Worker return 'deqp-binary' 361*b7c941bbSAndroid Build Coastguard Worker elif test_name.endswith('64'): 362*b7c941bbSAndroid Build Coastguard Worker return 'deqp-binary64' 363*b7c941bbSAndroid Build Coastguard Worker else: 364*b7c941bbSAndroid Build Coastguard Worker raise TestError('Fail to get dEQP binary due to unknonw test name: ' + test_name) 365*b7c941bbSAndroid Build Coastguard Worker 366*b7c941bbSAndroid Build Coastguard Worker def get_test_log_name(self, test_name): 367*b7c941bbSAndroid Build Coastguard Worker """Get test log's name based on test name. 368*b7c941bbSAndroid Build Coastguard Worker 369*b7c941bbSAndroid Build Coastguard Worker Args: 370*b7c941bbSAndroid Build Coastguard Worker test_name: name of test. 371*b7c941bbSAndroid Build Coastguard Worker Returns: 372*b7c941bbSAndroid Build Coastguard Worker test log's name when running dEQP test. 373*b7c941bbSAndroid Build Coastguard Worker """ 374*b7c941bbSAndroid Build Coastguard Worker return test_name + '.qpa' 375*b7c941bbSAndroid Build Coastguard Worker 376*b7c941bbSAndroid Build Coastguard Worker def get_test_perf_name(self, test_name): 377*b7c941bbSAndroid Build Coastguard Worker """Get perf file's name based on test name. 378*b7c941bbSAndroid Build Coastguard Worker 379*b7c941bbSAndroid Build Coastguard Worker Args: 380*b7c941bbSAndroid Build Coastguard Worker test_name: name of test. 381*b7c941bbSAndroid Build Coastguard Worker Returns: 382*b7c941bbSAndroid Build Coastguard Worker perf file's name. 383*b7c941bbSAndroid Build Coastguard Worker """ 384*b7c941bbSAndroid Build Coastguard Worker return test_name + '.data' 385*b7c941bbSAndroid Build Coastguard Worker 386*b7c941bbSAndroid Build Coastguard Worker def get_perf_dump_name(self, test_name): 387*b7c941bbSAndroid Build Coastguard Worker """Get perf dump file's name based on test name. 388*b7c941bbSAndroid Build Coastguard Worker 389*b7c941bbSAndroid Build Coastguard Worker Args: 390*b7c941bbSAndroid Build Coastguard Worker test_name: name of test. 391*b7c941bbSAndroid Build Coastguard Worker Returns: 392*b7c941bbSAndroid Build Coastguard Worker perf dump file's name. 393*b7c941bbSAndroid Build Coastguard Worker """ 394*b7c941bbSAndroid Build Coastguard Worker return test_name + '-perf-dump.txt' 395*b7c941bbSAndroid Build Coastguard Worker 396*b7c941bbSAndroid Build Coastguard Worker def get_test_list_name(self, test_name): 397*b7c941bbSAndroid Build Coastguard Worker """Get test list file's name based on test name. 398*b7c941bbSAndroid Build Coastguard Worker 399*b7c941bbSAndroid Build Coastguard Worker test list file is used to run dEQP test. 400*b7c941bbSAndroid Build Coastguard Worker 401*b7c941bbSAndroid Build Coastguard Worker Args: 402*b7c941bbSAndroid Build Coastguard Worker test_name: name of test. 403*b7c941bbSAndroid Build Coastguard Worker Returns: 404*b7c941bbSAndroid Build Coastguard Worker test list file's name. 405*b7c941bbSAndroid Build Coastguard Worker """ 406*b7c941bbSAndroid Build Coastguard Worker if test_name.startswith('vk'): 407*b7c941bbSAndroid Build Coastguard Worker return 'vk-master-subset.txt' 408*b7c941bbSAndroid Build Coastguard Worker elif test_name.startswith('gles3'): 409*b7c941bbSAndroid Build Coastguard Worker return 'gles3-master-subset.txt' 410*b7c941bbSAndroid Build Coastguard Worker else: 411*b7c941bbSAndroid Build Coastguard Worker raise TestError('Fail to get test list due to unknown test name: ' + test_name) 412*b7c941bbSAndroid Build Coastguard Worker 413*b7c941bbSAndroid Build Coastguard Worker def get_deqp_dependency(self): 414*b7c941bbSAndroid Build Coastguard Worker """Get dEQP dependency. 415*b7c941bbSAndroid Build Coastguard Worker 416*b7c941bbSAndroid Build Coastguard Worker Returns: 417*b7c941bbSAndroid Build Coastguard Worker A set of dEQP dependency. 418*b7c941bbSAndroid Build Coastguard Worker """ 419*b7c941bbSAndroid Build Coastguard Worker device_deqp_dir = '/data/local/tmp' 420*b7c941bbSAndroid Build Coastguard Worker device_deqp_out_dir = '/data/local/tmp/out' 421*b7c941bbSAndroid Build Coastguard Worker test_list = ['vk-32', 'vk-64', 'gles3-32', 'gles3-64'] 422*b7c941bbSAndroid Build Coastguard Worker 423*b7c941bbSAndroid Build Coastguard Worker # Clean up the device. 424*b7c941bbSAndroid Build Coastguard Worker self._adb.run_shell_command('mkdir -p ' + device_deqp_out_dir) 425*b7c941bbSAndroid Build Coastguard Worker 426*b7c941bbSAndroid Build Coastguard Worker # Copy test resources to device. 427*b7c941bbSAndroid Build Coastguard Worker logger.info(self._adb.push_file(self._test_dir + '/*', device_deqp_dir)) 428*b7c941bbSAndroid Build Coastguard Worker 429*b7c941bbSAndroid Build Coastguard Worker # Run the dEQP binary with simpleperf 430*b7c941bbSAndroid Build Coastguard Worker print('Running a subset of dEQP tests as binary on the device...') 431*b7c941bbSAndroid Build Coastguard Worker deqp_deps = set() 432*b7c941bbSAndroid Build Coastguard Worker for test in test_list: 433*b7c941bbSAndroid Build Coastguard Worker test_file = os.path.join(device_deqp_dir, self.get_test_list_name(test)) 434*b7c941bbSAndroid Build Coastguard Worker log_file = os.path.join(device_deqp_out_dir, self.get_test_log_name(test)) 435*b7c941bbSAndroid Build Coastguard Worker perf_file = os.path.join(device_deqp_out_dir, self.get_test_perf_name(test)) 436*b7c941bbSAndroid Build Coastguard Worker deqp_binary = os.path.join(device_deqp_dir, self.get_test_binary_name(test)) 437*b7c941bbSAndroid Build Coastguard Worker simpleperf_command = ('"cd {device_deqp_dir} && simpleperf record -o {perf_file} {binary} ' 438*b7c941bbSAndroid Build Coastguard Worker '--deqp-caselist-file={test_list} --deqp-log-images=disable ' 439*b7c941bbSAndroid Build Coastguard Worker '--deqp-log-shader-sources=disable --deqp-log-filename={log_file} ' 440*b7c941bbSAndroid Build Coastguard Worker '--deqp-surface-type=fbo --deqp-surface-width=2048 ' 441*b7c941bbSAndroid Build Coastguard Worker '--deqp-surface-height=2048"') 442*b7c941bbSAndroid Build Coastguard Worker self._adb.run_shell_command( 443*b7c941bbSAndroid Build Coastguard Worker simpleperf_command.format(device_deqp_dir=device_deqp_dir, binary=deqp_binary, 444*b7c941bbSAndroid Build Coastguard Worker perf_file=perf_file, test_list=test_file, log_file=log_file)) 445*b7c941bbSAndroid Build Coastguard Worker 446*b7c941bbSAndroid Build Coastguard Worker # Check test log. 447*b7c941bbSAndroid Build Coastguard Worker host_log_file = os.path.join(self._work_dir, self.get_test_log_name(test)) 448*b7c941bbSAndroid Build Coastguard Worker self._adb.pull_file(log_file, host_log_file ) 449*b7c941bbSAndroid Build Coastguard Worker if not self.check_test_log(os.path.join(self._test_dir, self.get_test_list_name(test)), 450*b7c941bbSAndroid Build Coastguard Worker host_log_file): 451*b7c941bbSAndroid Build Coastguard Worker error_msg = ('Fail to run incremental dEQP because of crashed test. Check test' 452*b7c941bbSAndroid Build Coastguard Worker 'log {} for more detail.').format(host_log_file) 453*b7c941bbSAndroid Build Coastguard Worker logger.error(error_msg) 454*b7c941bbSAndroid Build Coastguard Worker raise TestError(error_msg) 455*b7c941bbSAndroid Build Coastguard Worker print('Tests are all passed!') 456*b7c941bbSAndroid Build Coastguard Worker 457*b7c941bbSAndroid Build Coastguard Worker # Parse perf dump result to get dependency. 458*b7c941bbSAndroid Build Coastguard Worker print('Analyzing dEQP dependency...') 459*b7c941bbSAndroid Build Coastguard Worker for test in test_list: 460*b7c941bbSAndroid Build Coastguard Worker perf_file = os.path.join(device_deqp_out_dir, self.get_test_perf_name(test)) 461*b7c941bbSAndroid Build Coastguard Worker dump_file = os.path.join(self._work_dir, self.get_perf_dump_name(test)) 462*b7c941bbSAndroid Build Coastguard Worker self._adb.run_shell_command('simpleperf dump {perf_file} > {dump_file}' 463*b7c941bbSAndroid Build Coastguard Worker .format(perf_file=perf_file, dump_file=dump_file)) 464*b7c941bbSAndroid Build Coastguard Worker self.update_dependency(deqp_deps, dump_file) 465*b7c941bbSAndroid Build Coastguard Worker print('Done!') 466*b7c941bbSAndroid Build Coastguard Worker return deqp_deps 467*b7c941bbSAndroid Build Coastguard Worker 468*b7c941bbSAndroid Build Coastguard Workerdef _is_deqp_dependency(dependency_name): 469*b7c941bbSAndroid Build Coastguard Worker """Check if dependency is related to dEQP.""" 470*b7c941bbSAndroid Build Coastguard Worker # dEQP dependency with pattern below will not be used to compare build: 471*b7c941bbSAndroid Build Coastguard Worker # files has /apex/ prefix are not related to dEQP. 472*b7c941bbSAndroid Build Coastguard Worker return not re.search(re.compile('^/apex/'), dependency_name) 473*b7c941bbSAndroid Build Coastguard Worker 474*b7c941bbSAndroid Build Coastguard Workerdef _get_parser(): 475*b7c941bbSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description='Run incremental dEQP on devices.') 476*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('-s', '--serial', help='Optional. Use device with given serial.') 477*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('-t', '--test', help=('Optional. Directory of incremental deqp test file. ' 478*b7c941bbSAndroid Build Coastguard Worker 'This directory should have test resources and dEQP ' 479*b7c941bbSAndroid Build Coastguard Worker 'binaries.')) 480*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('-b', '--base_build', help=('Target file of base build that has passed dEQP ' 481*b7c941bbSAndroid Build Coastguard Worker 'test, e.g. flame-target_files-6935423.zip.')) 482*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('-c', '--current_build', 483*b7c941bbSAndroid Build Coastguard Worker help=('Optional. When empty, the script will read files in the build from ' 484*b7c941bbSAndroid Build Coastguard Worker 'the device via adb. When set, the script will read build files from ' 485*b7c941bbSAndroid Build Coastguard Worker 'the file provided by this argument. And this file should be the ' 486*b7c941bbSAndroid Build Coastguard Worker 'current build that is flashed to device, such as a target file ' 487*b7c941bbSAndroid Build Coastguard Worker 'like flame-target_files-6935424.zip. This argument can be used when ' 488*b7c941bbSAndroid Build Coastguard Worker 'some dependencies files are not accessible via adb.')) 489*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('--generate_deps_only', action='store_true', 490*b7c941bbSAndroid Build Coastguard Worker help=('Run test and generate dEQP dependency list only ' 491*b7c941bbSAndroid Build Coastguard Worker 'without comparing build.')) 492*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('--custom_handler', action='store_true', 493*b7c941bbSAndroid Build Coastguard Worker help='Use custome build file handler') 494*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('--ats_mode', action='store_true', 495*b7c941bbSAndroid Build Coastguard Worker help=('Run incremental dEQP with Android Test Station.')) 496*b7c941bbSAndroid Build Coastguard Worker parser.add_argument('--userdebug_build', action='store_true', 497*b7c941bbSAndroid Build Coastguard Worker help=('ATS mode option. Current build on device is userdebug.')) 498*b7c941bbSAndroid Build Coastguard Worker return parser 499*b7c941bbSAndroid Build Coastguard Worker 500*b7c941bbSAndroid Build Coastguard Workerdef _create_logger(log_file_name): 501*b7c941bbSAndroid Build Coastguard Worker """Create logger. 502*b7c941bbSAndroid Build Coastguard Worker 503*b7c941bbSAndroid Build Coastguard Worker Args: 504*b7c941bbSAndroid Build Coastguard Worker log_file_name: absolute path of the log file. 505*b7c941bbSAndroid Build Coastguard Worker Returns: 506*b7c941bbSAndroid Build Coastguard Worker a logging.Logger 507*b7c941bbSAndroid Build Coastguard Worker """ 508*b7c941bbSAndroid Build Coastguard Worker logging.basicConfig(filename=log_file_name) 509*b7c941bbSAndroid Build Coastguard Worker logger = logging.getLogger() 510*b7c941bbSAndroid Build Coastguard Worker logger.setLevel(level=logging.NOTSET) 511*b7c941bbSAndroid Build Coastguard Worker return logger 512*b7c941bbSAndroid Build Coastguard Worker 513*b7c941bbSAndroid Build Coastguard Workerdef _save_deqp_deps(deqp_deps, file_name): 514*b7c941bbSAndroid Build Coastguard Worker """Save dEQP dependency to file. 515*b7c941bbSAndroid Build Coastguard Worker 516*b7c941bbSAndroid Build Coastguard Worker Args: 517*b7c941bbSAndroid Build Coastguard Worker deqp_deps: a set of dEQP dependency. 518*b7c941bbSAndroid Build Coastguard Worker file_name: name of the file to save dEQP dependency. 519*b7c941bbSAndroid Build Coastguard Worker Returns: 520*b7c941bbSAndroid Build Coastguard Worker name of the file that saves dEQP dependency. 521*b7c941bbSAndroid Build Coastguard Worker """ 522*b7c941bbSAndroid Build Coastguard Worker with open(file_name, 'w') as f: 523*b7c941bbSAndroid Build Coastguard Worker for dep in sorted(deqp_deps): 524*b7c941bbSAndroid Build Coastguard Worker f.write(dep+'\n') 525*b7c941bbSAndroid Build Coastguard Worker return file_name 526*b7c941bbSAndroid Build Coastguard Worker 527*b7c941bbSAndroid Build Coastguard Workerdef _generate_report( 528*b7c941bbSAndroid Build Coastguard Worker report_name, 529*b7c941bbSAndroid Build Coastguard Worker base_build_fingerprint, 530*b7c941bbSAndroid Build Coastguard Worker current_build_fingerprint, 531*b7c941bbSAndroid Build Coastguard Worker deqp_deps, 532*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps, 533*b7c941bbSAndroid Build Coastguard Worker deqp_deps_changes): 534*b7c941bbSAndroid Build Coastguard Worker """Generate a json report. 535*b7c941bbSAndroid Build Coastguard Worker 536*b7c941bbSAndroid Build Coastguard Worker Args: 537*b7c941bbSAndroid Build Coastguard Worker report_name: absolute file name of report. 538*b7c941bbSAndroid Build Coastguard Worker base_build_fingerprint: fingerprint of the base build. 539*b7c941bbSAndroid Build Coastguard Worker current_build_fingerprint: fingerprint of the current build. 540*b7c941bbSAndroid Build Coastguard Worker deqp_deps: list of dEQP dependencies generated by the tool. 541*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps: list of extra dEQP dependencies. 542*b7c941bbSAndroid Build Coastguard Worker deqp_deps_changes: dictionary of dependency changes. 543*b7c941bbSAndroid Build Coastguard Worker """ 544*b7c941bbSAndroid Build Coastguard Worker data = {} 545*b7c941bbSAndroid Build Coastguard Worker data['base_build_fingerprint'] = base_build_fingerprint 546*b7c941bbSAndroid Build Coastguard Worker data['current_build_fingerprint'] = current_build_fingerprint 547*b7c941bbSAndroid Build Coastguard Worker data['deqp_deps'] = sorted(list(deqp_deps)) 548*b7c941bbSAndroid Build Coastguard Worker data['extra_deqp_deps'] = sorted(list(extra_deqp_deps)) 549*b7c941bbSAndroid Build Coastguard Worker data['deqp_deps_changes'] = deqp_deps_changes 550*b7c941bbSAndroid Build Coastguard Worker 551*b7c941bbSAndroid Build Coastguard Worker with open(report_name, 'w') as f: 552*b7c941bbSAndroid Build Coastguard Worker json.dump(data, f, indent=4) 553*b7c941bbSAndroid Build Coastguard Worker 554*b7c941bbSAndroid Build Coastguard Worker print('Incremental dEQP report is generated at: ' + report_name) 555*b7c941bbSAndroid Build Coastguard Worker 556*b7c941bbSAndroid Build Coastguard Worker 557*b7c941bbSAndroid Build Coastguard Workerdef _local_run(args, work_dir): 558*b7c941bbSAndroid Build Coastguard Worker """Run incremental dEQP locally. 559*b7c941bbSAndroid Build Coastguard Worker 560*b7c941bbSAndroid Build Coastguard Worker Args: 561*b7c941bbSAndroid Build Coastguard Worker args: return of parser.parse_args(). 562*b7c941bbSAndroid Build Coastguard Worker work_dir: path of directory for saving script result and logs. 563*b7c941bbSAndroid Build Coastguard Worker """ 564*b7c941bbSAndroid Build Coastguard Worker print('Logs and simpleperf results will be copied to: ' + work_dir) 565*b7c941bbSAndroid Build Coastguard Worker if args.test: 566*b7c941bbSAndroid Build Coastguard Worker test_dir = args.test 567*b7c941bbSAndroid Build Coastguard Worker else: 568*b7c941bbSAndroid Build Coastguard Worker test_dir = os.path.dirname(os.path.abspath(__file__)) 569*b7c941bbSAndroid Build Coastguard Worker # Extra dEQP dependencies are the files can't be loaded to memory such as firmware. 570*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps = set() 571*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps_file = os.path.join(test_dir, 'extra_deqp_dependency.txt') 572*b7c941bbSAndroid Build Coastguard Worker if not os.path.exists(extra_deqp_deps_file): 573*b7c941bbSAndroid Build Coastguard Worker if not args.generate_deps_only: 574*b7c941bbSAndroid Build Coastguard Worker raise TestResourceError('{test_resource} doesn\'t exist' 575*b7c941bbSAndroid Build Coastguard Worker .format(test_resource=extra_deqp_deps_file)) 576*b7c941bbSAndroid Build Coastguard Worker else: 577*b7c941bbSAndroid Build Coastguard Worker with open(extra_deqp_deps_file, 'r') as f: 578*b7c941bbSAndroid Build Coastguard Worker for line in f: 579*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps.add(line.strip()) 580*b7c941bbSAndroid Build Coastguard Worker 581*b7c941bbSAndroid Build Coastguard Worker if args.serial: 582*b7c941bbSAndroid Build Coastguard Worker adb = AdbHelper(args.serial) 583*b7c941bbSAndroid Build Coastguard Worker else: 584*b7c941bbSAndroid Build Coastguard Worker adb = AdbHelper() 585*b7c941bbSAndroid Build Coastguard Worker 586*b7c941bbSAndroid Build Coastguard Worker dependency_collector = DeqpDependencyCollector(work_dir, test_dir, adb) 587*b7c941bbSAndroid Build Coastguard Worker deqp_deps = dependency_collector.get_deqp_dependency() 588*b7c941bbSAndroid Build Coastguard Worker aggregated_deqp_deps = deqp_deps.union(extra_deqp_deps) 589*b7c941bbSAndroid Build Coastguard Worker 590*b7c941bbSAndroid Build Coastguard Worker deqp_deps_file_name = _save_deqp_deps(aggregated_deqp_deps, 591*b7c941bbSAndroid Build Coastguard Worker os.path.join(work_dir, 'dEQP-dependency.txt')) 592*b7c941bbSAndroid Build Coastguard Worker print('dEQP dependency list has been generated in: ' + deqp_deps_file_name) 593*b7c941bbSAndroid Build Coastguard Worker 594*b7c941bbSAndroid Build Coastguard Worker if args.generate_deps_only: 595*b7c941bbSAndroid Build Coastguard Worker return 596*b7c941bbSAndroid Build Coastguard Worker 597*b7c941bbSAndroid Build Coastguard Worker # Compare the build difference with dEQP dependency 598*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps = [dep for dep in aggregated_deqp_deps if _is_deqp_dependency(dep)] 599*b7c941bbSAndroid Build Coastguard Worker build_helper = BuildHelper(args.custom_handler) 600*b7c941bbSAndroid Build Coastguard Worker if args.current_build: 601*b7c941bbSAndroid Build Coastguard Worker skip_dEQP, changes = build_helper.compare_base_build_with_current_build( 602*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps, args.current_build, args.base_build) 603*b7c941bbSAndroid Build Coastguard Worker else: 604*b7c941bbSAndroid Build Coastguard Worker skip_dEQP, changes = build_helper.compare_base_build_with_device_files( 605*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps, adb, args.base_build) 606*b7c941bbSAndroid Build Coastguard Worker if skip_dEQP: 607*b7c941bbSAndroid Build Coastguard Worker print('Congratulations, current build could skip dEQP test.\n' 608*b7c941bbSAndroid Build Coastguard Worker 'If you run CTS through suite, you could pass filter like ' 609*b7c941bbSAndroid Build Coastguard Worker '\'--exclude-filter CtsDeqpTestCases\'.') 610*b7c941bbSAndroid Build Coastguard Worker else: 611*b7c941bbSAndroid Build Coastguard Worker print('Sorry, current build can\'t skip dEQP test because dEQP dependency has been ' 612*b7c941bbSAndroid Build Coastguard Worker 'changed.\nPlease check logs for more details.') 613*b7c941bbSAndroid Build Coastguard Worker 614*b7c941bbSAndroid Build Coastguard Worker _generate_report(os.path.join(work_dir, REPORT_FILENAME), 615*b7c941bbSAndroid Build Coastguard Worker build_helper.get_system_fingerprint(args.base_build), 616*b7c941bbSAndroid Build Coastguard Worker adb.get_fingerprint(), 617*b7c941bbSAndroid Build Coastguard Worker deqp_deps, 618*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps, 619*b7c941bbSAndroid Build Coastguard Worker changes) 620*b7c941bbSAndroid Build Coastguard Worker 621*b7c941bbSAndroid Build Coastguard Workerdef _generate_cts_xml(out_dir, content): 622*b7c941bbSAndroid Build Coastguard Worker """Generate cts configuration for Android Test Station. 623*b7c941bbSAndroid Build Coastguard Worker 624*b7c941bbSAndroid Build Coastguard Worker Args: 625*b7c941bbSAndroid Build Coastguard Worker out_dir: output directory for cts confiugration. 626*b7c941bbSAndroid Build Coastguard Worker content: configuration content. 627*b7c941bbSAndroid Build Coastguard Worker """ 628*b7c941bbSAndroid Build Coastguard Worker with open(os.path.join(out_dir, 'incremental_deqp.xml'), 'w') as f: 629*b7c941bbSAndroid Build Coastguard Worker f.write(content) 630*b7c941bbSAndroid Build Coastguard Worker 631*b7c941bbSAndroid Build Coastguard Worker 632*b7c941bbSAndroid Build Coastguard Workerdef _ats_run(args, work_dir): 633*b7c941bbSAndroid Build Coastguard Worker """Run incremental dEQP with Android Test Station. 634*b7c941bbSAndroid Build Coastguard Worker 635*b7c941bbSAndroid Build Coastguard Worker Args: 636*b7c941bbSAndroid Build Coastguard Worker args: return of parser.parse_args(). 637*b7c941bbSAndroid Build Coastguard Worker work_dir: path of directory for saving script result and logs. 638*b7c941bbSAndroid Build Coastguard Worker """ 639*b7c941bbSAndroid Build Coastguard Worker # Extra dEQP dependencies are the files can't be loaded to memory such as firmware. 640*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps = set() 641*b7c941bbSAndroid Build Coastguard Worker with open(os.path.join(work_dir, 'extra_deqp_dependency.txt'), 'r') as f: 642*b7c941bbSAndroid Build Coastguard Worker for line in f: 643*b7c941bbSAndroid Build Coastguard Worker if line.strip(): 644*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps.add(line.strip()) 645*b7c941bbSAndroid Build Coastguard Worker 646*b7c941bbSAndroid Build Coastguard Worker android_serials = os.getenv('ANDROID_SERIALS') 647*b7c941bbSAndroid Build Coastguard Worker if not android_serials: 648*b7c941bbSAndroid Build Coastguard Worker raise AtsError('Fail to read environment variable ANDROID_SERIALS.') 649*b7c941bbSAndroid Build Coastguard Worker first_device_serial = android_serials.split(',')[0] 650*b7c941bbSAndroid Build Coastguard Worker adb = AdbHelper(first_device_serial) 651*b7c941bbSAndroid Build Coastguard Worker 652*b7c941bbSAndroid Build Coastguard Worker dependency_collector = DeqpDependencyCollector(work_dir, 653*b7c941bbSAndroid Build Coastguard Worker os.path.join(work_dir, 'test_resources'), adb) 654*b7c941bbSAndroid Build Coastguard Worker deqp_deps = dependency_collector.get_deqp_dependency() 655*b7c941bbSAndroid Build Coastguard Worker aggregated_deqp_deps = deqp_deps.union(extra_deqp_deps) 656*b7c941bbSAndroid Build Coastguard Worker 657*b7c941bbSAndroid Build Coastguard Worker deqp_deps_file_name = _save_deqp_deps(aggregated_deqp_deps, 658*b7c941bbSAndroid Build Coastguard Worker os.path.join(work_dir, 'dEQP-dependency.txt')) 659*b7c941bbSAndroid Build Coastguard Worker 660*b7c941bbSAndroid Build Coastguard Worker if args.generate_deps_only: 661*b7c941bbSAndroid Build Coastguard Worker _generate_cts_xml(work_dir, DEFAULT_CTS_XML) 662*b7c941bbSAndroid Build Coastguard Worker return 663*b7c941bbSAndroid Build Coastguard Worker 664*b7c941bbSAndroid Build Coastguard Worker # Compare the build difference with dEQP dependency 665*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps = [dep for dep in aggregated_deqp_deps if _is_deqp_dependency(dep)] 666*b7c941bbSAndroid Build Coastguard Worker 667*b7c941bbSAndroid Build Coastguard Worker # base build target file is from test resources. 668*b7c941bbSAndroid Build Coastguard Worker base_build_target = os.path.join(work_dir, 'base_build_target_files') 669*b7c941bbSAndroid Build Coastguard Worker build_helper = BuildHelper(args.custom_handler) 670*b7c941bbSAndroid Build Coastguard Worker if args.userdebug_build: 671*b7c941bbSAndroid Build Coastguard Worker current_build_fingerprint = adb.get_fingerprint() 672*b7c941bbSAndroid Build Coastguard Worker skip_dEQP, changes = build_helper.compare_base_build_with_device_files( 673*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps, adb, base_build_target) 674*b7c941bbSAndroid Build Coastguard Worker else: 675*b7c941bbSAndroid Build Coastguard Worker current_build_target = os.path.join(work_dir, 'current_build_target_files') 676*b7c941bbSAndroid Build Coastguard Worker current_build_fingerprint = build_helper.get_system_fingerprint(current_build_target) 677*b7c941bbSAndroid Build Coastguard Worker skip_dEQP, changes = build_helper.compare_base_build_with_current_build( 678*b7c941bbSAndroid Build Coastguard Worker valid_deqp_deps, current_build_target, base_build_target) 679*b7c941bbSAndroid Build Coastguard Worker if skip_dEQP: 680*b7c941bbSAndroid Build Coastguard Worker _generate_cts_xml(work_dir, INCREMENTAL_DEQP_XML) 681*b7c941bbSAndroid Build Coastguard Worker else: 682*b7c941bbSAndroid Build Coastguard Worker _generate_cts_xml(work_dir, DEFAULT_CTS_XML) 683*b7c941bbSAndroid Build Coastguard Worker 684*b7c941bbSAndroid Build Coastguard Worker _generate_report(os.path.join(*[work_dir, 'logs', REPORT_FILENAME]), 685*b7c941bbSAndroid Build Coastguard Worker build_helper.get_system_fingerprint(base_build_target), 686*b7c941bbSAndroid Build Coastguard Worker current_build_fingerprint, 687*b7c941bbSAndroid Build Coastguard Worker deqp_deps, 688*b7c941bbSAndroid Build Coastguard Worker extra_deqp_deps, 689*b7c941bbSAndroid Build Coastguard Worker changes) 690*b7c941bbSAndroid Build Coastguard Worker 691*b7c941bbSAndroid Build Coastguard Workerdef main(): 692*b7c941bbSAndroid Build Coastguard Worker parser = _get_parser() 693*b7c941bbSAndroid Build Coastguard Worker args = parser.parse_args() 694*b7c941bbSAndroid Build Coastguard Worker if not args.generate_deps_only and not args.base_build and not args.ats_mode: 695*b7c941bbSAndroid Build Coastguard Worker parser.error('Base build argument: \'-b [file] or --base_build [file]\' ' 696*b7c941bbSAndroid Build Coastguard Worker 'is required to compare build.') 697*b7c941bbSAndroid Build Coastguard Worker 698*b7c941bbSAndroid Build Coastguard Worker work_dir = '' 699*b7c941bbSAndroid Build Coastguard Worker log_file_name = '' 700*b7c941bbSAndroid Build Coastguard Worker if args.ats_mode: 701*b7c941bbSAndroid Build Coastguard Worker work_dir = os.getenv('TF_WORK_DIR') 702*b7c941bbSAndroid Build Coastguard Worker log_file_name = os.path.join(*[work_dir, 'logs', 'incremental-deqp-log-'+str(uuid.uuid4())]) 703*b7c941bbSAndroid Build Coastguard Worker else: 704*b7c941bbSAndroid Build Coastguard Worker work_dir = tempfile.mkdtemp(prefix='incremental-deqp-' 705*b7c941bbSAndroid Build Coastguard Worker + time.strftime("%Y%m%d-%H%M%S")) 706*b7c941bbSAndroid Build Coastguard Worker log_file_name = os.path.join(work_dir, 'incremental-deqp-log') 707*b7c941bbSAndroid Build Coastguard Worker global logger 708*b7c941bbSAndroid Build Coastguard Worker logger = _create_logger(log_file_name) 709*b7c941bbSAndroid Build Coastguard Worker 710*b7c941bbSAndroid Build Coastguard Worker if args.ats_mode: 711*b7c941bbSAndroid Build Coastguard Worker _ats_run(args, work_dir) 712*b7c941bbSAndroid Build Coastguard Worker else: 713*b7c941bbSAndroid Build Coastguard Worker _local_run(args, work_dir) 714*b7c941bbSAndroid Build Coastguard Worker 715*b7c941bbSAndroid Build Coastguard Workerif __name__ == '__main__': 716*b7c941bbSAndroid Build Coastguard Worker main() 717*b7c941bbSAndroid Build Coastguard Worker 718