Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | # This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
michael@0 | 4 | |
michael@0 | 5 | # Works with python2.6 |
michael@0 | 6 | |
michael@0 | 7 | import datetime, os, re, sys, traceback |
michael@0 | 8 | import math, string, copy, json |
michael@0 | 9 | import subprocess |
michael@0 | 10 | from subprocess import * |
michael@0 | 11 | from operator import itemgetter |
michael@0 | 12 | |
michael@0 | 13 | class Test: |
michael@0 | 14 | def __init__(self, path, name): |
michael@0 | 15 | self.path = path |
michael@0 | 16 | self.name = name |
michael@0 | 17 | |
michael@0 | 18 | @classmethod |
michael@0 | 19 | def from_file(cls, path, name, options): |
michael@0 | 20 | return cls(path, name) |
michael@0 | 21 | |
michael@0 | 22 | def find_tests(dir, substring = None): |
michael@0 | 23 | ans = [] |
michael@0 | 24 | for dirpath, dirnames, filenames in os.walk(dir): |
michael@0 | 25 | if dirpath == '.': |
michael@0 | 26 | continue |
michael@0 | 27 | for filename in filenames: |
michael@0 | 28 | if not filename.endswith('.js'): |
michael@0 | 29 | continue |
michael@0 | 30 | test = os.path.join(dirpath, filename) |
michael@0 | 31 | if substring is None or substring in os.path.relpath(test, dir): |
michael@0 | 32 | ans.append([test, filename]) |
michael@0 | 33 | return ans |
michael@0 | 34 | |
michael@0 | 35 | def get_test_cmd(path): |
michael@0 | 36 | return [ JS, '-f', path ] |
michael@0 | 37 | |
michael@0 | 38 | def avg(seq): |
michael@0 | 39 | return sum(seq) / len(seq) |
michael@0 | 40 | |
michael@0 | 41 | def stddev(seq, mean): |
michael@0 | 42 | diffs = ((float(item) - mean) ** 2 for item in seq) |
michael@0 | 43 | return math.sqrt(sum(diffs) / len(seq)) |
michael@0 | 44 | |
michael@0 | 45 | def run_test(test): |
michael@0 | 46 | env = os.environ.copy() |
michael@0 | 47 | env['MOZ_GCTIMER'] = 'stderr' |
michael@0 | 48 | cmd = get_test_cmd(test.path) |
michael@0 | 49 | total = [] |
michael@0 | 50 | mark = [] |
michael@0 | 51 | sweep = [] |
michael@0 | 52 | close_fds = sys.platform != 'win32' |
michael@0 | 53 | p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env) |
michael@0 | 54 | out, err = p.communicate() |
michael@0 | 55 | out, err = out.decode(), err.decode() |
michael@0 | 56 | |
michael@0 | 57 | float_array = [float(_) for _ in err.split()] |
michael@0 | 58 | |
michael@0 | 59 | if len(float_array) == 0: |
michael@0 | 60 | print('Error: No data from application. Configured with --enable-gctimer?') |
michael@0 | 61 | sys.exit(1) |
michael@0 | 62 | |
michael@0 | 63 | for i, currItem in enumerate(float_array): |
michael@0 | 64 | if (i % 3 == 0): |
michael@0 | 65 | total.append(currItem) |
michael@0 | 66 | else: |
michael@0 | 67 | if (i % 3 == 1): |
michael@0 | 68 | mark.append(currItem) |
michael@0 | 69 | else: |
michael@0 | 70 | sweep.append(currItem) |
michael@0 | 71 | |
michael@0 | 72 | return max(total), avg(total), max(mark), avg(mark), max(sweep), avg(sweep) |
michael@0 | 73 | |
michael@0 | 74 | def run_tests(tests, test_dir): |
michael@0 | 75 | bench_map = {} |
michael@0 | 76 | |
michael@0 | 77 | try: |
michael@0 | 78 | for i, test in enumerate(tests): |
michael@0 | 79 | filename_str = '"%s"' % test.name |
michael@0 | 80 | TMax, TAvg, MMax, MAvg, SMax, SAvg = run_test(test) |
michael@0 | 81 | bench_map[test.name] = [TMax, TAvg, MMax, MAvg, SMax, SAvg] |
michael@0 | 82 | fmt = '%20s: {"TMax": %4.1f, "TAvg": %4.1f, "MMax": %4.1f, "MAvg": %4.1f, "SMax": %4.1f, "SAvg": %4.1f}' |
michael@0 | 83 | if (i != len(tests) - 1): |
michael@0 | 84 | fmt += ',' |
michael@0 | 85 | print(fmt %(filename_str ,TMax, TAvg, MMax, MAvg, SMax, MAvg)) |
michael@0 | 86 | except KeyboardInterrupt: |
michael@0 | 87 | print('fail') |
michael@0 | 88 | |
michael@0 | 89 | return dict((filename, dict(TMax=TMax, TAvg=TAvg, MMax=MMax, MAvg=MAvg, SMax=SMax, SAvg=SAvg)) |
michael@0 | 90 | for filename, (TMax, TAvg, MMax, MAvg, SMax, SAvg) in bench_map.iteritems()) |
michael@0 | 91 | |
michael@0 | 92 | def compare(current, baseline): |
michael@0 | 93 | percent_speedups = [] |
michael@0 | 94 | for key, current_result in current.iteritems(): |
michael@0 | 95 | try: |
michael@0 | 96 | baseline_result = baseline[key] |
michael@0 | 97 | except KeyError: |
michael@0 | 98 | print key, 'missing from baseline' |
michael@0 | 99 | continue |
michael@0 | 100 | |
michael@0 | 101 | val_getter = itemgetter('TMax', 'TAvg', 'MMax', 'MAvg', 'SMax', 'SAvg') |
michael@0 | 102 | BTMax, BTAvg, BMMax, BMAvg, BSMax, BSAvg = val_getter(baseline_result) |
michael@0 | 103 | CTMax, CTAvg, CMMax, CMAvg, CSMax, CSAvg = val_getter(current_result) |
michael@0 | 104 | |
michael@0 | 105 | fmt = '%30s: %s' |
michael@0 | 106 | if CTAvg <= BTAvg: |
michael@0 | 107 | speedup = (CTAvg / BTAvg - 1) * 100 |
michael@0 | 108 | result = 'faster: %6.2f < baseline %6.2f (%+6.2f%%)' % \ |
michael@0 | 109 | (CTAvg, BTAvg, speedup) |
michael@0 | 110 | percent_speedups.append(speedup) |
michael@0 | 111 | else: |
michael@0 | 112 | slowdown = (CTAvg / BTAvg - 1) * 100 |
michael@0 | 113 | result = 'SLOWER: %6.2f > baseline %6.2f (%+6.2f%%) ' % \ |
michael@0 | 114 | (CTAvg, BTAvg, slowdown) |
michael@0 | 115 | percent_speedups.append(slowdown) |
michael@0 | 116 | print '%30s: %s' % (key, result) |
michael@0 | 117 | if percent_speedups: |
michael@0 | 118 | print 'Average speedup: %.2f%%' % avg(percent_speedups) |
michael@0 | 119 | |
michael@0 | 120 | if __name__ == '__main__': |
michael@0 | 121 | script_path = os.path.abspath(__file__) |
michael@0 | 122 | script_dir = os.path.dirname(script_path) |
michael@0 | 123 | test_dir = os.path.join(script_dir, 'tests') |
michael@0 | 124 | |
michael@0 | 125 | from optparse import OptionParser |
michael@0 | 126 | op = OptionParser(usage='%prog [options] JS_SHELL [TESTS]') |
michael@0 | 127 | |
michael@0 | 128 | op.add_option('-b', '--baseline', metavar='JSON_PATH', |
michael@0 | 129 | dest='baseline_path', help='json file with baseline values to ' |
michael@0 | 130 | 'compare against') |
michael@0 | 131 | |
michael@0 | 132 | (OPTIONS, args) = op.parse_args() |
michael@0 | 133 | if len(args) < 1: |
michael@0 | 134 | op.error('missing JS_SHELL argument') |
michael@0 | 135 | # We need to make sure we are using backslashes on Windows. |
michael@0 | 136 | JS, test_args = os.path.normpath(args[0]), args[1:] |
michael@0 | 137 | |
michael@0 | 138 | test_list = [] |
michael@0 | 139 | bench_map = {} |
michael@0 | 140 | |
michael@0 | 141 | test_list = find_tests(test_dir) |
michael@0 | 142 | |
michael@0 | 143 | if not test_list: |
michael@0 | 144 | print >> sys.stderr, "No tests found matching command line arguments." |
michael@0 | 145 | sys.exit(0) |
michael@0 | 146 | |
michael@0 | 147 | test_list = [ Test.from_file(tst, name, OPTIONS) for tst, name in test_list ] |
michael@0 | 148 | |
michael@0 | 149 | try: |
michael@0 | 150 | print("{") |
michael@0 | 151 | bench_map = run_tests(test_list, test_dir) |
michael@0 | 152 | print("}") |
michael@0 | 153 | |
michael@0 | 154 | except OSError: |
michael@0 | 155 | if not os.path.exists(JS): |
michael@0 | 156 | print >> sys.stderr, "JS shell argument: file does not exist: '%s'"%JS |
michael@0 | 157 | sys.exit(1) |
michael@0 | 158 | else: |
michael@0 | 159 | raise |
michael@0 | 160 | |
michael@0 | 161 | if OPTIONS.baseline_path: |
michael@0 | 162 | baseline_map = [] |
michael@0 | 163 | fh = open(OPTIONS.baseline_path, 'r') |
michael@0 | 164 | baseline_map = json.load(fh) |
michael@0 | 165 | fh.close() |
michael@0 | 166 | compare(current=bench_map, baseline=baseline_map) |