#!/usr/bin/env python

"""This script computes the relative performance between python
implementations on a set of microbenchmarks. The script usually is started
with "./microbench.py python ./pypy" where pypy is a symlink to your pypy executable."""

import os, time, sys

try:
    import gc
except ImportError:
    if sys.platform.startswith('java'):
        import java.lang
        gccollect = java.lang.System.gc
    else:
        gccollect = lambda: None
else:
    gccollect = gc.collect

try:
    this_dir = os.path.dirname(__file__)
except NameError:
    this_dir = os.path.dirname(sys.argv[0])

microbenches = []
for fname in os.listdir(this_dir):
    if not fname.startswith('test_') or not fname.endswith('.py'):
        continue
    microbench = fname[:-3]
    microbenches.append(microbench)

def run(test_cases, fmt):
    MINIMUM_MICROBENCH_TIME = 1.0

    for microbench in microbenches:
        testmoddict = {}
        execfile(os.path.join(this_dir, microbench + '.py'), testmoddict)
        for k in [s for s in testmoddict if s.startswith('test_')] :
            if test_cases:
                for tc in test_cases:
                    if k.startswith(tc) or microbench.startswith(tc):
                        break
                else:
                    continue
            testcase_name = microbench + '.' + k + '()'
            testcase = testmoddict[k]
            gccollect()
            start = time.clock()
            n = 0
            duration = 0.0
            while duration < MINIMUM_MICROBENCH_TIME:
                testcase()
                n += 1
                duration = time.clock() - start
            print ('%s took ' + fmt +' seconds') % (testcase_name, duration / float(n))

if __name__ == '__main__':
    args = sys.argv[1:]
    if args[0].startswith('-F'):
        fmt = "%" + args[0][2:]
        args.pop(0)
        inner = True
    else:
        fmt = "%.2f"
        inner = False
        
    if '-k' in args:
        i = args.index('-k')
        executables = args[:i]
        test_cases  = args[i+1:]
        limit = '-k ' + ' '.join(test_cases)
    else:
        executables = args
        test_cases  = []
        limit = ''

    for n, exe in enumerate(executables):
        print 'exe:', exe
        data = [s for s in os.popen('%s %s -Fr %s 2>&1' %
            (exe, os.path.join(this_dir, 'microbench.py'), limit)).readlines()
                if not s.startswith('debug:')]
        benchdata = {}
        for d in data:
            try:
                testcase, took, duration, seconds = d.split()
            except ValueError:
                print >> sys.stderr, 'Unexpected output:\n%s' % d
                sys.exit(1)
            benchdata[testcase] = float(duration)
        if n == 0:
            benchdata_ref = benchdata
        else:
            result = []
            for k, v in benchdata.iteritems():
                result.append( (v / benchdata_ref[k], k) )
            result.sort()
            for slowdown, testcase in result:
                print '%5.2fx slower on %s' % (slowdown, testcase)
    if not inner and n == 0:
        result = []
        for k, v in benchdata.iteritems():
            result.append((v, k))
        result.sort()
        for v, testcase in result:
            print 'took %5.5fs for %s' % (v, testcase)
        
    if not executables:
        run(test_cases, fmt)


