diff options
Diffstat (limited to 'android_bench_suite/fix_skia_results.py')
-rwxr-xr-x | android_bench_suite/fix_skia_results.py | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/android_bench_suite/fix_skia_results.py b/android_bench_suite/fix_skia_results.py new file mode 100755 index 00000000..6eec6ccf --- /dev/null +++ b/android_bench_suite/fix_skia_results.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python2 +# +# Copyright 2017 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# pylint: disable=cros-logging-import +"""Transforms skia benchmark results to ones that crosperf can understand.""" + +from __future__ import print_function + +import itertools +import logging +import json +import sys + +# Turn the logging level to INFO before importing other autotest +# code, to avoid having failed import logging messages confuse the +# test_droid user. +logging.basicConfig(level=logging.INFO) + +# All of the results we care about, by name. +# Each of these *must* end in _ns, _us, _ms, or _s, since all the metrics we +# collect (so far) are related to time, and we alter the results based on the +# suffix of these strings (so we don't have 0.000421ms per sample, for example) +_RESULT_RENAMES = { + 'memset32_100000_640_480_nonrendering': 'memset_time_ms', + 'path_equality_50%_640_480_nonrendering': 'path_equality_ns', + 'sort_qsort_backward_640_480_nonrendering': 'qsort_us' +} + + +def _GetFamiliarName(name): + r = _RESULT_RENAMES[name] + return r if r else name + + +def _IsResultInteresting(name): + return name in _RESULT_RENAMES + + +def _GetTimeMultiplier(label_name): + """Given a time (in milliseconds), normalize it to what label_name expects. + + "What label_name expects" meaning "we pattern match against the last few + non-space chars in label_name." + + This expects the time unit to be separated from anything else by '_'. + """ + ms_mul = 1000 * 1000. + endings = [('_ns', 1), ('_us', 1000), ('_ms', ms_mul), ('_s', ms_mul * 1000)] + for end, mul in endings: + if label_name.endswith(end): + return ms_mul / mul + raise ValueError('Unknown ending in "%s"; expecting one of %s' % + (label_name, [end for end, _ in endings])) + + +def _GetTimeDenom(ms): + """Given a list of times (in milliseconds), find a sane time unit for them. + + Returns the unit name, and `ms` normalized to that time unit. + + >>> _GetTimeDenom([1, 2, 3]) + ('ms', [1.0, 2.0, 3.0]) + >>> _GetTimeDenom([.1, .2, .3]) + ('us', [100.0, 200.0, 300.0]) + """ + + ms_mul = 1000 * 1000 + units = [('us', 1000), ('ms', ms_mul), ('s', ms_mul * 1000)] + for name, mul in reversed(units): + normalized = [float(t) * ms_mul / mul for t in ms] + average = sum(normalized) / len(normalized) + if all(n > 0.1 for n in normalized) and average >= 1: + return name, normalized + + normalized = [float(t) * ms_mul for t in ms] + return 'ns', normalized + + +def _TransformBenchmarks(raw_benchmarks): + # We get {"results": {"bench_name": Results}} + # where + # Results = {"config_name": {"samples": [float], etc.}} + # + # We want {"data": {"skia": [[BenchmarkData]]}, + # "platforms": ["platform1, ..."]} + # where + # BenchmarkData = {"bench_name": bench_samples[N], ..., "retval": 0} + # + # Note that retval is awkward -- crosperf's JSON reporter reports the result + # as a failure if it's not there. Everything else treats it like a + # statistic... + benchmarks = raw_benchmarks['results'] + results = [] + for bench_name, bench_result in benchmarks.iteritems(): + try: + for cfg_name, keyvals in bench_result.iteritems(): + # Some benchmarks won't have timing data (either it won't exist at all, + # or it'll be empty); skip them. + samples = keyvals.get('samples') + if not samples: + continue + + bench_name = '%s_%s' % (bench_name, cfg_name) + if not _IsResultInteresting(bench_name): + continue + + friendly_name = _GetFamiliarName(bench_name) + if len(results) < len(samples): + results.extend({ + 'retval': 0 + } for _ in xrange(len(samples) - len(results))) + + time_mul = _GetTimeMultiplier(friendly_name) + for sample, app in itertools.izip(samples, results): + assert friendly_name not in app + app[friendly_name] = sample * time_mul + except (KeyError, ValueError) as e: + logging.error('While converting "%s" (key: %s): %s', + bench_result, bench_name, e.message) + raise + + # Realistically, [results] should be multiple results, where each entry in the + # list is the result for a different label. Because we only deal with one + # label at the moment, we need to wrap it in its own list. + return results + + +if __name__ == '__main__': + + def _GetUserFile(argv): + if not argv or argv[0] == '-': + return sys.stdin + return open(argv[0]) + + def _Main(): + with _GetUserFile(sys.argv[1:]) as in_file: + obj = json.load(in_file) + output = _TransformBenchmarks(obj) + json.dump(output, sys.stdout) + + _Main() |