xref: /aosp_15_r20/external/angle/src/tests/run_perf_tests.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker#! /usr/bin/env vpython3
2*8975f5c5SAndroid Build Coastguard Worker#
3*8975f5c5SAndroid Build Coastguard Worker# Copyright 2021 The ANGLE Project Authors. All rights reserved.
4*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
5*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
6*8975f5c5SAndroid Build Coastguard Worker#
7*8975f5c5SAndroid Build Coastguard Worker# run_perf_test.py:
8*8975f5c5SAndroid Build Coastguard Worker#   Runs ANGLE perf tests using some statistical averaging.
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Workerimport argparse
11*8975f5c5SAndroid Build Coastguard Workerimport contextlib
12*8975f5c5SAndroid Build Coastguard Workerimport glob
13*8975f5c5SAndroid Build Coastguard Workerimport importlib
14*8975f5c5SAndroid Build Coastguard Workerimport io
15*8975f5c5SAndroid Build Coastguard Workerimport json
16*8975f5c5SAndroid Build Coastguard Workerimport logging
17*8975f5c5SAndroid Build Coastguard Workerimport tempfile
18*8975f5c5SAndroid Build Coastguard Workerimport time
19*8975f5c5SAndroid Build Coastguard Workerimport os
20*8975f5c5SAndroid Build Coastguard Workerimport pathlib
21*8975f5c5SAndroid Build Coastguard Workerimport re
22*8975f5c5SAndroid Build Coastguard Workerimport subprocess
23*8975f5c5SAndroid Build Coastguard Workerimport shutil
24*8975f5c5SAndroid Build Coastguard Workerimport sys
25*8975f5c5SAndroid Build Coastguard Worker
26*8975f5c5SAndroid Build Coastguard WorkerSCRIPT_DIR = str(pathlib.Path(__file__).resolve().parent)
27*8975f5c5SAndroid Build Coastguard WorkerPY_UTILS = str(pathlib.Path(SCRIPT_DIR) / 'py_utils')
28*8975f5c5SAndroid Build Coastguard Workerif PY_UTILS not in sys.path:
29*8975f5c5SAndroid Build Coastguard Worker    os.stat(PY_UTILS) and sys.path.insert(0, PY_UTILS)
30*8975f5c5SAndroid Build Coastguard Workerimport android_helper
31*8975f5c5SAndroid Build Coastguard Workerimport angle_metrics
32*8975f5c5SAndroid Build Coastguard Workerimport angle_path_util
33*8975f5c5SAndroid Build Coastguard Workerimport angle_test_util
34*8975f5c5SAndroid Build Coastguard Worker
35*8975f5c5SAndroid Build Coastguard Workerangle_path_util.AddDepsDirToPath('testing/scripts')
36*8975f5c5SAndroid Build Coastguard Workerimport common
37*8975f5c5SAndroid Build Coastguard Worker
38*8975f5c5SAndroid Build Coastguard Workerangle_path_util.AddDepsDirToPath('third_party/catapult/tracing')
39*8975f5c5SAndroid Build Coastguard Workerfrom tracing.value import histogram
40*8975f5c5SAndroid Build Coastguard Workerfrom tracing.value import histogram_set
41*8975f5c5SAndroid Build Coastguard Workerfrom tracing.value import merge_histograms
42*8975f5c5SAndroid Build Coastguard Worker
43*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_TEST_SUITE = 'angle_perftests'
44*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_LOG = 'info'
45*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_SAMPLES = 10
46*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_TRIALS = 4
47*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_MAX_ERRORS = 3
48*8975f5c5SAndroid Build Coastguard WorkerDEFAULT_TRIAL_TIME = 3
49*8975f5c5SAndroid Build Coastguard Worker
50*8975f5c5SAndroid Build Coastguard Worker# Test expectations
51*8975f5c5SAndroid Build Coastguard WorkerFAIL = 'FAIL'
52*8975f5c5SAndroid Build Coastguard WorkerPASS = 'PASS'
53*8975f5c5SAndroid Build Coastguard WorkerSKIP = 'SKIP'
54*8975f5c5SAndroid Build Coastguard Worker
55*8975f5c5SAndroid Build Coastguard WorkerEXIT_FAILURE = 1
56*8975f5c5SAndroid Build Coastguard WorkerEXIT_SUCCESS = 0
57*8975f5c5SAndroid Build Coastguard Worker
58*8975f5c5SAndroid Build Coastguard Worker
59*8975f5c5SAndroid Build Coastguard Worker@contextlib.contextmanager
60*8975f5c5SAndroid Build Coastguard Workerdef temporary_dir(prefix=''):
61*8975f5c5SAndroid Build Coastguard Worker    path = tempfile.mkdtemp(prefix=prefix)
62*8975f5c5SAndroid Build Coastguard Worker    try:
63*8975f5c5SAndroid Build Coastguard Worker        yield path
64*8975f5c5SAndroid Build Coastguard Worker    finally:
65*8975f5c5SAndroid Build Coastguard Worker        shutil.rmtree(path)
66*8975f5c5SAndroid Build Coastguard Worker
67*8975f5c5SAndroid Build Coastguard Worker
68*8975f5c5SAndroid Build Coastguard Workerdef _shard_tests(tests, shard_count, shard_index):
69*8975f5c5SAndroid Build Coastguard Worker    return [tests[index] for index in range(shard_index, len(tests), shard_count)]
70*8975f5c5SAndroid Build Coastguard Worker
71*8975f5c5SAndroid Build Coastguard Worker
72*8975f5c5SAndroid Build Coastguard Workerdef _get_results_from_output(output, result):
73*8975f5c5SAndroid Build Coastguard Worker    m = re.search(r'Running (\d+) tests', output)
74*8975f5c5SAndroid Build Coastguard Worker    if m and int(m.group(1)) > 1:
75*8975f5c5SAndroid Build Coastguard Worker        raise Exception('Found more than one test result in output')
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker    # Results are reported in the format:
78*8975f5c5SAndroid Build Coastguard Worker    # name_backend.result: story= value units.
79*8975f5c5SAndroid Build Coastguard Worker    pattern = r'\.' + result + r':.*= ([0-9.]+)'
80*8975f5c5SAndroid Build Coastguard Worker    logging.debug('Searching for %s in output' % pattern)
81*8975f5c5SAndroid Build Coastguard Worker    m = re.findall(pattern, output)
82*8975f5c5SAndroid Build Coastguard Worker    if not m:
83*8975f5c5SAndroid Build Coastguard Worker        logging.warning('Did not find the result "%s" in the test output:\n%s' % (result, output))
84*8975f5c5SAndroid Build Coastguard Worker        return None
85*8975f5c5SAndroid Build Coastguard Worker
86*8975f5c5SAndroid Build Coastguard Worker    return [float(value) for value in m]
87*8975f5c5SAndroid Build Coastguard Worker
88*8975f5c5SAndroid Build Coastguard Worker
89*8975f5c5SAndroid Build Coastguard Workerdef _truncated_list(data, n):
90*8975f5c5SAndroid Build Coastguard Worker    """Compute a truncated list, n is truncation size"""
91*8975f5c5SAndroid Build Coastguard Worker    if len(data) < n * 2:
92*8975f5c5SAndroid Build Coastguard Worker        raise ValueError('list not large enough to truncate')
93*8975f5c5SAndroid Build Coastguard Worker    return sorted(data)[n:-n]
94*8975f5c5SAndroid Build Coastguard Worker
95*8975f5c5SAndroid Build Coastguard Worker
96*8975f5c5SAndroid Build Coastguard Workerdef _mean(data):
97*8975f5c5SAndroid Build Coastguard Worker    """Return the sample arithmetic mean of data."""
98*8975f5c5SAndroid Build Coastguard Worker    n = len(data)
99*8975f5c5SAndroid Build Coastguard Worker    if n < 1:
100*8975f5c5SAndroid Build Coastguard Worker        raise ValueError('mean requires at least one data point')
101*8975f5c5SAndroid Build Coastguard Worker    return float(sum(data)) / float(n)  # in Python 2 use sum(data)/float(n)
102*8975f5c5SAndroid Build Coastguard Worker
103*8975f5c5SAndroid Build Coastguard Worker
104*8975f5c5SAndroid Build Coastguard Workerdef _sum_of_square_deviations(data, c):
105*8975f5c5SAndroid Build Coastguard Worker    """Return sum of square deviations of sequence data."""
106*8975f5c5SAndroid Build Coastguard Worker    ss = sum((float(x) - c)**2 for x in data)
107*8975f5c5SAndroid Build Coastguard Worker    return ss
108*8975f5c5SAndroid Build Coastguard Worker
109*8975f5c5SAndroid Build Coastguard Worker
110*8975f5c5SAndroid Build Coastguard Workerdef _coefficient_of_variation(data):
111*8975f5c5SAndroid Build Coastguard Worker    """Calculates the population coefficient of variation."""
112*8975f5c5SAndroid Build Coastguard Worker    n = len(data)
113*8975f5c5SAndroid Build Coastguard Worker    if n < 2:
114*8975f5c5SAndroid Build Coastguard Worker        raise ValueError('variance requires at least two data points')
115*8975f5c5SAndroid Build Coastguard Worker    c = _mean(data)
116*8975f5c5SAndroid Build Coastguard Worker    ss = _sum_of_square_deviations(data, c)
117*8975f5c5SAndroid Build Coastguard Worker    pvar = ss / n  # the population variance
118*8975f5c5SAndroid Build Coastguard Worker    stddev = (pvar**0.5)  # population standard deviation
119*8975f5c5SAndroid Build Coastguard Worker    return stddev / c
120*8975f5c5SAndroid Build Coastguard Worker
121*8975f5c5SAndroid Build Coastguard Worker
122*8975f5c5SAndroid Build Coastguard Workerdef _save_extra_output_files(args, results, histograms, metrics):
123*8975f5c5SAndroid Build Coastguard Worker    isolated_out_dir = os.path.dirname(args.isolated_script_test_output)
124*8975f5c5SAndroid Build Coastguard Worker    if not os.path.isdir(isolated_out_dir):
125*8975f5c5SAndroid Build Coastguard Worker        return
126*8975f5c5SAndroid Build Coastguard Worker    benchmark_path = os.path.join(isolated_out_dir, args.test_suite)
127*8975f5c5SAndroid Build Coastguard Worker    if not os.path.isdir(benchmark_path):
128*8975f5c5SAndroid Build Coastguard Worker        os.makedirs(benchmark_path)
129*8975f5c5SAndroid Build Coastguard Worker    test_output_path = os.path.join(benchmark_path, 'test_results.json')
130*8975f5c5SAndroid Build Coastguard Worker    results.save_to_json_file(test_output_path)
131*8975f5c5SAndroid Build Coastguard Worker    perf_output_path = os.path.join(benchmark_path, 'perf_results.json')
132*8975f5c5SAndroid Build Coastguard Worker    logging.info('Saving perf histograms to %s.' % perf_output_path)
133*8975f5c5SAndroid Build Coastguard Worker    with open(perf_output_path, 'w') as out_file:
134*8975f5c5SAndroid Build Coastguard Worker        out_file.write(json.dumps(histograms.AsDicts(), indent=2))
135*8975f5c5SAndroid Build Coastguard Worker
136*8975f5c5SAndroid Build Coastguard Worker    angle_metrics_path = os.path.join(benchmark_path, 'angle_metrics.json')
137*8975f5c5SAndroid Build Coastguard Worker    with open(angle_metrics_path, 'w') as f:
138*8975f5c5SAndroid Build Coastguard Worker        f.write(json.dumps(metrics, indent=2))
139*8975f5c5SAndroid Build Coastguard Worker
140*8975f5c5SAndroid Build Coastguard Worker    # Calling here to catch errors earlier (fail shard instead of merge script)
141*8975f5c5SAndroid Build Coastguard Worker    assert angle_metrics.ConvertToSkiaPerf([angle_metrics_path])
142*8975f5c5SAndroid Build Coastguard Worker
143*8975f5c5SAndroid Build Coastguard Worker
144*8975f5c5SAndroid Build Coastguard Workerclass Results:
145*8975f5c5SAndroid Build Coastguard Worker
146*8975f5c5SAndroid Build Coastguard Worker    def __init__(self, suffix):
147*8975f5c5SAndroid Build Coastguard Worker        self._results = {
148*8975f5c5SAndroid Build Coastguard Worker            'tests': {},
149*8975f5c5SAndroid Build Coastguard Worker            'interrupted': False,
150*8975f5c5SAndroid Build Coastguard Worker            'seconds_since_epoch': time.time(),
151*8975f5c5SAndroid Build Coastguard Worker            'path_delimiter': '.',
152*8975f5c5SAndroid Build Coastguard Worker            'version': 3,
153*8975f5c5SAndroid Build Coastguard Worker            'num_failures_by_type': {
154*8975f5c5SAndroid Build Coastguard Worker                FAIL: 0,
155*8975f5c5SAndroid Build Coastguard Worker                PASS: 0,
156*8975f5c5SAndroid Build Coastguard Worker                SKIP: 0,
157*8975f5c5SAndroid Build Coastguard Worker            },
158*8975f5c5SAndroid Build Coastguard Worker        }
159*8975f5c5SAndroid Build Coastguard Worker        self._test_results = {}
160*8975f5c5SAndroid Build Coastguard Worker        self._suffix = suffix
161*8975f5c5SAndroid Build Coastguard Worker
162*8975f5c5SAndroid Build Coastguard Worker    def _testname(self, name):
163*8975f5c5SAndroid Build Coastguard Worker        return name + self._suffix
164*8975f5c5SAndroid Build Coastguard Worker
165*8975f5c5SAndroid Build Coastguard Worker    def has_failures(self):
166*8975f5c5SAndroid Build Coastguard Worker        return self._results['num_failures_by_type'][FAIL] > 0
167*8975f5c5SAndroid Build Coastguard Worker
168*8975f5c5SAndroid Build Coastguard Worker    def has_result(self, test):
169*8975f5c5SAndroid Build Coastguard Worker        return self._testname(test) in self._test_results
170*8975f5c5SAndroid Build Coastguard Worker
171*8975f5c5SAndroid Build Coastguard Worker    def result_skip(self, test):
172*8975f5c5SAndroid Build Coastguard Worker        self._test_results[self._testname(test)] = {'expected': SKIP, 'actual': SKIP}
173*8975f5c5SAndroid Build Coastguard Worker        self._results['num_failures_by_type'][SKIP] += 1
174*8975f5c5SAndroid Build Coastguard Worker
175*8975f5c5SAndroid Build Coastguard Worker    def result_pass(self, test):
176*8975f5c5SAndroid Build Coastguard Worker        self._test_results[self._testname(test)] = {'expected': PASS, 'actual': PASS}
177*8975f5c5SAndroid Build Coastguard Worker        self._results['num_failures_by_type'][PASS] += 1
178*8975f5c5SAndroid Build Coastguard Worker
179*8975f5c5SAndroid Build Coastguard Worker    def result_fail(self, test):
180*8975f5c5SAndroid Build Coastguard Worker        self._test_results[self._testname(test)] = {
181*8975f5c5SAndroid Build Coastguard Worker            'expected': PASS,
182*8975f5c5SAndroid Build Coastguard Worker            'actual': FAIL,
183*8975f5c5SAndroid Build Coastguard Worker            'is_unexpected': True
184*8975f5c5SAndroid Build Coastguard Worker        }
185*8975f5c5SAndroid Build Coastguard Worker        self._results['num_failures_by_type'][FAIL] += 1
186*8975f5c5SAndroid Build Coastguard Worker
187*8975f5c5SAndroid Build Coastguard Worker    def save_to_output_file(self, test_suite, fname):
188*8975f5c5SAndroid Build Coastguard Worker        self._update_results(test_suite)
189*8975f5c5SAndroid Build Coastguard Worker        with open(fname, 'w') as out_file:
190*8975f5c5SAndroid Build Coastguard Worker            out_file.write(json.dumps(self._results, indent=2))
191*8975f5c5SAndroid Build Coastguard Worker
192*8975f5c5SAndroid Build Coastguard Worker    def save_to_json_file(self, fname):
193*8975f5c5SAndroid Build Coastguard Worker        logging.info('Saving test results to %s.' % fname)
194*8975f5c5SAndroid Build Coastguard Worker        with open(fname, 'w') as out_file:
195*8975f5c5SAndroid Build Coastguard Worker            out_file.write(json.dumps(self._results, indent=2))
196*8975f5c5SAndroid Build Coastguard Worker
197*8975f5c5SAndroid Build Coastguard Worker    def _update_results(self, test_suite):
198*8975f5c5SAndroid Build Coastguard Worker        if self._test_results:
199*8975f5c5SAndroid Build Coastguard Worker            self._results['tests'][test_suite] = self._test_results
200*8975f5c5SAndroid Build Coastguard Worker            self._test_results = {}
201*8975f5c5SAndroid Build Coastguard Worker
202*8975f5c5SAndroid Build Coastguard Worker
203*8975f5c5SAndroid Build Coastguard Workerdef _read_histogram(histogram_file_path):
204*8975f5c5SAndroid Build Coastguard Worker    with open(histogram_file_path) as histogram_file:
205*8975f5c5SAndroid Build Coastguard Worker        histogram = histogram_set.HistogramSet()
206*8975f5c5SAndroid Build Coastguard Worker        histogram.ImportDicts(json.load(histogram_file))
207*8975f5c5SAndroid Build Coastguard Worker        return histogram
208*8975f5c5SAndroid Build Coastguard Worker
209*8975f5c5SAndroid Build Coastguard Worker
210*8975f5c5SAndroid Build Coastguard Workerdef _read_metrics(metrics_file_path):
211*8975f5c5SAndroid Build Coastguard Worker    try:
212*8975f5c5SAndroid Build Coastguard Worker        with open(metrics_file_path) as f:
213*8975f5c5SAndroid Build Coastguard Worker            return [json.loads(l) for l in f]
214*8975f5c5SAndroid Build Coastguard Worker    except FileNotFoundError:
215*8975f5c5SAndroid Build Coastguard Worker        return []
216*8975f5c5SAndroid Build Coastguard Worker
217*8975f5c5SAndroid Build Coastguard Worker
218*8975f5c5SAndroid Build Coastguard Workerdef _merge_into_one_histogram(test_histogram_set):
219*8975f5c5SAndroid Build Coastguard Worker    with common.temporary_file() as merge_histogram_path:
220*8975f5c5SAndroid Build Coastguard Worker        logging.info('Writing merged histograms to %s.' % merge_histogram_path)
221*8975f5c5SAndroid Build Coastguard Worker        with open(merge_histogram_path, 'w') as merge_histogram_file:
222*8975f5c5SAndroid Build Coastguard Worker            json.dump(test_histogram_set.AsDicts(), merge_histogram_file)
223*8975f5c5SAndroid Build Coastguard Worker            merge_histogram_file.close()
224*8975f5c5SAndroid Build Coastguard Worker        merged_dicts = merge_histograms.MergeHistograms(merge_histogram_path, groupby=['name'])
225*8975f5c5SAndroid Build Coastguard Worker        merged_histogram = histogram_set.HistogramSet()
226*8975f5c5SAndroid Build Coastguard Worker        merged_histogram.ImportDicts(merged_dicts)
227*8975f5c5SAndroid Build Coastguard Worker        return merged_histogram
228*8975f5c5SAndroid Build Coastguard Worker
229*8975f5c5SAndroid Build Coastguard Worker
230*8975f5c5SAndroid Build Coastguard Workerdef _wall_times_stats(wall_times):
231*8975f5c5SAndroid Build Coastguard Worker    if len(wall_times) > 7:
232*8975f5c5SAndroid Build Coastguard Worker        truncation_n = len(wall_times) >> 3
233*8975f5c5SAndroid Build Coastguard Worker        logging.debug('Truncation: Removing the %d highest and lowest times from wall_times.' %
234*8975f5c5SAndroid Build Coastguard Worker                      truncation_n)
235*8975f5c5SAndroid Build Coastguard Worker        wall_times = _truncated_list(wall_times, truncation_n)
236*8975f5c5SAndroid Build Coastguard Worker
237*8975f5c5SAndroid Build Coastguard Worker    if len(wall_times) > 1:
238*8975f5c5SAndroid Build Coastguard Worker        return ('truncated mean wall_time = %.2f, cov = %.2f%%' %
239*8975f5c5SAndroid Build Coastguard Worker                (_mean(wall_times), _coefficient_of_variation(wall_times) * 100.0))
240*8975f5c5SAndroid Build Coastguard Worker
241*8975f5c5SAndroid Build Coastguard Worker    return None
242*8975f5c5SAndroid Build Coastguard Worker
243*8975f5c5SAndroid Build Coastguard Worker
244*8975f5c5SAndroid Build Coastguard Workerdef _run_test_suite(args, cmd_args, env):
245*8975f5c5SAndroid Build Coastguard Worker    return angle_test_util.RunTestSuite(
246*8975f5c5SAndroid Build Coastguard Worker        args.test_suite,
247*8975f5c5SAndroid Build Coastguard Worker        cmd_args,
248*8975f5c5SAndroid Build Coastguard Worker        env,
249*8975f5c5SAndroid Build Coastguard Worker        use_xvfb=args.xvfb,
250*8975f5c5SAndroid Build Coastguard Worker        show_test_stdout=args.show_test_stdout)
251*8975f5c5SAndroid Build Coastguard Worker
252*8975f5c5SAndroid Build Coastguard Worker
253*8975f5c5SAndroid Build Coastguard Workerdef _run_perf(args, common_args, env, steps_per_trial=None):
254*8975f5c5SAndroid Build Coastguard Worker    run_args = common_args + [
255*8975f5c5SAndroid Build Coastguard Worker        '--trials',
256*8975f5c5SAndroid Build Coastguard Worker        str(args.trials_per_sample),
257*8975f5c5SAndroid Build Coastguard Worker    ]
258*8975f5c5SAndroid Build Coastguard Worker
259*8975f5c5SAndroid Build Coastguard Worker    if steps_per_trial:
260*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--steps-per-trial', str(steps_per_trial)]
261*8975f5c5SAndroid Build Coastguard Worker    else:
262*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--trial-time', str(args.trial_time)]
263*8975f5c5SAndroid Build Coastguard Worker
264*8975f5c5SAndroid Build Coastguard Worker    if not args.smoke_test_mode:
265*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--warmup']  # Render each frame once with glFinish
266*8975f5c5SAndroid Build Coastguard Worker
267*8975f5c5SAndroid Build Coastguard Worker    if args.perf_counters:
268*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--perf-counters', args.perf_counters]
269*8975f5c5SAndroid Build Coastguard Worker
270*8975f5c5SAndroid Build Coastguard Worker    with temporary_dir() as render_output_dir:
271*8975f5c5SAndroid Build Coastguard Worker        histogram_file_path = os.path.join(render_output_dir, 'histogram')
272*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--isolated-script-test-perf-output=%s' % histogram_file_path]
273*8975f5c5SAndroid Build Coastguard Worker        run_args += ['--render-test-output-dir=%s' % render_output_dir]
274*8975f5c5SAndroid Build Coastguard Worker
275*8975f5c5SAndroid Build Coastguard Worker        exit_code, output, json_results = _run_test_suite(args, run_args, env)
276*8975f5c5SAndroid Build Coastguard Worker        if exit_code != EXIT_SUCCESS:
277*8975f5c5SAndroid Build Coastguard Worker            raise RuntimeError('%s failed. Output:\n%s' % (args.test_suite, output))
278*8975f5c5SAndroid Build Coastguard Worker        if SKIP in json_results['num_failures_by_type']:
279*8975f5c5SAndroid Build Coastguard Worker            return SKIP, None, None
280*8975f5c5SAndroid Build Coastguard Worker
281*8975f5c5SAndroid Build Coastguard Worker        # Extract debug files for https://issuetracker.google.com/296921272
282*8975f5c5SAndroid Build Coastguard Worker        if args.isolated_script_test_output:
283*8975f5c5SAndroid Build Coastguard Worker            isolated_out_dir = os.path.dirname(args.isolated_script_test_output)
284*8975f5c5SAndroid Build Coastguard Worker            for path in glob.glob(os.path.join(render_output_dir, '*gzdbg*')):
285*8975f5c5SAndroid Build Coastguard Worker                shutil.move(path, isolated_out_dir)
286*8975f5c5SAndroid Build Coastguard Worker
287*8975f5c5SAndroid Build Coastguard Worker        sample_metrics = _read_metrics(os.path.join(render_output_dir, 'angle_metrics'))
288*8975f5c5SAndroid Build Coastguard Worker
289*8975f5c5SAndroid Build Coastguard Worker        if sample_metrics:
290*8975f5c5SAndroid Build Coastguard Worker            sample_histogram = _read_histogram(histogram_file_path)
291*8975f5c5SAndroid Build Coastguard Worker            return PASS, sample_metrics, sample_histogram
292*8975f5c5SAndroid Build Coastguard Worker
293*8975f5c5SAndroid Build Coastguard Worker    return FAIL, None, None
294*8975f5c5SAndroid Build Coastguard Worker
295*8975f5c5SAndroid Build Coastguard Worker
296*8975f5c5SAndroid Build Coastguard Workerclass _MaxErrorsException(Exception):
297*8975f5c5SAndroid Build Coastguard Worker    pass
298*8975f5c5SAndroid Build Coastguard Worker
299*8975f5c5SAndroid Build Coastguard Worker
300*8975f5c5SAndroid Build Coastguard Workerdef _skipped_or_glmark2(test, test_status):
301*8975f5c5SAndroid Build Coastguard Worker    if test_status == SKIP:
302*8975f5c5SAndroid Build Coastguard Worker        logging.info('Test skipped by suite: %s' % test)
303*8975f5c5SAndroid Build Coastguard Worker        return True
304*8975f5c5SAndroid Build Coastguard Worker
305*8975f5c5SAndroid Build Coastguard Worker    # GLMark2Benchmark logs .fps/.score instead of our perf metrics.
306*8975f5c5SAndroid Build Coastguard Worker    if test.startswith('GLMark2Benchmark.Run/'):
307*8975f5c5SAndroid Build Coastguard Worker        logging.info('GLMark2Benchmark missing metrics (as expected, skipping): %s' % test)
308*8975f5c5SAndroid Build Coastguard Worker        return True
309*8975f5c5SAndroid Build Coastguard Worker
310*8975f5c5SAndroid Build Coastguard Worker    return False
311*8975f5c5SAndroid Build Coastguard Worker
312*8975f5c5SAndroid Build Coastguard Worker
313*8975f5c5SAndroid Build Coastguard Workerdef _sleep_until_temps_below(limit_temp):
314*8975f5c5SAndroid Build Coastguard Worker    while True:
315*8975f5c5SAndroid Build Coastguard Worker        max_temp = max(android_helper.GetTemps())
316*8975f5c5SAndroid Build Coastguard Worker        if max_temp < limit_temp:
317*8975f5c5SAndroid Build Coastguard Worker            break
318*8975f5c5SAndroid Build Coastguard Worker        logging.info('Waiting for device temps below %.1f, curently %.1f', limit_temp, max_temp)
319*8975f5c5SAndroid Build Coastguard Worker        time.sleep(10)
320*8975f5c5SAndroid Build Coastguard Worker
321*8975f5c5SAndroid Build Coastguard Worker
322*8975f5c5SAndroid Build Coastguard Workerdef _maybe_throttle_or_log_temps(custom_throttling_temp):
323*8975f5c5SAndroid Build Coastguard Worker    is_debug = logging.getLogger().isEnabledFor(logging.DEBUG)
324*8975f5c5SAndroid Build Coastguard Worker
325*8975f5c5SAndroid Build Coastguard Worker    if angle_test_util.IsAndroid():
326*8975f5c5SAndroid Build Coastguard Worker        if custom_throttling_temp:
327*8975f5c5SAndroid Build Coastguard Worker            _sleep_until_temps_below(custom_throttling_temp)
328*8975f5c5SAndroid Build Coastguard Worker        elif is_debug:
329*8975f5c5SAndroid Build Coastguard Worker            android_helper.GetTemps()  # calls log.debug
330*8975f5c5SAndroid Build Coastguard Worker    elif sys.platform == 'linux' and is_debug:
331*8975f5c5SAndroid Build Coastguard Worker        out = subprocess.check_output('cat /sys/class/hwmon/hwmon*/temp*_input', shell=True)
332*8975f5c5SAndroid Build Coastguard Worker        logging.debug('hwmon temps: %s',
333*8975f5c5SAndroid Build Coastguard Worker                      ','.join([str(int(n) // 1000) for n in out.decode().split('\n') if n]))
334*8975f5c5SAndroid Build Coastguard Worker
335*8975f5c5SAndroid Build Coastguard Worker
336*8975f5c5SAndroid Build Coastguard Workerdef _run_tests(tests, args, extra_flags, env):
337*8975f5c5SAndroid Build Coastguard Worker    if args.split_shard_samples and args.shard_index is not None:
338*8975f5c5SAndroid Build Coastguard Worker        test_suffix = Results('_shard%d' % args.shard_index)
339*8975f5c5SAndroid Build Coastguard Worker    else:
340*8975f5c5SAndroid Build Coastguard Worker        test_suffix = ''
341*8975f5c5SAndroid Build Coastguard Worker
342*8975f5c5SAndroid Build Coastguard Worker    results = Results(test_suffix)
343*8975f5c5SAndroid Build Coastguard Worker
344*8975f5c5SAndroid Build Coastguard Worker    histograms = histogram_set.HistogramSet()
345*8975f5c5SAndroid Build Coastguard Worker    metrics = []
346*8975f5c5SAndroid Build Coastguard Worker    total_errors = 0
347*8975f5c5SAndroid Build Coastguard Worker    prepared_traces = set()
348*8975f5c5SAndroid Build Coastguard Worker
349*8975f5c5SAndroid Build Coastguard Worker    for test_index in range(len(tests)):
350*8975f5c5SAndroid Build Coastguard Worker        if total_errors >= args.max_errors:
351*8975f5c5SAndroid Build Coastguard Worker            raise _MaxErrorsException()
352*8975f5c5SAndroid Build Coastguard Worker
353*8975f5c5SAndroid Build Coastguard Worker        test = tests[test_index]
354*8975f5c5SAndroid Build Coastguard Worker
355*8975f5c5SAndroid Build Coastguard Worker        if angle_test_util.IsAndroid():
356*8975f5c5SAndroid Build Coastguard Worker            trace = android_helper.GetTraceFromTestName(test)
357*8975f5c5SAndroid Build Coastguard Worker            if trace and trace not in prepared_traces:
358*8975f5c5SAndroid Build Coastguard Worker                android_helper.PrepareRestrictedTraces([trace])
359*8975f5c5SAndroid Build Coastguard Worker                prepared_traces.add(trace)
360*8975f5c5SAndroid Build Coastguard Worker
361*8975f5c5SAndroid Build Coastguard Worker        common_args = [
362*8975f5c5SAndroid Build Coastguard Worker            '--gtest_filter=%s' % test,
363*8975f5c5SAndroid Build Coastguard Worker            '--verbose',
364*8975f5c5SAndroid Build Coastguard Worker        ] + extra_flags
365*8975f5c5SAndroid Build Coastguard Worker
366*8975f5c5SAndroid Build Coastguard Worker        if args.steps_per_trial:
367*8975f5c5SAndroid Build Coastguard Worker            steps_per_trial = args.steps_per_trial
368*8975f5c5SAndroid Build Coastguard Worker            trial_limit = 'steps_per_trial=%d' % steps_per_trial
369*8975f5c5SAndroid Build Coastguard Worker        else:
370*8975f5c5SAndroid Build Coastguard Worker            steps_per_trial = None
371*8975f5c5SAndroid Build Coastguard Worker            trial_limit = 'trial_time=%d' % args.trial_time
372*8975f5c5SAndroid Build Coastguard Worker
373*8975f5c5SAndroid Build Coastguard Worker        logging.info('Test %d/%d: %s (samples=%d trials_per_sample=%d %s)' %
374*8975f5c5SAndroid Build Coastguard Worker                     (test_index + 1, len(tests), test, args.samples_per_test,
375*8975f5c5SAndroid Build Coastguard Worker                      args.trials_per_sample, trial_limit))
376*8975f5c5SAndroid Build Coastguard Worker
377*8975f5c5SAndroid Build Coastguard Worker        wall_times = []
378*8975f5c5SAndroid Build Coastguard Worker        test_histogram_set = histogram_set.HistogramSet()
379*8975f5c5SAndroid Build Coastguard Worker        for sample in range(args.samples_per_test):
380*8975f5c5SAndroid Build Coastguard Worker            try:
381*8975f5c5SAndroid Build Coastguard Worker                _maybe_throttle_or_log_temps(args.custom_throttling_temp)
382*8975f5c5SAndroid Build Coastguard Worker                test_status, sample_metrics, sample_histogram = _run_perf(
383*8975f5c5SAndroid Build Coastguard Worker                    args, common_args, env, steps_per_trial)
384*8975f5c5SAndroid Build Coastguard Worker            except RuntimeError as e:
385*8975f5c5SAndroid Build Coastguard Worker                logging.error(e)
386*8975f5c5SAndroid Build Coastguard Worker                results.result_fail(test)
387*8975f5c5SAndroid Build Coastguard Worker                total_errors += 1
388*8975f5c5SAndroid Build Coastguard Worker                break
389*8975f5c5SAndroid Build Coastguard Worker
390*8975f5c5SAndroid Build Coastguard Worker            if _skipped_or_glmark2(test, test_status):
391*8975f5c5SAndroid Build Coastguard Worker                results.result_skip(test)
392*8975f5c5SAndroid Build Coastguard Worker                break
393*8975f5c5SAndroid Build Coastguard Worker
394*8975f5c5SAndroid Build Coastguard Worker            if not sample_metrics:
395*8975f5c5SAndroid Build Coastguard Worker                logging.error('Test %s failed to produce a sample output' % test)
396*8975f5c5SAndroid Build Coastguard Worker                results.result_fail(test)
397*8975f5c5SAndroid Build Coastguard Worker                break
398*8975f5c5SAndroid Build Coastguard Worker
399*8975f5c5SAndroid Build Coastguard Worker            sample_wall_times = [
400*8975f5c5SAndroid Build Coastguard Worker                float(m['value']) for m in sample_metrics if m['metric'] == '.wall_time'
401*8975f5c5SAndroid Build Coastguard Worker            ]
402*8975f5c5SAndroid Build Coastguard Worker
403*8975f5c5SAndroid Build Coastguard Worker            logging.info('Test %d/%d Sample %d/%d wall_times: %s' %
404*8975f5c5SAndroid Build Coastguard Worker                         (test_index + 1, len(tests), sample + 1, args.samples_per_test,
405*8975f5c5SAndroid Build Coastguard Worker                          str(sample_wall_times)))
406*8975f5c5SAndroid Build Coastguard Worker
407*8975f5c5SAndroid Build Coastguard Worker            if len(sample_wall_times) != args.trials_per_sample:
408*8975f5c5SAndroid Build Coastguard Worker                logging.error('Test %s failed to record some wall_times (expected %d, got %d)' %
409*8975f5c5SAndroid Build Coastguard Worker                              (test, args.trials_per_sample, len(sample_wall_times)))
410*8975f5c5SAndroid Build Coastguard Worker                results.result_fail(test)
411*8975f5c5SAndroid Build Coastguard Worker                break
412*8975f5c5SAndroid Build Coastguard Worker
413*8975f5c5SAndroid Build Coastguard Worker            wall_times += sample_wall_times
414*8975f5c5SAndroid Build Coastguard Worker            test_histogram_set.Merge(sample_histogram)
415*8975f5c5SAndroid Build Coastguard Worker            metrics.append(sample_metrics)
416*8975f5c5SAndroid Build Coastguard Worker
417*8975f5c5SAndroid Build Coastguard Worker        if not results.has_result(test):
418*8975f5c5SAndroid Build Coastguard Worker            assert len(wall_times) == (args.samples_per_test * args.trials_per_sample)
419*8975f5c5SAndroid Build Coastguard Worker            stats = _wall_times_stats(wall_times)
420*8975f5c5SAndroid Build Coastguard Worker            if stats:
421*8975f5c5SAndroid Build Coastguard Worker                logging.info('Test %d/%d: %s: %s' % (test_index + 1, len(tests), test, stats))
422*8975f5c5SAndroid Build Coastguard Worker            histograms.Merge(_merge_into_one_histogram(test_histogram_set))
423*8975f5c5SAndroid Build Coastguard Worker            results.result_pass(test)
424*8975f5c5SAndroid Build Coastguard Worker
425*8975f5c5SAndroid Build Coastguard Worker    return results, histograms, metrics
426*8975f5c5SAndroid Build Coastguard Worker
427*8975f5c5SAndroid Build Coastguard Worker
428*8975f5c5SAndroid Build Coastguard Workerdef _find_test_suite_directory(test_suite):
429*8975f5c5SAndroid Build Coastguard Worker    if os.path.exists(angle_test_util.ExecutablePathInCurrentDir(test_suite)):
430*8975f5c5SAndroid Build Coastguard Worker        return '.'
431*8975f5c5SAndroid Build Coastguard Worker
432*8975f5c5SAndroid Build Coastguard Worker    if angle_test_util.IsWindows():
433*8975f5c5SAndroid Build Coastguard Worker        test_suite += '.exe'
434*8975f5c5SAndroid Build Coastguard Worker
435*8975f5c5SAndroid Build Coastguard Worker    # Find most recent binary in search paths.
436*8975f5c5SAndroid Build Coastguard Worker    newest_binary = None
437*8975f5c5SAndroid Build Coastguard Worker    newest_mtime = None
438*8975f5c5SAndroid Build Coastguard Worker
439*8975f5c5SAndroid Build Coastguard Worker    for path in glob.glob('out/*'):
440*8975f5c5SAndroid Build Coastguard Worker        binary_path = str(pathlib.Path(SCRIPT_DIR).parent.parent / path / test_suite)
441*8975f5c5SAndroid Build Coastguard Worker        if os.path.exists(binary_path):
442*8975f5c5SAndroid Build Coastguard Worker            binary_mtime = os.path.getmtime(binary_path)
443*8975f5c5SAndroid Build Coastguard Worker            if (newest_binary is None) or (binary_mtime > newest_mtime):
444*8975f5c5SAndroid Build Coastguard Worker                newest_binary = binary_path
445*8975f5c5SAndroid Build Coastguard Worker                newest_mtime = binary_mtime
446*8975f5c5SAndroid Build Coastguard Worker
447*8975f5c5SAndroid Build Coastguard Worker    if newest_binary:
448*8975f5c5SAndroid Build Coastguard Worker        logging.info('Found %s in %s' % (test_suite, os.path.dirname(newest_binary)))
449*8975f5c5SAndroid Build Coastguard Worker        return os.path.dirname(newest_binary)
450*8975f5c5SAndroid Build Coastguard Worker    return None
451*8975f5c5SAndroid Build Coastguard Worker
452*8975f5c5SAndroid Build Coastguard Worker
453*8975f5c5SAndroid Build Coastguard Workerdef _split_shard_samples(tests, samples_per_test, shard_count, shard_index):
454*8975f5c5SAndroid Build Coastguard Worker    test_samples = [(test, sample) for test in tests for sample in range(samples_per_test)]
455*8975f5c5SAndroid Build Coastguard Worker    shard_test_samples = _shard_tests(test_samples, shard_count, shard_index)
456*8975f5c5SAndroid Build Coastguard Worker    return [test for (test, sample) in shard_test_samples]
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Worker
459*8975f5c5SAndroid Build Coastguard Workerdef _should_lock_gpu_clocks():
460*8975f5c5SAndroid Build Coastguard Worker    if not angle_test_util.IsWindows():
461*8975f5c5SAndroid Build Coastguard Worker        return False
462*8975f5c5SAndroid Build Coastguard Worker
463*8975f5c5SAndroid Build Coastguard Worker    try:
464*8975f5c5SAndroid Build Coastguard Worker        gpu_info = subprocess.check_output(
465*8975f5c5SAndroid Build Coastguard Worker            ['nvidia-smi', '--query-gpu=gpu_name', '--format=csv,noheader']).decode()
466*8975f5c5SAndroid Build Coastguard Worker    except FileNotFoundError:
467*8975f5c5SAndroid Build Coastguard Worker        # expected in some cases, e.g. non-nvidia bots
468*8975f5c5SAndroid Build Coastguard Worker        return False
469*8975f5c5SAndroid Build Coastguard Worker
470*8975f5c5SAndroid Build Coastguard Worker    logging.info('nvidia-smi --query-gpu=gpu_name output: %s' % gpu_info)
471*8975f5c5SAndroid Build Coastguard Worker
472*8975f5c5SAndroid Build Coastguard Worker    return gpu_info.strip() == 'GeForce GTX 1660'
473*8975f5c5SAndroid Build Coastguard Worker
474*8975f5c5SAndroid Build Coastguard Worker
475*8975f5c5SAndroid Build Coastguard Workerdef _log_nvidia_gpu_temperature():
476*8975f5c5SAndroid Build Coastguard Worker    t = subprocess.check_output(
477*8975f5c5SAndroid Build Coastguard Worker        ['nvidia-smi', '--query-gpu=temperature.gpu', '--format=csv,noheader']).decode().strip()
478*8975f5c5SAndroid Build Coastguard Worker    logging.info('Current GPU temperature: %s ' % t)
479*8975f5c5SAndroid Build Coastguard Worker
480*8975f5c5SAndroid Build Coastguard Worker
481*8975f5c5SAndroid Build Coastguard Worker@contextlib.contextmanager
482*8975f5c5SAndroid Build Coastguard Workerdef _maybe_lock_gpu_clocks():
483*8975f5c5SAndroid Build Coastguard Worker    if not _should_lock_gpu_clocks():
484*8975f5c5SAndroid Build Coastguard Worker        yield
485*8975f5c5SAndroid Build Coastguard Worker        return
486*8975f5c5SAndroid Build Coastguard Worker
487*8975f5c5SAndroid Build Coastguard Worker    # Lock to 1410Mhz (`nvidia-smi --query-supported-clocks=gr --format=csv`)
488*8975f5c5SAndroid Build Coastguard Worker    lgc_out = subprocess.check_output(['nvidia-smi', '--lock-gpu-clocks=1410,1410']).decode()
489*8975f5c5SAndroid Build Coastguard Worker    logging.info('Lock GPU clocks output: %s' % lgc_out)
490*8975f5c5SAndroid Build Coastguard Worker    _log_nvidia_gpu_temperature()
491*8975f5c5SAndroid Build Coastguard Worker    try:
492*8975f5c5SAndroid Build Coastguard Worker        yield
493*8975f5c5SAndroid Build Coastguard Worker    finally:
494*8975f5c5SAndroid Build Coastguard Worker        rgc_out = subprocess.check_output(['nvidia-smi', '--reset-gpu-clocks']).decode()
495*8975f5c5SAndroid Build Coastguard Worker        logging.info('Reset GPU clocks output: %s' % rgc_out)
496*8975f5c5SAndroid Build Coastguard Worker        _log_nvidia_gpu_temperature()
497*8975f5c5SAndroid Build Coastguard Worker
498*8975f5c5SAndroid Build Coastguard Worker
499*8975f5c5SAndroid Build Coastguard Workerdef main():
500*8975f5c5SAndroid Build Coastguard Worker    parser = argparse.ArgumentParser()
501*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument('--isolated-script-test-output', type=str)
502*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument('--isolated-script-test-perf-output', type=str)
503*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
504*8975f5c5SAndroid Build Coastguard Worker        '-f', '--filter', '--isolated-script-test-filter', type=str, help='Test filter.')
505*8975f5c5SAndroid Build Coastguard Worker    suite_group = parser.add_mutually_exclusive_group()
506*8975f5c5SAndroid Build Coastguard Worker    suite_group.add_argument(
507*8975f5c5SAndroid Build Coastguard Worker        '--test-suite', '--suite', help='Test suite to run.', default=DEFAULT_TEST_SUITE)
508*8975f5c5SAndroid Build Coastguard Worker    suite_group.add_argument(
509*8975f5c5SAndroid Build Coastguard Worker        '-T',
510*8975f5c5SAndroid Build Coastguard Worker        '--trace-tests',
511*8975f5c5SAndroid Build Coastguard Worker        help='Run with the angle_trace_tests test suite.',
512*8975f5c5SAndroid Build Coastguard Worker        action='store_true')
513*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument('--xvfb', help='Use xvfb.', action='store_true')
514*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
515*8975f5c5SAndroid Build Coastguard Worker        '--shard-count',
516*8975f5c5SAndroid Build Coastguard Worker        help='Number of shards for test splitting. Default is 1.',
517*8975f5c5SAndroid Build Coastguard Worker        type=int,
518*8975f5c5SAndroid Build Coastguard Worker        default=1)
519*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
520*8975f5c5SAndroid Build Coastguard Worker        '--shard-index',
521*8975f5c5SAndroid Build Coastguard Worker        help='Index of the current shard for test splitting. Default is 0.',
522*8975f5c5SAndroid Build Coastguard Worker        type=int,
523*8975f5c5SAndroid Build Coastguard Worker        default=0)
524*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
525*8975f5c5SAndroid Build Coastguard Worker        '-l', '--log', help='Log output level. Default is %s.' % DEFAULT_LOG, default=DEFAULT_LOG)
526*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
527*8975f5c5SAndroid Build Coastguard Worker        '-s',
528*8975f5c5SAndroid Build Coastguard Worker        '--samples-per-test',
529*8975f5c5SAndroid Build Coastguard Worker        help='Number of samples to run per test. Default is %d.' % DEFAULT_SAMPLES,
530*8975f5c5SAndroid Build Coastguard Worker        type=int,
531*8975f5c5SAndroid Build Coastguard Worker        default=DEFAULT_SAMPLES)
532*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
533*8975f5c5SAndroid Build Coastguard Worker        '-t',
534*8975f5c5SAndroid Build Coastguard Worker        '--trials-per-sample',
535*8975f5c5SAndroid Build Coastguard Worker        help='Number of trials to run per sample. Default is %d.' % DEFAULT_TRIALS,
536*8975f5c5SAndroid Build Coastguard Worker        type=int,
537*8975f5c5SAndroid Build Coastguard Worker        default=DEFAULT_TRIALS)
538*8975f5c5SAndroid Build Coastguard Worker    trial_group = parser.add_mutually_exclusive_group()
539*8975f5c5SAndroid Build Coastguard Worker    trial_group.add_argument(
540*8975f5c5SAndroid Build Coastguard Worker        '--steps-per-trial', help='Fixed number of steps to run per trial.', type=int)
541*8975f5c5SAndroid Build Coastguard Worker    trial_group.add_argument(
542*8975f5c5SAndroid Build Coastguard Worker        '--trial-time',
543*8975f5c5SAndroid Build Coastguard Worker        help='Number of seconds to run per trial. Default is %d.' % DEFAULT_TRIAL_TIME,
544*8975f5c5SAndroid Build Coastguard Worker        type=int,
545*8975f5c5SAndroid Build Coastguard Worker        default=DEFAULT_TRIAL_TIME)
546*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
547*8975f5c5SAndroid Build Coastguard Worker        '--max-errors',
548*8975f5c5SAndroid Build Coastguard Worker        help='After this many errors, abort the run. Default is %d.' % DEFAULT_MAX_ERRORS,
549*8975f5c5SAndroid Build Coastguard Worker        type=int,
550*8975f5c5SAndroid Build Coastguard Worker        default=DEFAULT_MAX_ERRORS)
551*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
552*8975f5c5SAndroid Build Coastguard Worker        '--smoke-test-mode', help='Do a quick run to validate correctness.', action='store_true')
553*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
554*8975f5c5SAndroid Build Coastguard Worker        '--show-test-stdout', help='Prints all test stdout during execution.', action='store_true')
555*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
556*8975f5c5SAndroid Build Coastguard Worker        '--perf-counters', help='Colon-separated list of extra perf counter metrics.')
557*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
558*8975f5c5SAndroid Build Coastguard Worker        '-a',
559*8975f5c5SAndroid Build Coastguard Worker        '--auto-dir',
560*8975f5c5SAndroid Build Coastguard Worker        help='Run with the most recent test suite found in the build directories.',
561*8975f5c5SAndroid Build Coastguard Worker        action='store_true')
562*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
563*8975f5c5SAndroid Build Coastguard Worker        '--split-shard-samples',
564*8975f5c5SAndroid Build Coastguard Worker        help='Attempt to mitigate variance between machines by splitting samples between shards.',
565*8975f5c5SAndroid Build Coastguard Worker        action='store_true')
566*8975f5c5SAndroid Build Coastguard Worker    parser.add_argument(
567*8975f5c5SAndroid Build Coastguard Worker        '--custom-throttling-temp',
568*8975f5c5SAndroid Build Coastguard Worker        help='Android: custom thermal throttling with limit set to this temperature (off by default)',
569*8975f5c5SAndroid Build Coastguard Worker        type=float)
570*8975f5c5SAndroid Build Coastguard Worker
571*8975f5c5SAndroid Build Coastguard Worker    args, extra_flags = parser.parse_known_args()
572*8975f5c5SAndroid Build Coastguard Worker
573*8975f5c5SAndroid Build Coastguard Worker    if args.trace_tests:
574*8975f5c5SAndroid Build Coastguard Worker        args.test_suite = angle_test_util.ANGLE_TRACE_TEST_SUITE
575*8975f5c5SAndroid Build Coastguard Worker
576*8975f5c5SAndroid Build Coastguard Worker    angle_test_util.SetupLogging(args.log.upper())
577*8975f5c5SAndroid Build Coastguard Worker
578*8975f5c5SAndroid Build Coastguard Worker    start_time = time.time()
579*8975f5c5SAndroid Build Coastguard Worker
580*8975f5c5SAndroid Build Coastguard Worker    # Use fast execution for smoke test mode.
581*8975f5c5SAndroid Build Coastguard Worker    if args.smoke_test_mode:
582*8975f5c5SAndroid Build Coastguard Worker        args.steps_per_trial = 1
583*8975f5c5SAndroid Build Coastguard Worker        args.trials_per_sample = 1
584*8975f5c5SAndroid Build Coastguard Worker        args.samples_per_test = 1
585*8975f5c5SAndroid Build Coastguard Worker
586*8975f5c5SAndroid Build Coastguard Worker    env = os.environ.copy()
587*8975f5c5SAndroid Build Coastguard Worker
588*8975f5c5SAndroid Build Coastguard Worker    if angle_test_util.HasGtestShardsAndIndex(env):
589*8975f5c5SAndroid Build Coastguard Worker        args.shard_count, args.shard_index = angle_test_util.PopGtestShardsAndIndex(env)
590*8975f5c5SAndroid Build Coastguard Worker
591*8975f5c5SAndroid Build Coastguard Worker    if args.auto_dir:
592*8975f5c5SAndroid Build Coastguard Worker        test_suite_dir = _find_test_suite_directory(args.test_suite)
593*8975f5c5SAndroid Build Coastguard Worker        if not test_suite_dir:
594*8975f5c5SAndroid Build Coastguard Worker            logging.fatal('Could not find test suite: %s' % args.test_suite)
595*8975f5c5SAndroid Build Coastguard Worker            return EXIT_FAILURE
596*8975f5c5SAndroid Build Coastguard Worker        else:
597*8975f5c5SAndroid Build Coastguard Worker            os.chdir(test_suite_dir)
598*8975f5c5SAndroid Build Coastguard Worker
599*8975f5c5SAndroid Build Coastguard Worker    angle_test_util.Initialize(args.test_suite)
600*8975f5c5SAndroid Build Coastguard Worker
601*8975f5c5SAndroid Build Coastguard Worker    # Get test list
602*8975f5c5SAndroid Build Coastguard Worker    exit_code, output, _ = _run_test_suite(args, ['--list-tests', '--verbose'] + extra_flags, env)
603*8975f5c5SAndroid Build Coastguard Worker    if exit_code != EXIT_SUCCESS:
604*8975f5c5SAndroid Build Coastguard Worker        logging.fatal('Could not find test list from test output:\n%s' % output)
605*8975f5c5SAndroid Build Coastguard Worker        sys.exit(EXIT_FAILURE)
606*8975f5c5SAndroid Build Coastguard Worker    tests = angle_test_util.GetTestsFromOutput(output)
607*8975f5c5SAndroid Build Coastguard Worker
608*8975f5c5SAndroid Build Coastguard Worker    if args.filter:
609*8975f5c5SAndroid Build Coastguard Worker        tests = angle_test_util.FilterTests(tests, args.filter)
610*8975f5c5SAndroid Build Coastguard Worker
611*8975f5c5SAndroid Build Coastguard Worker    # Get tests for this shard (if using sharding args)
612*8975f5c5SAndroid Build Coastguard Worker    if args.split_shard_samples and args.shard_count >= args.samples_per_test:
613*8975f5c5SAndroid Build Coastguard Worker        tests = _split_shard_samples(tests, args.samples_per_test, args.shard_count,
614*8975f5c5SAndroid Build Coastguard Worker                                     args.shard_index)
615*8975f5c5SAndroid Build Coastguard Worker        assert (len(set(tests)) == len(tests))
616*8975f5c5SAndroid Build Coastguard Worker        args.samples_per_test = 1
617*8975f5c5SAndroid Build Coastguard Worker    else:
618*8975f5c5SAndroid Build Coastguard Worker        tests = _shard_tests(tests, args.shard_count, args.shard_index)
619*8975f5c5SAndroid Build Coastguard Worker
620*8975f5c5SAndroid Build Coastguard Worker    if not tests:
621*8975f5c5SAndroid Build Coastguard Worker        logging.error('No tests to run.')
622*8975f5c5SAndroid Build Coastguard Worker        return EXIT_FAILURE
623*8975f5c5SAndroid Build Coastguard Worker
624*8975f5c5SAndroid Build Coastguard Worker    logging.info('Running %d test%s' % (len(tests), 's' if len(tests) > 1 else ' '))
625*8975f5c5SAndroid Build Coastguard Worker
626*8975f5c5SAndroid Build Coastguard Worker    try:
627*8975f5c5SAndroid Build Coastguard Worker        with _maybe_lock_gpu_clocks():
628*8975f5c5SAndroid Build Coastguard Worker            results, histograms, metrics = _run_tests(tests, args, extra_flags, env)
629*8975f5c5SAndroid Build Coastguard Worker    except _MaxErrorsException:
630*8975f5c5SAndroid Build Coastguard Worker        logging.error('Error count exceeded max errors (%d). Aborting.' % args.max_errors)
631*8975f5c5SAndroid Build Coastguard Worker        return EXIT_FAILURE
632*8975f5c5SAndroid Build Coastguard Worker
633*8975f5c5SAndroid Build Coastguard Worker    for test in tests:
634*8975f5c5SAndroid Build Coastguard Worker        assert results.has_result(test)
635*8975f5c5SAndroid Build Coastguard Worker
636*8975f5c5SAndroid Build Coastguard Worker    if args.isolated_script_test_output:
637*8975f5c5SAndroid Build Coastguard Worker        results.save_to_output_file(args.test_suite, args.isolated_script_test_output)
638*8975f5c5SAndroid Build Coastguard Worker
639*8975f5c5SAndroid Build Coastguard Worker        # Uses special output files to match the merge script.
640*8975f5c5SAndroid Build Coastguard Worker        _save_extra_output_files(args, results, histograms, metrics)
641*8975f5c5SAndroid Build Coastguard Worker
642*8975f5c5SAndroid Build Coastguard Worker    if args.isolated_script_test_perf_output:
643*8975f5c5SAndroid Build Coastguard Worker        with open(args.isolated_script_test_perf_output, 'w') as out_file:
644*8975f5c5SAndroid Build Coastguard Worker            out_file.write(json.dumps(histograms.AsDicts(), indent=2))
645*8975f5c5SAndroid Build Coastguard Worker
646*8975f5c5SAndroid Build Coastguard Worker    end_time = time.time()
647*8975f5c5SAndroid Build Coastguard Worker    logging.info('Elapsed time: %.2lf seconds.' % (end_time - start_time))
648*8975f5c5SAndroid Build Coastguard Worker
649*8975f5c5SAndroid Build Coastguard Worker    if results.has_failures():
650*8975f5c5SAndroid Build Coastguard Worker        return EXIT_FAILURE
651*8975f5c5SAndroid Build Coastguard Worker    return EXIT_SUCCESS
652*8975f5c5SAndroid Build Coastguard Worker
653*8975f5c5SAndroid Build Coastguard Worker
654*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__':
655*8975f5c5SAndroid Build Coastguard Worker    sys.exit(main())
656