@@ -38,7 +38,7 @@
{% endif%}{% if units.hasmin %}| {{ row.val_min|floatformat:units.precission }} |
{% endif%}{% if units.hasmax %}{{ row.val_max|floatformat:units.precission }} |
{% endif%}{{ row.change|percentage }} |
- {% ifequal row.trend "-" %}-{% else %}{{ row.trend|floatformat:2 }}%{% endifequal %} |
+ {% if row.trend == "-" %}-{% else %}{{ row.trend|floatformat:2 }}%{% endif %} |
{% endfor %}
{% endfor %}
diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html
index 14139577..d78550db 100644
--- a/codespeed/templates/codespeed/comparison.html
+++ b/codespeed/templates/codespeed/comparison.html
@@ -6,7 +6,6 @@
{% block extra_head %}
{{ block.super }}
-
-
About this site
-
<description of site and what benchmarks that are run>
-
This site runs on top of Django and Codespeed
-
About the benchmarks
-
The code can be found here.
-
About MyProject
-
<Description of the main project>
-
Main website: MySite
-
About Codespeed
-Codespeed is a web application to monitor and analyze the performance of your code.
-
Code: github.com/tobami/codespeed
-
Wiki: wiki.github.com/tobami/codespeed/
-
Contact
-
For problems or suggestions about this website write to...
-
-{% endblock %}
diff --git a/sample_project/templates/codespeed/base_site.html b/sample_project/templates/codespeed/base_site.html
deleted file mode 100644
index 0ba7ca30..00000000
--- a/sample_project/templates/codespeed/base_site.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% extends "codespeed/base.html" %}
-
-{% block title %}
- My Own Title
-{% endblock %}
diff --git a/sample_project/templates/feeds/latest_description.html b/sample_project/templates/feeds/latest_description.html
deleted file mode 100644
index 66f20dcf..00000000
--- a/sample_project/templates/feeds/latest_description.html
+++ /dev/null
@@ -1,8 +0,0 @@
-{% ifequal obj.colorcode "red" %}Performance regressed: {% else %}
- {% ifequal obj.colorcode "green" %}Performance improved: {% else %}
- {% ifequal obj.colorcode "yellow" %}Trend regressed: {% else %}
- No significant changes.
- {% endifequal %}
- {% endifequal %}
-{% endifequal %}
-{{ obj.summary }}
diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html
deleted file mode 100644
index 2a0ddf3c..00000000
--- a/sample_project/templates/home.html
+++ /dev/null
@@ -1,216 +0,0 @@
-{% extends "codespeed/base_site.html" %}
-{% load static %}
-
-{% block navigation %}
-{% endblock navigation %}
-
-{% block body %}
-
-
-
-
-
-
-
-
-
-
-
-
- {% if show_historical %}
-
-
How fast is {{ default_exe.project }}?
-
-
Plot 1: The above plot represents {{ default_exe.project }} ({{ default_exe }}) benchmark times normalized to {{ baseline }}. Smaller is better.
-
It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than {{ baseline }}
-
-
How has {{ default_exe.project }} performance evolved over time?
-
-
Plot 2: Speedup compared to {{ baseline }}, using the inverse of the geometric average of normalized times, out of benchmarks (see paper on why the geometric mean is better for normalized results).
-
- {% endif %}
-
-{% endblock body %}
-
-{% block extra_script %}
-{{ block.super }}
-{% if show_historical %}
-
+
About this site
+
We have nightly benchmark runs of PyPy, together with CPython data for
+comparison. The current benchmarks have run since 2016 on a dedicated machine
+named benchmarker. Previously, we had other machines (tannit and
+briefly speed-python). The benchmarker machine is generously
+donated by Baroque Software. The
+specs are:
+
- Processor: Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz
+- RAM: 64GB Micron DDR4 2400 MHz
+- Disk: 4TB TOSHIBA MG04ACA4
+
+
+
About the benchmarks
+
The benchmark code can be found here.
+
This is a benchmark suite based on Unladen Swallow, adapted for PyPy and
+runs on Python2 and Python3. Also see the
+speed.python.org site.
+
+
About PyPy
+
PyPy is a very compliant implementation of the Python language.
+
Main website: www.pypy.org
+
Documentation: doc.pypy.org
+
Blog: www.pypy.org/blog/
+
+
About Codespeed
+
Codespeed is a web application
+to monitor and analyze the performance of your code.
+
The source code of this website can be found on the
+PyPy
+branch of the Python fork of codespeed.
+
+
Contact
+
For problems or suggestions about this website, please file an issue in the
+GitHub repository.
+
+{% endblock %}
diff --git a/sample_project/templates/admin/base_site.html b/speed_pypy/templates/admin/base_site.html
similarity index 100%
rename from sample_project/templates/admin/base_site.html
rename to speed_pypy/templates/admin/base_site.html
diff --git a/speed_pypy/templates/admin/index.html b/speed_pypy/templates/admin/index.html
new file mode 100644
index 00000000..540c9303
--- /dev/null
+++ b/speed_pypy/templates/admin/index.html
@@ -0,0 +1,73 @@
+{% extends "admin/index.html" %}
+{% load i18n %}
+
+{% block content %}
+
+ {% include "admin/app_list.html" with app_list=app_list show_changelinks=True %}
+
+
+
+
+{% endblock %}
diff --git a/speed_pypy/templates/codespeed/base_site.html b/speed_pypy/templates/codespeed/base_site.html
new file mode 100644
index 00000000..337a9769
--- /dev/null
+++ b/speed_pypy/templates/codespeed/base_site.html
@@ -0,0 +1,3 @@
+{% extends "codespeed/base.html" %}
+
+{% block title %}PyPy Speed{% endblock %}
diff --git a/speed_pypy/templates/feeds/latest_description.html b/speed_pypy/templates/feeds/latest_description.html
new file mode 100644
index 00000000..f790f4c0
--- /dev/null
+++ b/speed_pypy/templates/feeds/latest_description.html
@@ -0,0 +1,8 @@
+{% if obj.colorcode == "red" %}Performance regressed: {% else %}
+ {% if obj.colorcode == "green" %}Performance improved: {% else %}
+ {% if obj.colorcode == "yellow" %}Trend regressed: {% else %}
+ No significant changes.
+ {% endif %}
+ {% endif %}
+{% endif %}
+{{ obj.summary }}
diff --git a/sample_project/templates/feeds/latest_title.html b/speed_pypy/templates/feeds/latest_title.html
similarity index 100%
rename from sample_project/templates/feeds/latest_title.html
rename to speed_pypy/templates/feeds/latest_title.html
diff --git a/speed_pypy/templates/home.html b/speed_pypy/templates/home.html
new file mode 100644
index 00000000..93b051d6
--- /dev/null
+++ b/speed_pypy/templates/home.html
@@ -0,0 +1,192 @@
+{% extends "codespeed/base_site.html" %}
+{% load static %}
+
+{% block navigation %}
+{% endblock navigation %}
+
+{% block body %}
+
+
+
+
+
+
+
+
+
+
+
+
+ {% if show_historical %}
+
+
How fast is {{ default_exe.project }}?
+
+
Plot 1: The above plot represents {{ default_exe.project }} ({{ default_exe }}) benchmark times normalized to {{ baseline }}. Smaller is better.
+
It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than {{ baseline }}
+
+
How has PyPy performance evolved over time?
+
+
Plot 2: Speedup compared to {{ baseline }}, using the inverse of the geometric average of normalized times, out of benchmarks (see paper on why the geometric mean is better for normalized results).
+
+ {% endif %}
+
+{% endblock body %}
+
+{% block extra_script %}
+{{ block.super }}
+{% if show_historical %}
+
+{% endif %}
+
+
+{% endblock %}
diff --git a/sample_project/urls.py b/speed_pypy/urls.py
similarity index 52%
rename from sample_project/urls.py
rename to speed_pypy/urls.py
index ed416c79..b149cb30 100644
--- a/sample_project/urls.py
+++ b/speed_pypy/urls.py
@@ -1,12 +1,15 @@
# -*- coding: utf-8 -*-
from django.conf import settings
-from django.conf.urls import include, url
+from django.urls import include, re_path
from django.contrib import admin
+from codespeed import admin_views
+
urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^', include('codespeed.urls'))
+ re_path(r'^admin/download-db/$', admin_views.download_db, name='admin-download-db'),
+ re_path(r'^admin/', admin.site.urls),
+ re_path(r'^', include('codespeed.urls'))
]
if settings.DEBUG:
diff --git a/speed_pypy/wsgi.py b/speed_pypy/wsgi.py
new file mode 100644
index 00000000..6d7a2a33
--- /dev/null
+++ b/speed_pypy/wsgi.py
@@ -0,0 +1,8 @@
+# This is used for staging & production
+import os
+import sys
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "speed_pypy.settings")
+
+from django.core.wsgi import get_wsgi_application
+application = get_wsgi_application()
diff --git a/tools/pypy/import_from_json.py b/tools/pypy/import_from_json.py
index 5d3eb21d..0fe722cb 100644
--- a/tools/pypy/import_from_json.py
+++ b/tools/pypy/import_from_json.py
@@ -2,64 +2,88 @@
################################################################################
# This script imports PyPy's result data from json files located on the server #
################################################################################
-import simplejson, urllib2
+import simplejson
+from urllib.request import urlopen
+from urllib.error import URLError
import sys
from xml.dom.minidom import parse
from datetime import datetime
-import saveresults, savecpython
+import saveresults
-RESULTS_URLS = {
- 'pypy-c-jit': 'http://buildbot.pypy.org/bench_results/',
- 'pypy-c': 'http://buildbot.pypy.org/bench_results_nojit/',
-}
-START_REV = 79485
-END_REV = 79485
-PROJECT = "PyPy"
+URL = 'http://buildbot.pypy.org/benchmark-results/'
+START_REV = 186137
+END_REV = 200000
-for INTERP in RESULTS_URLS:
- RESULTS_URL = RESULTS_URLS[INTERP]
- # get json filenames
- filelist = []
- try:
- datasource = urllib2.urlopen(RESULTS_URL)
- dom = parse(datasource)
- for elem in dom.getElementsByTagName('td'):
- for e in elem.childNodes:
- if len(e.childNodes):
- filename = e.firstChild.toxml()
- if e.tagName == "a" and ".json" in filename:
- if int(filename.replace(".json", "")) >= START_REV and\
- int(filename.replace(".json", "")) <= END_REV:
- filelist.append(filename)
- except urllib2.URLError, e:
- response = "None"
- if hasattr(e, 'reason'):
- response = '\n We failed to reach ' + RESULTS_URL + '\n'
- response += ' Reason: ' + str(e.reason)
- elif hasattr(e, 'code'):
- response = '\n The server couldn\'t fulfill the request\n'
- response += ' Error code: ' + str(e)
- print "Results Server (%s) response: %s\n" % (RESULTS_URL, response)
- sys.exit(1)
- finally:
- datasource.close()
- # read json result and save to speed.pypy.org
- for filename in filelist:
- print "Reading %s..." % filename
- f = urllib2.urlopen(RESULTS_URL + filename)
- result = simplejson.load(f)
- f.close()
- proj = PROJECT
- revision = result['revision']
- interpreter = INTERP
- int_options = ""
- options = ""
- if 'options' in result:
- options = result['options']
+speed_url = "http://127.0.0.1:8000/"
- host = 'tannit'
- #saveresults.save(proj, revision, result['results'], options, interpreter, host)
- if filename == filelist[len(filelist)-1]:
- savecpython.save('cpython', '100', result['results'], options, 'cpython', host)
-print "\nOK"
+# get json filenames
+filelist = []
+try:
+ datasource = urlopen(URL)
+ dom = parse(datasource)
+ for elem in dom.getElementsByTagName('td'):
+ for e in elem.childNodes:
+ if len(e.childNodes):
+ filename = e.firstChild.toxml()
+ if e.tagName == "a" and ".json" in filename:
+ rev_int = int(filename.split(":")[0])
+ if START_REV <= rev_int <= END_REV:
+ filelist.append(filename)
+except URLError as e:
+ response = "None"
+ if hasattr(e, 'reason'):
+ response = '\n We failed to reach ' + URL + '\n'
+ response += ' Reason: ' + str(e.reason)
+ elif hasattr(e, 'code'):
+ response = '\n The server couldn\'t fulfill the request\n'
+ response += ' Error code: ' + str(e)
+ print("Results Server (%s) response: %s\n" % (URL, response))
+ sys.exit(1)
+finally:
+ datasource.close()
+
+# read json result and save to speed.pypy.org
+skipped = []
+for filename in filelist:
+ print(f"Reading {filename}...")
+ f = urlopen(URL + filename)
+ if f.length < 10:
+ skipped.append(filename)
+ continue
+ result = simplejson.load(f)
+ f.close()
+ revision = result['revision']
+ int_options = ""
+ options = ""
+ if 'options' in result:
+ options = result['options']
+
+ host = 'benchmarker'
+ if revision and len(revision) >10:
+ branch = result['branch']
+ if branch in ("default", "main"):
+ proj = "PyPy"
+ executable = "pypy-c"
+ branch = "main"
+ elif branch == "py3.9":
+ proj = "PyPy3.9"
+ executable = "pypy3.9-64"
+ elif branch == "py3.10":
+ proj = "PyPy3.10"
+ executable = "pypy3.10-64"
+ elif branch == "py3.11":
+ proj = "PyPy3.11"
+ executable = "pypy3.11-64"
+ else:
+ skipped.append(filename)
+ continue
+ saveresults.save(proj, revision, result['results'], executable,
+ host, speed_url, branch=branch, changed=True)
+ saveresults.save(proj, revision, result['results'],
+ executable.replace('-', '-jit-'),
+ host, speed_url, branch=branch, changed=False)
+ else:
+ savecpython.save('cpython', '100', result['results'], options, 'cpython', host)
+print("\nOK")
+print("skipped", skipped)
diff --git a/tools/pypy/saveresults.py b/tools/pypy/saveresults.py
index 8ca8ee75..3d3eb0df 100644
--- a/tools/pypy/saveresults.py
+++ b/tools/pypy/saveresults.py
@@ -3,64 +3,172 @@
# This script saves result data #
# It expects the format of unladen swallow's perf.py #
#######################################################
-import urllib, urllib2
+
+"""
+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 benchmarker
+
+ OR
+
+ $ ./saveresults.py result.json -r '45757:fabe4fc0dc08' -n pypy-c-jit-64 \
+ -H benchmarker
+"""
+from __future__ import division, print_function
+
from datetime import datetime
+import optparse
+import sys
+import time
+try:
+ import urllib2
+ from urllib import urlencode
+except ImportError:
+ import urllib.request as urllib2
+ from urllib.parse import urlencode
+import json
+import pprint
-#SPEEDURL = 'http://127.0.0.1:8000/'
-SPEEDURL = 'http://speed.pypy.org/'
+SPEEDURL = 'http://127.0.0.1:8000/'
+# SPEEDURL = 'https://speed.pypy.org/'
-def save(project, revision, results, options, executable, environment, testing=False):
+def save(project, revision, results, executable, host, url, testing=False,
+ changed=True, branch='default'):
testparams = []
#Parse data
data = {}
- current_date = datetime.today()
+ error = 0
+
+ print("saveresults::save sending from %s to %s" %(host, url))
for b in results:
bench_name = b[0]
res_type = b[1]
results = b[2]
value = 0
if res_type == "SimpleComparisonResult":
- value = results['changed_time']
+ if changed:
+ value = results['changed_time']
+ else:
+ value = results['base_time']
elif res_type == "ComparisonResult":
- value = results['avg_changed']
+ 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 = {
+ data = [{
'commitid': revision,
'project': project,
'executable': executable,
'benchmark': bench_name,
- 'environment': environment,
+ 'environment': host,
'result_value': value,
- }
+ 'branch': branch,
+ }]
+ if not value:
+ print("Ignoring skipped result", data)
+ continue
if res_type == "ComparisonResult":
- data['std_dev'] = results['std_changed']
- if testing: testparams.append(data)
- else: send(data)
- if testing: return testparams
- else: return 0
+ if changed:
+ data[0]['std_dev'] = results['std_changed']
+ else:
+ data[0]['std_dev'] = results['std_base']
+ if testing:
+ testparams.append(data)
+ else:
+ error |= send(data, url)
-def send(data):
+ if error:
+ raise IOError("Saving failed. See messages above.")
+ if testing:
+ return testparams
+ else:
+ return 0
+
+
+def send(data, url):
#save results
- params = urllib.urlencode(data)
+ params = urlencode({'json': json.dumps(data)}).encode("utf-8")
f = None
response = "None"
- info = str(datetime.today()) + ": Saving result for " + data['executable']
- info += " revision " + " " + str(data['commitid']) + ", benchmark "
- info += data['benchmark']
+ info = ("%s: Saving result for %s revision %s, benchmark %s" %
+ (str(datetime.today()), data[0]['executable'],
+ str(data[0]['commitid']), data[0]['benchmark']))
print(info)
try:
- f = urllib2.urlopen(SPEEDURL + 'result/add/', params)
- response = f.read()
- f.close()
+ retries = [1, 3, 6, 20]
+ while True:
+ try:
+ print('result/add')
+ f = urllib2.urlopen(url + 'result/add/json/', params)
+ print('urlopen')
+ response = f.read().decode()
+ print('response')
+ 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 as e:
if hasattr(e, 'reason'):
- response = '\n We failed to reach a server\n'
+ response = '\n We failed to save the data\n'
response += ' Reason: ' + str(e.reason)
elif hasattr(e, 'code'):
- response = '\n The server couldn\'t fulfill the request\n'
- response += ' Error code: ' + str(e)
- print("Server (%s) response: %s\n" % (SPEEDURL, response))
+ response = '\n The server couldn\'t fulfill the request'
+ if hasattr(e, 'readlines'):
+ response = "".join([response] + [s.decode() for s in e.readlines()])
+ print(response)
+ print('when sending')
+ pprint.pprint(data)
+ raise
+ with open('error.html', 'w') as error_file:
+ error_file.write(response)
+ print("Server (%s) response written to error.html" % (url,))
+ print(' Error code: %s\n' % (e,))
return 1
+ print("saved correctly!", end='\n\n')
return 0
+
+if __name__ == '__main__':
+ usage = "Usage: %prog [options]