js/src/devtools/gc/gc-test.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/devtools/gc/gc-test.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,166 @@
     1.4 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 +
     1.8 +# Works with python2.6
     1.9 +
    1.10 +import datetime, os, re, sys, traceback
    1.11 +import math, string, copy, json
    1.12 +import subprocess
    1.13 +from subprocess import *
    1.14 +from operator import itemgetter
    1.15 +
    1.16 +class Test:
    1.17 +    def __init__(self, path, name):
    1.18 +        self.path = path
    1.19 +        self.name = name
    1.20 +
    1.21 +    @classmethod
    1.22 +    def from_file(cls, path, name, options):
    1.23 +        return cls(path, name)
    1.24 +
    1.25 +def find_tests(dir, substring = None):
    1.26 +    ans = []
    1.27 +    for dirpath, dirnames, filenames in os.walk(dir):
    1.28 +        if dirpath == '.':
    1.29 +            continue
    1.30 +        for filename in filenames:
    1.31 +            if not filename.endswith('.js'):
    1.32 +                continue
    1.33 +            test = os.path.join(dirpath, filename)
    1.34 +            if substring is None or substring in os.path.relpath(test, dir):
    1.35 +                ans.append([test, filename])
    1.36 +    return ans
    1.37 +
    1.38 +def get_test_cmd(path):
    1.39 +    return [ JS, '-f', path ]
    1.40 +
    1.41 +def avg(seq):
    1.42 +    return sum(seq) / len(seq)
    1.43 +
    1.44 +def stddev(seq, mean):
    1.45 +    diffs = ((float(item) - mean) ** 2 for item in seq)
    1.46 +    return math.sqrt(sum(diffs) / len(seq))
    1.47 +
    1.48 +def run_test(test):
    1.49 +    env = os.environ.copy()
    1.50 +    env['MOZ_GCTIMER'] = 'stderr'
    1.51 +    cmd = get_test_cmd(test.path)
    1.52 +    total = []
    1.53 +    mark = []
    1.54 +    sweep = []
    1.55 +    close_fds = sys.platform != 'win32'
    1.56 +    p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=close_fds, env=env)
    1.57 +    out, err = p.communicate()
    1.58 +    out, err = out.decode(), err.decode()
    1.59 +
    1.60 +    float_array = [float(_) for _ in err.split()]
    1.61 +    
    1.62 +    if len(float_array) == 0:
    1.63 +        print('Error: No data from application. Configured with --enable-gctimer?')
    1.64 +        sys.exit(1)
    1.65 +
    1.66 +    for i, currItem in enumerate(float_array):
    1.67 +        if (i % 3 == 0):
    1.68 +            total.append(currItem)
    1.69 +        else:
    1.70 +            if (i % 3 == 1):
    1.71 +                mark.append(currItem)
    1.72 +            else:
    1.73 +                sweep.append(currItem)
    1.74 +
    1.75 +    return max(total), avg(total), max(mark), avg(mark), max(sweep), avg(sweep)
    1.76 +
    1.77 +def run_tests(tests, test_dir):
    1.78 +    bench_map = {}
    1.79 +
    1.80 +    try:
    1.81 +        for i, test in enumerate(tests):
    1.82 +            filename_str = '"%s"' % test.name
    1.83 +            TMax, TAvg, MMax, MAvg, SMax, SAvg = run_test(test)
    1.84 +            bench_map[test.name] = [TMax, TAvg, MMax, MAvg, SMax, SAvg]
    1.85 +            fmt = '%20s: {"TMax": %4.1f, "TAvg": %4.1f, "MMax": %4.1f, "MAvg": %4.1f, "SMax": %4.1f, "SAvg": %4.1f}'
    1.86 +            if (i != len(tests) - 1):
    1.87 +                fmt += ','
    1.88 +            print(fmt %(filename_str ,TMax, TAvg, MMax, MAvg, SMax, MAvg))
    1.89 +    except KeyboardInterrupt:
    1.90 +        print('fail')
    1.91 +
    1.92 +    return dict((filename, dict(TMax=TMax, TAvg=TAvg, MMax=MMax, MAvg=MAvg, SMax=SMax, SAvg=SAvg))
    1.93 +            for filename, (TMax, TAvg, MMax, MAvg, SMax, SAvg) in bench_map.iteritems())
    1.94 +
    1.95 +def compare(current, baseline):
    1.96 +    percent_speedups = []
    1.97 +    for key, current_result in current.iteritems():
    1.98 +        try:
    1.99 +            baseline_result = baseline[key]
   1.100 +        except KeyError:
   1.101 +            print key, 'missing from baseline'
   1.102 +            continue
   1.103 +
   1.104 +        val_getter = itemgetter('TMax', 'TAvg', 'MMax', 'MAvg', 'SMax', 'SAvg')
   1.105 +        BTMax, BTAvg, BMMax, BMAvg, BSMax, BSAvg = val_getter(baseline_result)
   1.106 +        CTMax, CTAvg, CMMax, CMAvg, CSMax, CSAvg = val_getter(current_result)
   1.107 +
   1.108 +        fmt = '%30s: %s'
   1.109 +        if CTAvg <= BTAvg:
   1.110 +            speedup = (CTAvg / BTAvg - 1) * 100
   1.111 +            result = 'faster: %6.2f < baseline %6.2f (%+6.2f%%)' % \
   1.112 +                    (CTAvg, BTAvg, speedup)
   1.113 +            percent_speedups.append(speedup)
   1.114 +        else:
   1.115 +            slowdown = (CTAvg / BTAvg - 1) * 100
   1.116 +            result = 'SLOWER: %6.2f > baseline %6.2f (%+6.2f%%) ' % \
   1.117 +                    (CTAvg, BTAvg, slowdown)
   1.118 +            percent_speedups.append(slowdown)
   1.119 +        print '%30s: %s' % (key, result)
   1.120 +    if percent_speedups:
   1.121 +        print 'Average speedup: %.2f%%' % avg(percent_speedups)
   1.122 +
   1.123 +if __name__ == '__main__':
   1.124 +    script_path = os.path.abspath(__file__)
   1.125 +    script_dir = os.path.dirname(script_path)
   1.126 +    test_dir = os.path.join(script_dir, 'tests')
   1.127 +
   1.128 +    from optparse import OptionParser
   1.129 +    op = OptionParser(usage='%prog [options] JS_SHELL [TESTS]')
   1.130 +
   1.131 +    op.add_option('-b', '--baseline', metavar='JSON_PATH',
   1.132 +            dest='baseline_path', help='json file with baseline values to '
   1.133 +            'compare against')
   1.134 +
   1.135 +    (OPTIONS, args) = op.parse_args()
   1.136 +    if len(args) < 1:
   1.137 +        op.error('missing JS_SHELL argument')
   1.138 +    # We need to make sure we are using backslashes on Windows.
   1.139 +    JS, test_args = os.path.normpath(args[0]), args[1:]
   1.140 +
   1.141 +    test_list = []
   1.142 +    bench_map = {}
   1.143 +
   1.144 +    test_list = find_tests(test_dir)
   1.145 +
   1.146 +    if not test_list:
   1.147 +        print >> sys.stderr, "No tests found matching command line arguments."
   1.148 +        sys.exit(0)
   1.149 +
   1.150 +    test_list = [ Test.from_file(tst, name, OPTIONS) for tst, name in test_list ]
   1.151 +
   1.152 +    try:
   1.153 +        print("{")
   1.154 +        bench_map = run_tests(test_list, test_dir)
   1.155 +        print("}")
   1.156 +
   1.157 +    except OSError:
   1.158 +        if not os.path.exists(JS):
   1.159 +            print >> sys.stderr, "JS shell argument: file does not exist: '%s'"%JS
   1.160 +            sys.exit(1)
   1.161 +        else:
   1.162 +            raise
   1.163 +
   1.164 +    if OPTIONS.baseline_path:
   1.165 +        baseline_map = []
   1.166 +        fh = open(OPTIONS.baseline_path, 'r')
   1.167 +        baseline_map = json.load(fh)
   1.168 +        fh.close()
   1.169 +        compare(current=bench_map, baseline=baseline_map)

mercurial