Source

benchmarks / saveresults.py

Full commit
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#######################################################
# This script saves result data                       #
# It expects the format of unladen swallow's perf.py  #
#######################################################

"""
Upload a json file generated by runner.py.

Revision, name and host are required.

Example usage:

  $ ./saveresults.py result.json -r '45757:fabe4fc0dc08' -n pypy-c-jit -H tannit
  
  OR
  
  $ ./saveresults.py result.json -r '45757:fabe4fc0dc08' -n pypy-c-jit-64 -H tannit

"""

import sys
import urllib, urllib2, time
from datetime import datetime
import optparse

SPEEDURL = "http://speed.pypy.org/"

def save(project, revision, results, options, interpreter, host, testing=False,
         changed=True, branch='default'):
    testparams = []
    #Parse data
    data = {}
    error = 0
        
    for b in results:
        bench_name = b[0]
        res_type = b[1]
        results = b[2]
        value = 0
        if res_type == "SimpleComparisonResult":
            if changed:
                value = results['changed_time']
            else:
                value = results['base_time']
        elif res_type == "ComparisonResult":
            if changed:
                value = results['avg_changed']
            else:
                value = results['avg_base']
        elif res_type == "RawResult":
            if changed:
                value = results["changed_times"]
            else:
                value = results["base_times"]
            if value:
                assert len(value) == 1
                value = value[0]
        else:
            print("ERROR: result type unknown " + b[1])
            return 1
        data = {
            'commitid': revision,
            'project': project,
            'executable': interpreter,
            'benchmark': bench_name,
            'environment': host,
            'result_value': value,
            'branch': branch,
        }
        if value is None:
            print "Ignoring skipped result", data
            continue
        if res_type == "ComparisonResult":
            if changed:
                data['std_dev'] = results['std_changed']
            else:
                data['std_dev'] = results['std_base']
        if testing: testparams.append(data)
        else: error |= send(data)
    if error:
        raise IOError("Saving failed.  See messages above.")
    if testing: return testparams
    else: return 0
    
def send(data):
    #save results
    params = urllib.urlencode(data)
    f = None
    response = "None"
    info = str(datetime.today()) + ": Saving result for " + data['executable'] + " revision "
    info += str(data['commitid']) + ", benchmark " + data['benchmark']
    print(info)
    try:
        retries = [1, 2, 3, 6]
        while True:
            try:
                f = urllib2.urlopen(SPEEDURL + 'result/add/', params)
                response = f.read()
                f.close()
                break
            except urllib2.URLError:
                if not retries:
                    raise
                d = retries.pop(0)
                print "retrying in %d seconds..." % d
                time.sleep(d)
    except urllib2.URLError, e:
        if hasattr(e, 'reason'):
            response = '\n  We failed to reach a server\n'
            response += '  Reason: ' + str(e.reason)
        elif hasattr(e, 'code'):
            response = '\n  The server couldn\'t fulfill the request'
        response = "".join([response] + e.readlines())
        print response
        with open('error.html', 'w') as error_file:
            error_file.write(response)
        print("Server (%s) response written to error.html" % (SPEEDURL,))
        print('  Error code: %s\n' % (e,))
        return 1
    print "saved correctly!\n"
    return 0


def main(jsonfile, options):
    import simplejson
    with open(jsonfile) as f:
        data = simplejson.load(f)
    results = data['results']
    print 'uploading results...',
    save('PyPy', options.revision, results, '', options.name, options.host,
         changed=options.changed)
    print 'done'


if __name__ == '__main__':
    parser = optparse.OptionParser(usage="%prog result.json [options]")
    parser.add_option('-r', '--revision', dest='revision', default=None, type=str)
    parser.add_option('-n', '--name', dest='name', default=None, type=str)
    parser.add_option('-H', '--host', dest='host', default=None, type=str)
    parser.add_option('-b', '--baseline', dest='changed', default=True,
                      action='store_false',
                      help='upload the results as baseline instead of changed')
    parser.format_description = lambda fmt: __doc__
    parser.description = __doc__
    options, args = parser.parse_args()
    if options.revision is None or options.name is None or options.host is None or \
            len(args) != 1:
        parser.print_help()
        sys.exit(2)
    main(args[0], options)