From 753d53cd64fbb8bfcb7592029680e4139541b69b Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 14:16:08 +0200 Subject: [PATCH 001/134] Custom PyPy about.html --- example/templates/about.html | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/example/templates/about.html b/example/templates/about.html index 931cf62b..51c1d4ad 100644 --- a/example/templates/about.html +++ b/example/templates/about.html @@ -1,22 +1,26 @@ -{% extends "base.html" %} +{% extends "site_base.html" %} {% block title %}{{ block.super }}: About this site{% endblock %} {% block body %}

About this site

-

<description of site and what benchmarks that are run>

+

We have nightly benchmark runs of pypy-c-jit and pypy-c, together with cpython 2.6.2 data for comparison.

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

+

The code can be found here and here.

+

About PyPy

+

PyPy is a very compliant implementation of the Python language.

+

Main website: pypy.org

+ +

Blog: morepypy.blogspot.com

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...

+

For problems or suggestions about this website write to

+

the pypy-dev mailing list or directly to Miquel Torres (tobami at googlemail dot com)

+
{% endblock %} From a7aaa6427a2a33ab97377138853cc123f9368382 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:18:20 +0200 Subject: [PATCH 002/134] Custom PyPy settings --- example/settings.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/example/settings.py b/example/settings.py index 3b251f0c..8d7efaa3 100644 --- a/example/settings.py +++ b/example/settings.py @@ -124,7 +124,7 @@ def process_exception(self, request, exception): #DEF_ENVIRONMENT = None #Name of the environment which should be selected as default -#DEF_BASELINE = None # Which executable + revision should be default as a baseline +DEF_BASELINE = {'executable': 'cpython', 'revision': '100'} # Which executable + revision should be default as a baseline # Given as the name of the executable and commitid of the revision # Example: defaultbaseline = {'executable': 'myexe', 'revision': '21'} @@ -132,11 +132,11 @@ def process_exception(self, request, exception): # Used by reports for the latest runs and changes view # Threshold that determines when a performance change over the last result is significant -#CHANGE_THRESHOLD = 3.0 +CHANGE_THRESHOLD = 5.0 # Threshold that determines when a performance change # over a number of revisions is significant -#TREND_THRESHOLD = 5.0 +TREND_THRESHOLD = 6.0 ## Changes view options ## #DEF_EXECUTABLE = None # Executable that should be chosen as default in the changes view @@ -156,14 +156,14 @@ def process_exception(self, request, exception): ## Comparison view options ## #CHART_TYPE = 'normal bars' # The options are 'normal bars', 'stacked bars' and 'relative bars' -#NORMALIZATION = False # True will enable normalization as the default selection +NORMALIZATION = True # True will enable normalization as the default selection # in the Comparison view. The default normalization can be # chosen in the defaultbaseline setting #CHART_ORIENTATION = 'vertical' # 'vertical' or 'horizontal can be chosen as # default chart orientation -#COMP_EXECUTABLES = None # Which executable + revision should be checked as default +COMP_EXECUTABLES = [('pypy-c-jit', 'L'), ('pypy-c', 'L')] # Which executable + revision should be checked as default # Given as a list of tuples containing the # name of an executable + commitid of a revision # An 'L' denotes the last revision From a6b36a06804dffd9127417c7ab3de0d8ab74cc9b Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:42:07 +0200 Subject: [PATCH 003/134] Add custom PyPy homepage --- codespeed/views.py | 45 +++++++++++ example/settings.py | 2 +- example/templates/home.html | 146 +++++++++++++++++++++++++++++++++++- example/urls.py | 4 +- 4 files changed, 191 insertions(+), 6 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index b0e1a778..51f7de27 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -927,3 +927,48 @@ def add_json_results(request): logging.debug("add_json_results: completed") return HttpResponse("All result data saved successfully", status=202) + + +def get_home_data(request): + if request.method != 'GET': + return HttpResponseNotAllowed('GET') + data = {'results': {}, 'benchmarks': []} + env = Environment.objects.get(name='tannit') + # Fetch CPython data + cp_exe = Executable.objects.get(name="cpython") + cp_lastrev = Revision.objects.filter( + branch__project=cp_exe.project).order_by('-date')[0] + cp_results = Result.objects.filter( + executable=cp_exe, revision=cp_lastrev, environment=env) + # Fetch PyPy trunk data + pp_exe = Executable.objects.get(name="pypy-c-jit") + pp_branch = Branch.objects.get(name="default", project=pp_exe.project) + pp_lastrev = Revision.objects.filter(branch=pp_branch).order_by('-date')[0] + pp_results = Result.objects.filter( + executable=pp_exe, revision=pp_lastrev, environment=env) + # Fetch PyPy tagged revisions + pp_taggedrevs = Revision.objects.filter( + project=pp_exe.project + ).exclude(tag="").order_by('date') + data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] + pp_results = {'PyPy trunk': pp_results} + for rev in pp_taggedrevs: + pp_results[rev.tag] = Result.objects.filter( + executable=pp_exe, revision=rev, environment=env) + # Save data + benchmarks = [] + for res in cp_results: + if res == 0: + continue + benchmarks.append(res.benchmark.name) + key = 'CPython ' + cp_lastrev.tag + data['results'][res.benchmark.name] = {key: res.value} + for rev_name in pp_results: + val = 0 + for pp_res in pp_results[rev_name]: + if pp_res.benchmark.name == res.benchmark.name: + val = pp_res.value + data['results'][res.benchmark.name][rev_name] = val + benchmarks.sort() + data['benchmarks'] = benchmarks + return HttpResponse(json.dumps( data )) diff --git a/example/settings.py b/example/settings.py index 8d7efaa3..73027dcf 100644 --- a/example/settings.py +++ b/example/settings.py @@ -119,7 +119,7 @@ def process_exception(self, request, exception): # Codespeed settings that can be overwritten here. ## General default options ## -#WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed +WEBSITE_NAME = "PyPy Speed Center" # This name will be used in the reports RSS feed #DEF_ENVIRONMENT = None #Name of the environment which should be selected as default diff --git a/example/templates/home.html b/example/templates/home.html index 30a553a5..168fbd1e 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -2,7 +2,137 @@ {% block extra_head %} {{ block.super }} + + + + + + + + + {% endblock %} @@ -50,6 +181,15 @@

Comparison

Compare different executables and revisions


-
+ +
+

How fast is PyPy?

+
+

Plot 1: The above plot represents PyPy trunk (with JIT) benchmark times normalized to CPython. Smaller is better.

+

While it depends greately on the type of taks being performed, currently PyPy takes % of the time that CPython needs to complete an average given task (represented by the geometric mean of all benchmarks), which means that PyPy is about times faster than CPython

+

How has PyPy performance evolved over time?

+
+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

+
{% endblock body %} diff --git a/example/urls.py b/example/urls.py index 34c3fca1..a1f7628b 100644 --- a/example/urls.py +++ b/example/urls.py @@ -19,8 +19,8 @@ #('^$', redirect_to, {'url': '/speed/'}), ) -urlpatterns += patterns( - '', +urlpatterns += patterns('', + (r'^json/$', 'codespeed.views.get_home_data'), (r'^', include('codespeed.urls')), #(r'^speed/', include('codespeed.urls')), ) From 69d3f621d3eabab033aea8e182aed8d7ad001f43 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:44:19 +0200 Subject: [PATCH 004/134] Add Google Analytics script --- example/templates/base.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/example/templates/base.html b/example/templates/base.html index 1da6890d..252f11c4 100644 --- a/example/templates/base.html +++ b/example/templates/base.html @@ -50,5 +50,15 @@

{% block page_title %}SPEED CENTER{% endblock page_title %}

{% endblock %} + + From 5029db8cd9496e2fd2e05fc02f539d12a8ab94df Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:45:05 +0200 Subject: [PATCH 005/134] Add pointlabels jqplot plugin for Home page plot --- .../static/js/jqplot/jqplot.pointLabels.min.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codespeed/static/js/jqplot/jqplot.pointLabels.min.js diff --git a/codespeed/static/js/jqplot/jqplot.pointLabels.min.js b/codespeed/static/js/jqplot/jqplot.pointLabels.min.js new file mode 100644 index 00000000..2bf8a86d --- /dev/null +++ b/codespeed/static/js/jqplot/jqplot.pointLabels.min.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2009 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT and GPL version 2.0 licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + */ +(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=0;this.hideZeros=false;c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(k,h,g,e){var n=c.extend(true,{},g,e);this.plugins.pointLabels=new c.jqplot.PointLabels(n.pointLabels);var f=this.plugins.pointLabels;if(f.labels.length==0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){var m=f.seriesLabelIndex||this._plotData[0].length-1;for(var j=0;j');u.insertAfter(s.canvas);if(q.escapeHTML){u.text(m)}else{u.html(m)}var f=q.location;if(this.waterfall&&parseInt(m,10)<0){f=b[d[f]]}var l=v.u2p(y[r][0])+q.xOffset(u,f);var g=n.u2p(y[r][1])+q.yOffset(u,f);u.css("left",l);u.css("top",g);var j=l+c(u).width();var o=g+c(u).height();var x=q.edgeTolerance;var e=c(s.canvas).position().left;var t=c(s.canvas).position().top;var w=s.canvas.width+e;var k=s.canvas.height+t;if(l-xw||o+x>k){c(u).remove()}}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); \ No newline at end of file From 96160f3a52d19b136ead35320cace3867bad5666 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:56:00 +0200 Subject: [PATCH 006/134] Add PyPy favicon --- example/override/static/images/favicon.ico | Bin 0 -> 3230 bytes example/templates/base.html | 1 + 2 files changed, 1 insertion(+) create mode 100644 example/override/static/images/favicon.ico diff --git a/example/override/static/images/favicon.ico b/example/override/static/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c79bb6ded95b2a0035b0a9c47c7f2785cfbed0c1 GIT binary patch literal 3230 zcmcIm2~ZSA6rJ5!&S41Xf;r$ zqM;n$@_8clzhRx^3y<0yxNOOWLwN@5E3@F(uoR~Af}pCc0X2Osa6&;p<3>tWSl8 zttqR^inqu?o%-HNTpdlKHY5kogI*c5YB9RcX!0AL5>p~plPM99)42uv)7P)el8tFh0|Do15q5JsypNP(wD|-W z%=Ct3Od?$KiwUoy`dGk=bce_xKQ-72J*`R{s)|NMX$*2p;;^_m1G$|Wk#V{V$>*xz zx;YI|7aI`vL+yZm*!69YmS@5wB@m+wwFh#s%gBZ_a|yAWoru{7Pa|sIQKC9t^ASIC z zoN0(7olWsXJYF3F0p~}_JVh`?wMbp1-#EY?CUQ57nWW2fJ1G9|UF!^L*olnZM@Tr< zgMg}S(6*TYfl#PVeV#K50}WhinFFTJ>MxzD!?dlQBR%V|8jgF`eP!!}TR}1LD{q8< zMGMP;)u42chg;UH={Q#(GoXL0DvFJ(We{h0U4g*J$ioLgTX!O)aW59%1B<z95Od)MG#;&E!Y(i%UY-`x-gcgaM?OCQX8lfJr^n4Ob-Aq~3;dk0gx zdl9f@VE$iL+vdG%1IhPwv<6Lc(7Y-L*5+cC!{#^9e99FFrqTAVzUB2qvF9+6e|8Yj z`%hxLsRe|h5hI@R{%xqMig;}eb^P3>1RMXi)iEf}@kU&PEkwNVZ%WIfU}wTm=1vJ; zi)|$ctZgO9-B(Cb*JaE;a0)JYYuR`{enkK`yUAi)Y)d3v&GFbxwy~Vp|0aqH9~c|LQ05Jvnyn}yw(c%b z3}t?16UU*uHGv#&NhJH~lvwpq5OQ*Zky#jt^b#c$>y>a>u7K5IIjr&$;jn2Lk+oG4 zS#uS9>Z&2Du7RTcFf#i7K+b)Fz?wET?w>~M>a+DQq=|TeDJA{3EZG?+_N3#>-Sbh` zl8zN+O3d3B5BWMJWW`C4mZU*inggebe0bEAz;8!AA`iABj(*x&s|NJs1RRa|Zo@b$`flh7@CaIenFm n-h7oK08g>{Kj1qGh)S>fW0i+|;n>HN&;015(^x74VcF#$?Vs(& literal 0 HcmV?d00001 diff --git a/example/templates/base.html b/example/templates/base.html index 252f11c4..5ec7231a 100644 --- a/example/templates/base.html +++ b/example/templates/base.html @@ -9,6 +9,7 @@ + {% block extra_head %}{% endblock %} From b7e214b40fa90988f1f174c9215f22a1fff8480d Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 20:15:34 +0200 Subject: [PATCH 007/134] Add legend to first "home" plot --- codespeed/static/css/main.css | 2 +- example/templates/home.html | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/codespeed/static/css/main.css b/codespeed/static/css/main.css index 0220fd30..815e00aa 100644 --- a/codespeed/static/css/main.css +++ b/codespeed/static/css/main.css @@ -123,7 +123,7 @@ div#presentation div.menubox { } div#presentation div.menubox:hover { border: 5px solid #FFCE9C; } -div#presentation p { height: 5em; padding-left: 120px; } +div#presentation div.menubox p { height: 5em; padding-left: 120px; } div#presentation div#changes p { background: url(../images/changes.png) no-repeat; diff --git a/example/templates/home.html b/example/templates/home.html index 168fbd1e..3d667650 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -54,10 +54,11 @@ } trunk_geomean = Math.pow(trunk_geomean, 1/plotdata[0].length); var geofaster = 1/trunk_geomean; - $('#geomean').html((100*trunk_geomean).toFixed(1)); + $('#geomean').html(trunk_geomean.toFixed(2)); $('#geofaster').html(geofaster.toFixed(1)); // Render first plot plotoptions1 = { + legend:{show:true}, seriesDefaults: { showMarker: false, rendererOptions:{barPadding: 2, barMargin:5} @@ -67,10 +68,14 @@ }, series:[ { + label: 'PyPy trunk', renderer:$.jqplot.BarRenderer, pointLabels:{labels:labels} }, - {pointLabels:{show:false}} + { + label: 'CPython', + pointLabels:{show:false} + } ], axes: { xaxis: { @@ -85,7 +90,7 @@ } }; plot1 = $.jqplot("cpythonplot", plotdata, plotoptions1); - + // Prepare and render second plot var geomeans = [1.0]; var num_of_benchs = 0; @@ -109,6 +114,7 @@ geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); } $('#num_of_benchs').html(num_of_benchs) + plotoptions2 = { seriesDefaults: { renderer:$.jqplot.BarRenderer, @@ -182,12 +188,13 @@

Comparison


-
+

How fast is PyPy?

Plot 1: The above plot represents PyPy trunk (with JIT) benchmark times normalized to CPython. Smaller is better.

-

While it depends greately on the type of taks being performed, currently PyPy takes % of the time that CPython needs to complete an average given task (represented by the geometric mean of all benchmarks), which means that PyPy is about times faster than CPython

+

It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than CPython

How has PyPy performance evolved over time?

+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

From 9f75a7066e71ff45aeb1db037ae753cdac3b8b2b Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Mon, 18 Jul 2011 21:56:27 +0200 Subject: [PATCH 008/134] Don't choose a revision that doesn't have results for pypy-c-jit --- codespeed/views.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index 51f7de27..27a375c3 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -308,7 +308,7 @@ def comparison(request): pass # The selected baseline was not checked except: pass # Keep "none" as default baseline - print selectedbaseline + selecteddirection = False if 'hor' in data and data['hor'] == "true" or\ hasattr(settings, 'CHART_ORIENTATION') and settings.CHART_ORIENTATION == 'horizontal': @@ -940,21 +940,32 @@ def get_home_data(request): branch__project=cp_exe.project).order_by('-date')[0] cp_results = Result.objects.filter( executable=cp_exe, revision=cp_lastrev, environment=env) - # Fetch PyPy trunk data + pp_exe = Executable.objects.get(name="pypy-c-jit") pp_branch = Branch.objects.get(name="default", project=pp_exe.project) - pp_lastrev = Revision.objects.filter(branch=pp_branch).order_by('-date')[0] - pp_results = Result.objects.filter( - executable=pp_exe, revision=pp_lastrev, environment=env) # Fetch PyPy tagged revisions pp_taggedrevs = Revision.objects.filter( project=pp_exe.project ).exclude(tag="").order_by('date') data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] - pp_results = {'PyPy trunk': pp_results} + pp_results = {} for rev in pp_taggedrevs: pp_results[rev.tag] = Result.objects.filter( executable=pp_exe, revision=rev, environment=env) + + # Fetch PyPy trunk data + revs = Revision.objects.filter(branch=pp_branch).order_by('-date')[:5] + pp_lastrev = None + for i in range(4): + pp_lastrev = revs[i] + if pp_lastrev.results.filter(executable=pp_exe): + break + pp_lastrev = None + if pp_lastrev is None: + return HttpResponse(json.dumps( data )) + pp_results['PyPy trunk'] = Result.objects.filter( + executable=pp_exe, revision=pp_lastrev, environment=env) + # Save data benchmarks = [] for res in cp_results: From 601625940ebda49f9665095a142b88e15ca05e57 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 21 Aug 2011 17:37:21 +0200 Subject: [PATCH 009/134] Improve pypy branch query, set WEBSITE_NAME and project name in template --- codespeed/settings.py | 2 +- codespeed/views.py | 2 +- example/templates/base.html | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codespeed/settings.py b/codespeed/settings.py index 8340aa7f..3bcb7e54 100644 --- a/codespeed/settings.py +++ b/codespeed/settings.py @@ -2,7 +2,7 @@ """Default settings for Codespeed""" ## General default options ## -WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed +WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed DEF_ENVIRONMENT = None #Name of the environment which should be selected as default diff --git a/codespeed/views.py b/codespeed/views.py index 27a375c3..bc844b73 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -945,7 +945,7 @@ def get_home_data(request): pp_branch = Branch.objects.get(name="default", project=pp_exe.project) # Fetch PyPy tagged revisions pp_taggedrevs = Revision.objects.filter( - project=pp_exe.project + branch=pp_branch ).exclude(tag="").order_by('date') data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] pp_results = {} diff --git a/example/templates/base.html b/example/templates/base.html index 5ec7231a..af7d6b92 100644 --- a/example/templates/base.html +++ b/example/templates/base.html @@ -1,8 +1,8 @@ - {% block title %}MyProject's Speed Center{% endblock %} - + {% block title %}PyPy's Speed Center{% endblock %} + From 224babeaf27a9a0cbb6599d1adf2fb1f468b490a Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Thu, 17 May 2012 11:53:48 +0200 Subject: [PATCH 010/134] Use the proper key for CPython data Update default baseline Increase width of second graph --- codespeed/views.py | 4 ++-- example/settings.py | 2 +- example/templates/home.html | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index 303be50f..2e457907 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -935,6 +935,7 @@ def get_home_data(request): cp_exe = Executable.objects.get(name="cpython") cp_lastrev = Revision.objects.filter( branch__project=cp_exe.project).order_by('-date')[0] + data['baseline'] = 'CPython ' + cp_lastrev.tag cp_results = Result.objects.filter( executable=cp_exe, revision=cp_lastrev, environment=env) @@ -969,8 +970,7 @@ def get_home_data(request): if res == 0: continue benchmarks.append(res.benchmark.name) - key = 'CPython ' + cp_lastrev.tag - data['results'][res.benchmark.name] = {key: res.value} + data['results'][res.benchmark.name] = {data['baseline']: res.value} for rev_name in pp_results: val = 0 for pp_res in pp_results[rev_name]: diff --git a/example/settings.py b/example/settings.py index 07823e07..f767132e 100644 --- a/example/settings.py +++ b/example/settings.py @@ -124,7 +124,7 @@ def process_exception(self, request, exception): #DEF_ENVIRONMENT = None #Name of the environment which should be selected as default -DEF_BASELINE = {'executable': 'cpython', 'revision': '100'} # Which executable + revision should be default as a baseline +DEF_BASELINE = {'executable': 'cpython', 'revision': '101'} # Which executable + revision should be default as a baseline # Given as the name of the executable and commitid of the revision # Example: defaultbaseline = {'executable': 'myexe', 'revision': '21'} diff --git a/example/templates/home.html b/example/templates/home.html index 3d667650..26b35ee7 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -38,7 +38,7 @@ add_to_tagged_data = false; } if (add_to_tagged_data === false) { break; } - relative_value = data['results'][benchname][rev]/data['results'][benchname]['CPython 2.6.2']; + relative_value = data['results'][benchname][rev]/data['results'][benchname][data['baseline']]; tagged_data[i].push(relative_value) } // Only add benchmark if there are no 0 values @@ -46,7 +46,7 @@ // First add benchmark benchmarks.push(benchname); // Add PyPy trunk and CPython's 1.0 value - relative_value = data['results'][benchname]['PyPy trunk']/data['results'][benchname]['CPython 2.6.2']; + relative_value = data['results'][benchname]['PyPy trunk']/data['results'][benchname][data['baseline']]; plotdata[0].push(relative_value); plotdata[1].push(1.0); labels.push(relative_value.toFixed(2)); @@ -73,7 +73,7 @@ pointLabels:{labels:labels} }, { - label: 'CPython', + label: data['baseline'], pointLabels:{show:false} } ], @@ -84,7 +84,7 @@ tickOptions: {angle: -40} }, yaxis:{ - ticks: [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5], + ticks: [0, 0.25, 0.5, 0.75, 1, 1.25], tickOptions:{formatString:'%.2f'} } } @@ -104,7 +104,7 @@ geomeans.push(tempgeo); } geomeans.push(trunk_geomean); - var ticks = ['CPython 2.6.2']; + var ticks = [data['baseline']]; for (var i in data['tagged_revs']) { ticks.push(data['tagged_revs'][i]); } @@ -195,7 +195,7 @@

How fast is PyPy?

It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than CPython

How has PyPy performance evolved over time?

-
+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

From e4919086cc6912268c3cc2d2ebc67e733743949b Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Fri, 8 Jun 2012 14:43:38 +0200 Subject: [PATCH 011/134] Invert plot 2 --- example/templates/home.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/example/templates/home.html b/example/templates/home.html index 26b35ee7..bc3b8edf 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -101,17 +101,19 @@ tempgeo *= tagged_data[i][j]; } tempgeo = Math.pow(tempgeo, 1/tagged_data[i].length); + tempgeo = 1/tempgeo; geomeans.push(tempgeo); } - geomeans.push(trunk_geomean); + geomeans.push(1/trunk_geomean); var ticks = [data['baseline']]; for (var i in data['tagged_revs']) { ticks.push(data['tagged_revs'][i]); } ticks.push('PyPy trunk'); var geolabels = new Array(); - for (var i in geomeans) { - geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); + for (var i in geomeans) { +// geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); + geolabels.push(geomeans[i].toFixed(2) + "x"); } $('#num_of_benchs').html(num_of_benchs) @@ -131,7 +133,8 @@ ticks: ticks }, yaxis:{ - ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], +// ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], + min: 0, tickOptions:{formatString:'%.2f'} } } @@ -196,7 +199,7 @@

How fast is PyPy?

How has PyPy performance evolved over time?

-

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

+

Plot 2: Speedup compared to CPython, using the inverse of the geometric average of normalized times, out of benchmarks.

{% endblock body %} From 2d9325e01c29e73fde30a4f7f6de2894160a8daf Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Fri, 8 Jun 2012 15:04:38 +0200 Subject: [PATCH 012/134] Add reference to paper explaining geometric mean for normalized results --- example/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/templates/home.html b/example/templates/home.html index bc3b8edf..141abff3 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -199,7 +199,7 @@

How fast is PyPy?

How has PyPy performance evolved over time?

-

Plot 2: Speedup compared to CPython, using the inverse of the geometric average of normalized times, out of benchmarks.

+

Plot 2: Speedup compared to CPython, 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).

{% endblock body %} From 51d4b63439e883ca2c69e2d7962f3593b573e16d Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:19:33 -0800 Subject: [PATCH 013/134] exec wrapper script. --- manage.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 manage.py diff --git a/manage.py b/manage.py new file mode 100644 index 00000000..c6e84457 --- /dev/null +++ b/manage.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +import os +import sys + +new_file = os.path.join(os.path.dirname(__file__), 'example', 'manage.py') +os.execl(sys.executable, sys.executable, new_file, *sys.argv) From 9da7418e4b42e894e166536addb9c8504ef82713 Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:25:18 -0800 Subject: [PATCH 014/134] unix is hard. --- manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.py b/manage.py index c6e84457..802ac262 100644 --- a/manage.py +++ b/manage.py @@ -3,4 +3,4 @@ import sys new_file = os.path.join(os.path.dirname(__file__), 'example', 'manage.py') -os.execl(sys.executable, sys.executable, new_file, *sys.argv) +os.execl(sys.executable, new_file, new_file, *sys.argv) From 2084839530a2dfbce068f69ac6514e0ef81e8910 Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:32:53 -0800 Subject: [PATCH 015/134] No really, I'm bad at unix. --- manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.py b/manage.py index 802ac262..1962469e 100644 --- a/manage.py +++ b/manage.py @@ -3,4 +3,4 @@ import sys new_file = os.path.join(os.path.dirname(__file__), 'example', 'manage.py') -os.execl(sys.executable, new_file, new_file, *sys.argv) +os.execl(sys.executable, sys.executable, new_file, *sys.argv[1:]) From b2056a761e3db332b544179d2e063b2e6f3930c8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 7 Jan 2013 12:21:12 -0800 Subject: [PATCH 016/134] Incrase the size of a field --- .../009_auto__chg_field_branch_name.py | 97 +++++++++++++++++++ codespeed/models.py | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 codespeed/migrations/009_auto__chg_field_branch_name.py diff --git a/codespeed/migrations/009_auto__chg_field_branch_name.py b/codespeed/migrations/009_auto__chg_field_branch_name.py new file mode 100644 index 00000000..f35dcc57 --- /dev/null +++ b/codespeed/migrations/009_auto__chg_field_branch_name.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Changing field 'Branch.name' + db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=50)) + + def backwards(self, orm): + # Changing field 'Branch.name' + db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) + + models = { + 'codespeed.benchmark': { + 'Meta': {'object_name': 'Benchmark'}, + 'benchmark_type': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '1'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lessisbetter': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'units': ('django.db.models.fields.CharField', [], {'default': "'seconds'", 'max_length': '20'}), + 'units_title': ('django.db.models.fields.CharField', [], {'default': "'Time'", 'max_length': '30'}) + }, + 'codespeed.branch': { + 'Meta': {'unique_together': "(('name', 'project'),)", 'object_name': 'Branch'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'branches'", 'to': "orm['codespeed.Project']"}) + }, + 'codespeed.environment': { + 'Meta': {'object_name': 'Environment'}, + 'cpu': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kernel': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'memory': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'os': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}) + }, + 'codespeed.executable': { + 'Meta': {'object_name': 'Executable'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'executables'", 'to': "orm['codespeed.Project']"}) + }, + 'codespeed.project': { + 'Meta': {'object_name': 'Project'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'repo_pass': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'repo_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'repo_type': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}), + 'repo_user': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'track': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'codespeed.report': { + 'Meta': {'unique_together': "(('revision', 'executable', 'environment'),)", 'object_name': 'Report'}, + '_tablecache': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'colorcode': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '10'}), + 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Environment']"}), + 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Executable']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Revision']"}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) + }, + 'codespeed.result': { + 'Meta': {'unique_together': "(('revision', 'executable', 'benchmark', 'environment'),)", 'object_name': 'Result'}, + 'benchmark': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Benchmark']"}), + 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Environment']"}), + 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Executable']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Revision']"}), + 'std_dev': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'val_max': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'val_min': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'value': ('django.db.models.fields.FloatField', [], {}) + }, + 'codespeed.revision': { + 'Meta': {'unique_together': "(('commitid', 'branch'),)", 'object_name': 'Revision'}, + 'author': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'branch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['codespeed.Branch']"}), + 'commitid': ('django.db.models.fields.CharField', [], {'max_length': '42'}), + 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['codespeed.Project']"}), + 'tag': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}) + } + } + + complete_apps = ['codespeed'] diff --git a/codespeed/models.py b/codespeed/models.py index 39488c2e..c2047271 100644 --- a/codespeed/models.py +++ b/codespeed/models.py @@ -28,7 +28,7 @@ def __unicode__(self): class Branch(models.Model): - name = models.CharField(max_length=20) + name = models.CharField(max_length=50) project = models.ForeignKey(Project, related_name="branches") def __unicode__(self): From 5dfa14f14d91f59cd64342947a337f73342d3d43 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 28 Nov 2014 09:10:43 +0200 Subject: [PATCH 017/134] tilt xlabels on Plot 2 --- example/templates/home.html | 1 + 1 file changed, 1 insertion(+) diff --git a/example/templates/home.html b/example/templates/home.html index 141abff3..6ce4b133 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -131,6 +131,7 @@ xaxis: { renderer: $.jqplot.CategoryAxisRenderer, ticks: ticks + tickOptions: {angle: -40} }, yaxis:{ // ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], From 38757655382dd7c97582bb7c722d9707cb03c48a Mon Sep 17 00:00:00 2001 From: mattip Date: Sat, 29 Nov 2014 21:33:21 +0200 Subject: [PATCH 018/134] whoops --- example/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/templates/home.html b/example/templates/home.html index 6ce4b133..aad5162f 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -130,7 +130,7 @@ axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, - ticks: ticks + ticks: ticks, tickOptions: {angle: -40} }, yaxis:{ From 5a3bb8ca11e6468a515a4550198d6c21870210ba Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 26 Dec 2014 14:39:47 +0200 Subject: [PATCH 019/134] test, fix angling x-axis on cpythonplot2 --- example/templates/home.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example/templates/home.html b/example/templates/home.html index aad5162f..8714ab73 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -122,6 +122,9 @@ renderer:$.jqplot.BarRenderer, showMarker: false }, + axesDefaults: { + tickRenderer: $.jqplot.CanvasAxisTickRenderer + }, series:[ { pointLabels:{labels:geolabels} From 97f81b699e45b8135a8249ee5b8687c73d6667f8 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 08:46:12 -0500 Subject: [PATCH 020/134] add a deploy-requirements.txt --- deploy-requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 deploy-requirements.txt diff --git a/deploy-requirements.txt b/deploy-requirements.txt new file mode 100644 index 00000000..ed1bed4e --- /dev/null +++ b/deploy-requirements.txt @@ -0,0 +1,3 @@ +. +psycopg2==2.7.7 +gunicorn==19.9.0 From 36086d3780632f86d4b90b0093b0e28d6cc6f0c6 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 09:20:55 -0500 Subject: [PATCH 021/134] add wsgi entrypoint --- example/wsgi.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 example/wsgi.py diff --git a/example/wsgi.py b/example/wsgi.py new file mode 100644 index 00000000..20b8f2d1 --- /dev/null +++ b/example/wsgi.py @@ -0,0 +1,8 @@ +# This is used for staging & production +import os +import sys + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() From 4fc00dd978602cd1a55d3856190cb3729426304c Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 10:01:38 -0500 Subject: [PATCH 022/134] allow local_settings.py overrides --- example/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/settings.py b/example/settings.py index f767132e..43cfb22c 100644 --- a/example/settings.py +++ b/example/settings.py @@ -175,3 +175,5 @@ def process_exception(self, request, exception): #DEF_BRANCH = "default" # Defines the default branch to be used. # In git projects, this branch is usually be calles # "master" + +from .local_settings import * From bcd448086cb8d4abce932364d8578e5f675dabf1 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 10:02:45 -0500 Subject: [PATCH 023/134] seems that this isn't handling Django > 1.4... --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5a6a5f18..9a0d5cd6 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ version='0.9.0', url='https://github.com/tobami/codespeed', license='GNU Lesser General Public License version 2.1', - install_requires=['django>=1.3', 'isodate', 'south'], + install_requires=['django>=1.3,<=1.5', 'isodate', 'south'], packages=find_packages(exclude=['ez_setup', 'example']), description='A web application to monitor and analyze the performance of your code', include_package_data=True, From fa1abb45291941600900fa83731eb90a18ba33e5 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 16:24:37 -0500 Subject: [PATCH 024/134] don't use a relative import --- example/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/settings.py b/example/settings.py index 43cfb22c..2aba39eb 100644 --- a/example/settings.py +++ b/example/settings.py @@ -176,4 +176,4 @@ def process_exception(self, request, exception): # In git projects, this branch is usually be calles # "master" -from .local_settings import * +from local_settings import * From b07808f27a65cac9ae4467f2d73f762023065d5c Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 16:41:55 -0500 Subject: [PATCH 025/134] make it so --- example/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/example/settings.py b/example/settings.py index 2aba39eb..956319d5 100644 --- a/example/settings.py +++ b/example/settings.py @@ -1,6 +1,10 @@ # -*- coding: utf-8 -*- # Django settings for a speedcenter project. import os +import os.path +import sys + +sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) DEBUG = True TEMPLATE_DEBUG = DEBUG From aae7f89d5b71c21e3f022ac683d3cd1319aaa9c2 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 14:16:08 +0200 Subject: [PATCH 026/134] Custom PyPy about.html --- sample_project/templates/about.html | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sample_project/templates/about.html b/sample_project/templates/about.html index 7eebe2e7..1c4d6a9c 100644 --- a/sample_project/templates/about.html +++ b/sample_project/templates/about.html @@ -5,18 +5,22 @@

About this site

-

<description of site and what benchmarks that are run>

+

We have nightly benchmark runs of pypy-c-jit and pypy-c, together with cpython 2.6.2 data for comparison.

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

+

The code can be found here and here.

+

About PyPy

+

PyPy is a very compliant implementation of the Python language.

+

Main website: pypy.org

+ +

Blog: morepypy.blogspot.com

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...

+

For problems or suggestions about this website write to

+

the pypy-dev mailing list or directly to Miquel Torres (tobami at googlemail dot com)

+
{% endblock %} From 9c3ec4d784da4ec8ffa7e034ad23d6e9585f4103 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:18:20 +0200 Subject: [PATCH 027/134] Custom PyPy settings --- example/settings.py | 174 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 example/settings.py diff --git a/example/settings.py b/example/settings.py new file mode 100644 index 00000000..8d7efaa3 --- /dev/null +++ b/example/settings.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +# Django settings for a speedcenter project. +import os + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +BASEDIR = os.path.dirname(__file__) + +#: The directory which should contain checked out source repositories: +REPOSITORY_BASE_PATH = os.path.join(BASEDIR, "repos") + +ADMINS = ( + # ('Your Name', 'your_email@domain.com'), +) + +MANAGERS = ADMINS +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASEDIR, 'data.db'), + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'America/Chicago' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = False + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +MEDIA_ROOT = os.path.join(BASEDIR, "media") + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash if there is a path component (optional in other cases). +# Examples: "http://media.lawrence.com", "http://example.com/media/" +MEDIA_URL = '/media/' + +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a +# trailing slash. +# Examples: "http://foo.com/media/", "/media/". +ADMIN_MEDIA_PREFIX = '/static/admin/' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'as%n_m#)^vee2pe91^^@c))sl7^c6t-9r8n)_69%)2yt+(la2&' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + # 'django.template.loaders.eggs.load_template_source', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', +) + +if DEBUG: + import traceback + import logging + + # Define a class that logs unhandled errors + class LogUncatchedErrors: + def process_exception(self, request, exception): + logging.error("Unhandled Exception on request for %s\n%s" % + (request.build_absolute_uri(), + traceback.format_exc())) + # And add it to the middleware classes + MIDDLEWARE_CLASSES += ('settings.LogUncatchedErrors',) + + # set shown level of logging output to debug + logging.basicConfig(level=logging.DEBUG) + + +ROOT_URLCONF = 'example.urls' + +TEMPLATE_DIRS = ( + os.path.join(os.path.dirname(__file__), 'templates'), +) + +TEMPLATE_CONTEXT_PROCESSORS = ( + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + 'django.core.context_processors.debug', + 'django.core.context_processors.i18n', + 'django.core.context_processors.media', + 'django.core.context_processors.static', + 'django.core.context_processors.request', +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + #'django.contrib.sites', + 'django.contrib.admin', + 'django.contrib.staticfiles', + 'codespeed', + 'south' +) + +STATIC_URL = '/static/' + +STATIC_ROOT = os.path.join(BASEDIR, "sitestatic") + +# Codespeed settings that can be overwritten here. +## General default options ## +#WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed + +#DEF_ENVIRONMENT = None #Name of the environment which should be selected as default + + +DEF_BASELINE = {'executable': 'cpython', 'revision': '100'} # Which executable + revision should be default as a baseline + # Given as the name of the executable and commitid of the revision + # Example: defaultbaseline = {'executable': 'myexe', 'revision': '21'} + +#TREND = 10 # Default value for the depth of the trend + # Used by reports for the latest runs and changes view + +# Threshold that determines when a performance change over the last result is significant +CHANGE_THRESHOLD = 5.0 + +# Threshold that determines when a performance change +# over a number of revisions is significant +TREND_THRESHOLD = 6.0 + +## Changes view options ## +#DEF_EXECUTABLE = None # Executable that should be chosen as default in the changes view + # Given as the name of the executable. + # Example: defaultexecutable = "myexe" + +## Timeline view options ## +#DEF_BENCHMARK = "grid" # Default selected benchmark. Possible values: + # "grid": will show the grid of plots + # "show_none": will just show a text message + # "mybench": will select benchmark "mybench" + +#TIMELINE_BRANCHES = True # NOTE: Only the default branch is currently shown + # Get timeline results for specific branches + # Set to False if you want timeline plots and results only for trunk. + +## Comparison view options ## +#CHART_TYPE = 'normal bars' # The options are 'normal bars', 'stacked bars' and 'relative bars' + +NORMALIZATION = True # True will enable normalization as the default selection + # in the Comparison view. The default normalization can be + # chosen in the defaultbaseline setting + +#CHART_ORIENTATION = 'vertical' # 'vertical' or 'horizontal can be chosen as + # default chart orientation + +COMP_EXECUTABLES = [('pypy-c-jit', 'L'), ('pypy-c', 'L')] # Which executable + revision should be checked as default + # Given as a list of tuples containing the + # name of an executable + commitid of a revision + # An 'L' denotes the last revision + # Example: + # COMP_EXECUTABLES = [ + # ('myexe', '21df2423ra'), + # ('myexe', 'L'),] + From 34f7def947d4d94f2b53a44262a1be069b45a75d Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:42:07 +0200 Subject: [PATCH 028/134] Add custom PyPy homepage --- codespeed/views.py | 44 ++++++++ example/settings.py | 2 +- sample_project/templates/home.html | 168 ++++++++++++++++++++++++++++- 3 files changed, 211 insertions(+), 3 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index b3da0f0f..14572462 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -841,6 +841,7 @@ def add_json_results(request): return HttpResponse("All result data saved successfully", status=202) +<<<<<<< HEAD def django_has_content_type(): return (django.VERSION[0] > 1 or (django.VERSION[0] == 1 and django.VERSION[1] >= 6)) @@ -874,3 +875,46 @@ def makeimage(request): response['Content-Disposition'] = 'attachment; filename=image.png' return response +def get_home_data(request): + if request.method != 'GET': + return HttpResponseNotAllowed('GET') + data = {'results': {}, 'benchmarks': []} + env = Environment.objects.get(name='tannit') + # Fetch CPython data + cp_exe = Executable.objects.get(name="cpython") + cp_lastrev = Revision.objects.filter( + branch__project=cp_exe.project).order_by('-date')[0] + cp_results = Result.objects.filter( + executable=cp_exe, revision=cp_lastrev, environment=env) + # Fetch PyPy trunk data + pp_exe = Executable.objects.get(name="pypy-c-jit") + pp_branch = Branch.objects.get(name="default", project=pp_exe.project) + pp_lastrev = Revision.objects.filter(branch=pp_branch).order_by('-date')[0] + pp_results = Result.objects.filter( + executable=pp_exe, revision=pp_lastrev, environment=env) + # Fetch PyPy tagged revisions + pp_taggedrevs = Revision.objects.filter( + project=pp_exe.project + ).exclude(tag="").order_by('date') + data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] + pp_results = {'PyPy trunk': pp_results} + for rev in pp_taggedrevs: + pp_results[rev.tag] = Result.objects.filter( + executable=pp_exe, revision=rev, environment=env) + # Save data + benchmarks = [] + for res in cp_results: + if res == 0: + continue + benchmarks.append(res.benchmark.name) + key = 'CPython ' + cp_lastrev.tag + data['results'][res.benchmark.name] = {key: res.value} + for rev_name in pp_results: + val = 0 + for pp_res in pp_results[rev_name]: + if pp_res.benchmark.name == res.benchmark.name: + val = pp_res.value + data['results'][res.benchmark.name][rev_name] = val + benchmarks.sort() + data['benchmarks'] = benchmarks + return HttpResponse(json.dumps( data )) diff --git a/example/settings.py b/example/settings.py index 8d7efaa3..73027dcf 100644 --- a/example/settings.py +++ b/example/settings.py @@ -119,7 +119,7 @@ def process_exception(self, request, exception): # Codespeed settings that can be overwritten here. ## General default options ## -#WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed +WEBSITE_NAME = "PyPy Speed Center" # This name will be used in the reports RSS feed #DEF_ENVIRONMENT = None #Name of the environment which should be selected as default diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 67848d37..14a33f92 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -30,7 +30,137 @@

Comparison

{% block extra_body %} {{ block.super }} + + + + + + + + + {% endblock %} +{% block navigation %} +{% endblock navigation %} + +{% block body %} +
+ + + +
+ +
+

How fast is PyPy?

+
+

Plot 1: The above plot represents PyPy trunk (with JIT) benchmark times normalized to CPython. Smaller is better.

+

While it depends greately on the type of taks being performed, currently PyPy takes % of the time that CPython needs to complete an average given task (represented by the geometric mean of all benchmarks), which means that PyPy is about times faster than CPython

+

How has PyPy performance evolved over time?

+
+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

+
+
+{% endblock body %} From ab6063cc2f244cba178e1ab5fa6045615902ee66 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:44:19 +0200 Subject: [PATCH 029/134] Add Google Analytics script --- example/templates/base.html | 75 +++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 example/templates/base.html diff --git a/example/templates/base.html b/example/templates/base.html new file mode 100644 index 00000000..cc60dfb4 --- /dev/null +++ b/example/templates/base.html @@ -0,0 +1,75 @@ + + + + {% block title %}PyPy's Speed Center{% endblock %} + + + + + + + + + {% block extra_head %}{% endblock %} + + +
+ {# TODO: Rename id=title to id=header and/or switch to
#} +
+ {% block page_header %} + {% block logo %} + logo + {% endblock logo %} +

{% block page_title %}SPEED CENTER{% endblock page_title %}

+ {% block top_nav %} + + {% endblock top_nav %} + {% endblock page_header %} +
+ +
+ +
+{% block body %} +
Base template
+{% endblock %} +
+
+{% block footer %} + + + +{% endblock %} +
+ + + + From 4adbb14598ba308be9a24311af3f683d6b1b10a9 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:45:05 +0200 Subject: [PATCH 030/134] Add pointlabels jqplot plugin for Home page plot --- .../static/js/jqplot/jqplot.pointLabels.min.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codespeed/static/js/jqplot/jqplot.pointLabels.min.js diff --git a/codespeed/static/js/jqplot/jqplot.pointLabels.min.js b/codespeed/static/js/jqplot/jqplot.pointLabels.min.js new file mode 100644 index 00000000..2bf8a86d --- /dev/null +++ b/codespeed/static/js/jqplot/jqplot.pointLabels.min.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2009 Chris Leonello + * jqPlot is currently available for use in all personal or commercial projects + * under both the MIT and GPL version 2.0 licenses. This means that you can + * choose the license that best suits your project and use it accordingly. + * + * Although not required, the author would appreciate an email letting him + * know of any substantial use of jqPlot. You can reach the author at: + * chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . + * + * If you are feeling kind and generous, consider supporting the project by + * making a donation at: http://www.jqplot.com/donate.php . + */ +(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=0;this.hideZeros=false;c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(k,h,g,e){var n=c.extend(true,{},g,e);this.plugins.pointLabels=new c.jqplot.PointLabels(n.pointLabels);var f=this.plugins.pointLabels;if(f.labels.length==0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){var m=f.seriesLabelIndex||this._plotData[0].length-1;for(var j=0;j');u.insertAfter(s.canvas);if(q.escapeHTML){u.text(m)}else{u.html(m)}var f=q.location;if(this.waterfall&&parseInt(m,10)<0){f=b[d[f]]}var l=v.u2p(y[r][0])+q.xOffset(u,f);var g=n.u2p(y[r][1])+q.yOffset(u,f);u.css("left",l);u.css("top",g);var j=l+c(u).width();var o=g+c(u).height();var x=q.edgeTolerance;var e=c(s.canvas).position().left;var t=c(s.canvas).position().top;var w=s.canvas.width+e;var k=s.canvas.height+t;if(l-xw||o+x>k){c(u).remove()}}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); \ No newline at end of file From de207b9b6414e23b47b2533915aae81707a8536e Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 15:56:00 +0200 Subject: [PATCH 031/134] Add PyPy favicon --- example/override/static/images/favicon.ico | Bin 0 -> 3230 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 example/override/static/images/favicon.ico diff --git a/example/override/static/images/favicon.ico b/example/override/static/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c79bb6ded95b2a0035b0a9c47c7f2785cfbed0c1 GIT binary patch literal 3230 zcmcIm2~ZSA6rJ5!&S41Xf;r$ zqM;n$@_8clzhRx^3y<0yxNOOWLwN@5E3@F(uoR~Af}pCc0X2Osa6&;p<3>tWSl8 zttqR^inqu?o%-HNTpdlKHY5kogI*c5YB9RcX!0AL5>p~plPM99)42uv)7P)el8tFh0|Do15q5JsypNP(wD|-W z%=Ct3Od?$KiwUoy`dGk=bce_xKQ-72J*`R{s)|NMX$*2p;;^_m1G$|Wk#V{V$>*xz zx;YI|7aI`vL+yZm*!69YmS@5wB@m+wwFh#s%gBZ_a|yAWoru{7Pa|sIQKC9t^ASIC z zoN0(7olWsXJYF3F0p~}_JVh`?wMbp1-#EY?CUQ57nWW2fJ1G9|UF!^L*olnZM@Tr< zgMg}S(6*TYfl#PVeV#K50}WhinFFTJ>MxzD!?dlQBR%V|8jgF`eP!!}TR}1LD{q8< zMGMP;)u42chg;UH={Q#(GoXL0DvFJ(We{h0U4g*J$ioLgTX!O)aW59%1B<z95Od)MG#;&E!Y(i%UY-`x-gcgaM?OCQX8lfJr^n4Ob-Aq~3;dk0gx zdl9f@VE$iL+vdG%1IhPwv<6Lc(7Y-L*5+cC!{#^9e99FFrqTAVzUB2qvF9+6e|8Yj z`%hxLsRe|h5hI@R{%xqMig;}eb^P3>1RMXi)iEf}@kU&PEkwNVZ%WIfU}wTm=1vJ; zi)|$ctZgO9-B(Cb*JaE;a0)JYYuR`{enkK`yUAi)Y)d3v&GFbxwy~Vp|0aqH9~c|LQ05Jvnyn}yw(c%b z3}t?16UU*uHGv#&NhJH~lvwpq5OQ*Zky#jt^b#c$>y>a>u7K5IIjr&$;jn2Lk+oG4 zS#uS9>Z&2Du7RTcFf#i7K+b)Fz?wET?w>~M>a+DQq=|TeDJA{3EZG?+_N3#>-Sbh` zl8zN+O3d3B5BWMJWW`C4mZU*inggebe0bEAz;8!AA`iABj(*x&s|NJs1RRa|Zo@b$`flh7@CaIenFm n-h7oK08g>{Kj1qGh)S>fW0i+|;n>HN&;015(^x74VcF#$?Vs(& literal 0 HcmV?d00001 From e2b197f24219ab99527d8a9a298c59d3b573a2d1 Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 17 Jul 2011 20:15:34 +0200 Subject: [PATCH 032/134] Add legend to first "home" plot --- codespeed/static/css/main.css | 2 +- sample_project/templates/home.html | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/codespeed/static/css/main.css b/codespeed/static/css/main.css index 34afa5bc..d1a2fbe3 100644 --- a/codespeed/static/css/main.css +++ b/codespeed/static/css/main.css @@ -119,7 +119,7 @@ div#presentation div.menubox { } div#presentation div.menubox:hover { border: 5px solid #FFCE9C; } -div#presentation p { height: 5em; padding-left: 120px; } +div#presentation div.menubox p { height: 5em; padding-left: 120px; } div#presentation div#changes p { background: url(../images/changes.png) no-repeat; diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 14a33f92..910bc79e 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -82,10 +82,11 @@

Comparison

} trunk_geomean = Math.pow(trunk_geomean, 1/plotdata[0].length); var geofaster = 1/trunk_geomean; - $('#geomean').html((100*trunk_geomean).toFixed(1)); + $('#geomean').html(trunk_geomean.toFixed(2)); $('#geofaster').html(geofaster.toFixed(1)); // Render first plot plotoptions1 = { + legend:{show:true}, seriesDefaults: { showMarker: false, rendererOptions:{barPadding: 2, barMargin:5} @@ -95,10 +96,14 @@

Comparison

}, series:[ { + label: 'PyPy trunk', renderer:$.jqplot.BarRenderer, pointLabels:{labels:labels} }, - {pointLabels:{show:false}} + { + label: 'CPython', + pointLabels:{show:false} + } ], axes: { xaxis: { @@ -113,7 +118,7 @@

Comparison

} }; plot1 = $.jqplot("cpythonplot", plotdata, plotoptions1); - + // Prepare and render second plot var geomeans = [1.0]; var num_of_benchs = 0; @@ -137,6 +142,7 @@

Comparison

geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); } $('#num_of_benchs').html(num_of_benchs) + plotoptions2 = { seriesDefaults: { renderer:$.jqplot.BarRenderer, @@ -210,12 +216,13 @@

Comparison


-
+

How fast is PyPy?

Plot 1: The above plot represents PyPy trunk (with JIT) benchmark times normalized to CPython. Smaller is better.

-

While it depends greately on the type of taks being performed, currently PyPy takes % of the time that CPython needs to complete an average given task (represented by the geometric mean of all benchmarks), which means that PyPy is about times faster than CPython

+

It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than CPython

How has PyPy performance evolved over time?

+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

From 209dab0af360166e390744a1bc32caa0a27a0fbf Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Mon, 18 Jul 2011 21:56:27 +0200 Subject: [PATCH 033/134] Don't choose a revision that doesn't have results for pypy-c-jit --- codespeed/views.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index 14572462..127e108d 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -886,21 +886,32 @@ def get_home_data(request): branch__project=cp_exe.project).order_by('-date')[0] cp_results = Result.objects.filter( executable=cp_exe, revision=cp_lastrev, environment=env) - # Fetch PyPy trunk data + pp_exe = Executable.objects.get(name="pypy-c-jit") pp_branch = Branch.objects.get(name="default", project=pp_exe.project) - pp_lastrev = Revision.objects.filter(branch=pp_branch).order_by('-date')[0] - pp_results = Result.objects.filter( - executable=pp_exe, revision=pp_lastrev, environment=env) # Fetch PyPy tagged revisions pp_taggedrevs = Revision.objects.filter( project=pp_exe.project ).exclude(tag="").order_by('date') data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] - pp_results = {'PyPy trunk': pp_results} + pp_results = {} for rev in pp_taggedrevs: pp_results[rev.tag] = Result.objects.filter( executable=pp_exe, revision=rev, environment=env) + + # Fetch PyPy trunk data + revs = Revision.objects.filter(branch=pp_branch).order_by('-date')[:5] + pp_lastrev = None + for i in range(4): + pp_lastrev = revs[i] + if pp_lastrev.results.filter(executable=pp_exe): + break + pp_lastrev = None + if pp_lastrev is None: + return HttpResponse(json.dumps( data )) + pp_results['PyPy trunk'] = Result.objects.filter( + executable=pp_exe, revision=pp_lastrev, environment=env) + # Save data benchmarks = [] for res in cp_results: From b5b96d13e0cee972265a5998555de532f477680a Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Sun, 21 Aug 2011 17:37:21 +0200 Subject: [PATCH 034/134] Improve pypy branch query, set WEBSITE_NAME and project name in template --- codespeed/settings.py | 2 +- codespeed/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codespeed/settings.py b/codespeed/settings.py index 4e3b5d59..d191b339 100644 --- a/codespeed/settings.py +++ b/codespeed/settings.py @@ -2,7 +2,7 @@ """Default settings for Codespeed""" ## General default options ## -WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed +WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed DEF_ENVIRONMENT = None # Name of the environment which should be selected as default diff --git a/codespeed/views.py b/codespeed/views.py index 127e108d..4837f56e 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -891,7 +891,7 @@ def get_home_data(request): pp_branch = Branch.objects.get(name="default", project=pp_exe.project) # Fetch PyPy tagged revisions pp_taggedrevs = Revision.objects.filter( - project=pp_exe.project + branch=pp_branch ).exclude(tag="").order_by('date') data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] pp_results = {} From 3e9c67f761284150f95972e5e8f9157c65b7d03c Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Thu, 17 May 2012 11:53:48 +0200 Subject: [PATCH 035/134] Use the proper key for CPython data Update default baseline Increase width of second graph --- codespeed/views.py | 4 ++-- example/settings.py | 2 +- sample_project/templates/home.html | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index 4837f56e..37f7db1a 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -884,6 +884,7 @@ def get_home_data(request): cp_exe = Executable.objects.get(name="cpython") cp_lastrev = Revision.objects.filter( branch__project=cp_exe.project).order_by('-date')[0] + data['baseline'] = 'CPython ' + cp_lastrev.tag cp_results = Result.objects.filter( executable=cp_exe, revision=cp_lastrev, environment=env) @@ -918,8 +919,7 @@ def get_home_data(request): if res == 0: continue benchmarks.append(res.benchmark.name) - key = 'CPython ' + cp_lastrev.tag - data['results'][res.benchmark.name] = {key: res.value} + data['results'][res.benchmark.name] = {data['baseline']: res.value} for rev_name in pp_results: val = 0 for pp_res in pp_results[rev_name]: diff --git a/example/settings.py b/example/settings.py index 73027dcf..061232f7 100644 --- a/example/settings.py +++ b/example/settings.py @@ -124,7 +124,7 @@ def process_exception(self, request, exception): #DEF_ENVIRONMENT = None #Name of the environment which should be selected as default -DEF_BASELINE = {'executable': 'cpython', 'revision': '100'} # Which executable + revision should be default as a baseline +DEF_BASELINE = {'executable': 'cpython', 'revision': '101'} # Which executable + revision should be default as a baseline # Given as the name of the executable and commitid of the revision # Example: defaultbaseline = {'executable': 'myexe', 'revision': '21'} diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 910bc79e..93baf3e7 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -66,7 +66,7 @@

Comparison

add_to_tagged_data = false; } if (add_to_tagged_data === false) { break; } - relative_value = data['results'][benchname][rev]/data['results'][benchname]['CPython 2.6.2']; + relative_value = data['results'][benchname][rev]/data['results'][benchname][data['baseline']]; tagged_data[i].push(relative_value) } // Only add benchmark if there are no 0 values @@ -74,7 +74,7 @@

Comparison

// First add benchmark benchmarks.push(benchname); // Add PyPy trunk and CPython's 1.0 value - relative_value = data['results'][benchname]['PyPy trunk']/data['results'][benchname]['CPython 2.6.2']; + relative_value = data['results'][benchname]['PyPy trunk']/data['results'][benchname][data['baseline']]; plotdata[0].push(relative_value); plotdata[1].push(1.0); labels.push(relative_value.toFixed(2)); @@ -101,7 +101,7 @@

Comparison

pointLabels:{labels:labels} }, { - label: 'CPython', + label: data['baseline'], pointLabels:{show:false} } ], @@ -112,7 +112,7 @@

Comparison

tickOptions: {angle: -40} }, yaxis:{ - ticks: [0, 0.25, 0.5, 0.75, 1, 1.25, 1.5], + ticks: [0, 0.25, 0.5, 0.75, 1, 1.25], tickOptions:{formatString:'%.2f'} } } @@ -132,7 +132,7 @@

Comparison

geomeans.push(tempgeo); } geomeans.push(trunk_geomean); - var ticks = ['CPython 2.6.2']; + var ticks = [data['baseline']]; for (var i in data['tagged_revs']) { ticks.push(data['tagged_revs'][i]); } @@ -223,7 +223,7 @@

How fast is PyPy?

It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than CPython

How has PyPy performance evolved over time?

-
+

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

From 23d5aafc8e47f8084f9f0c7a9f5316d36d72408c Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Fri, 8 Jun 2012 14:43:38 +0200 Subject: [PATCH 036/134] Invert plot 2 --- sample_project/templates/home.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 93baf3e7..2efcbc62 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -129,17 +129,19 @@

Comparison

tempgeo *= tagged_data[i][j]; } tempgeo = Math.pow(tempgeo, 1/tagged_data[i].length); + tempgeo = 1/tempgeo; geomeans.push(tempgeo); } - geomeans.push(trunk_geomean); + geomeans.push(1/trunk_geomean); var ticks = [data['baseline']]; for (var i in data['tagged_revs']) { ticks.push(data['tagged_revs'][i]); } ticks.push('PyPy trunk'); var geolabels = new Array(); - for (var i in geomeans) { - geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); + for (var i in geomeans) { +// geolabels.push(geomeans[i].toFixed(2) + " (" + (1/geomeans[i]).toFixed(1) + "x)"); + geolabels.push(geomeans[i].toFixed(2) + "x"); } $('#num_of_benchs').html(num_of_benchs) @@ -159,7 +161,8 @@

Comparison

ticks: ticks }, yaxis:{ - ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], +// ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], + min: 0, tickOptions:{formatString:'%.2f'} } } @@ -224,7 +227,7 @@

How fast is PyPy?

How has PyPy performance evolved over time?

-

Plot 2: Geometric averages of normalized times, out of benchmarks. Smaller is better. "times faster" inside parenthesis

+

Plot 2: Speedup compared to CPython, using the inverse of the geometric average of normalized times, out of benchmarks.

{% endblock body %} From c15ab3b5022bad228e01205e609ea9cd226b9cfa Mon Sep 17 00:00:00 2001 From: Miquel Torres Date: Fri, 8 Jun 2012 15:04:38 +0200 Subject: [PATCH 037/134] Add reference to paper explaining geometric mean for normalized results --- sample_project/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 2efcbc62..9b137b3d 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -227,7 +227,7 @@

How fast is PyPy?

How has PyPy performance evolved over time?

-

Plot 2: Speedup compared to CPython, using the inverse of the geometric average of normalized times, out of benchmarks.

+

Plot 2: Speedup compared to CPython, 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).

{% endblock body %} From cdb2941f0bd2e4a71425afc2bc7fd14645166a4f Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:19:33 -0800 Subject: [PATCH 038/134] exec wrapper script. --- manage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/manage.py b/manage.py index 1c3713d6..9f56f9db 100755 --- a/manage.py +++ b/manage.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import os, sys + if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample_project.settings") From 10bec1909510b04c1c7608df602f7cef2815da1e Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:25:18 -0800 Subject: [PATCH 039/134] unix is hard. --- manage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/manage.py b/manage.py index 9f56f9db..1c3713d6 100755 --- a/manage.py +++ b/manage.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os, sys - if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample_project.settings") From 29dec697781fd8a9a14bb9c3c7603976a45d1afc Mon Sep 17 00:00:00 2001 From: Noah Kantrowitz Date: Sun, 6 Jan 2013 12:32:53 -0800 Subject: [PATCH 040/134] No really, I'm bad at unix. --- manage.py | 1 - 1 file changed, 1 deletion(-) diff --git a/manage.py b/manage.py index 1c3713d6..dd62d642 100755 --- a/manage.py +++ b/manage.py @@ -5,5 +5,4 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample_project.settings") from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) From 92fd0b18e33c6ec6130ccbfa29ad51560c6114f6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 7 Jan 2013 12:21:12 -0800 Subject: [PATCH 041/134] Incrase the size of a field --- .../009_auto__chg_field_branch_name.py | 97 +++++++++++++++++++ codespeed/models.py | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 codespeed/migrations/009_auto__chg_field_branch_name.py diff --git a/codespeed/migrations/009_auto__chg_field_branch_name.py b/codespeed/migrations/009_auto__chg_field_branch_name.py new file mode 100644 index 00000000..f35dcc57 --- /dev/null +++ b/codespeed/migrations/009_auto__chg_field_branch_name.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Changing field 'Branch.name' + db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=50)) + + def backwards(self, orm): + # Changing field 'Branch.name' + db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) + + models = { + 'codespeed.benchmark': { + 'Meta': {'object_name': 'Benchmark'}, + 'benchmark_type': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '1'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'lessisbetter': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'units': ('django.db.models.fields.CharField', [], {'default': "'seconds'", 'max_length': '20'}), + 'units_title': ('django.db.models.fields.CharField', [], {'default': "'Time'", 'max_length': '30'}) + }, + 'codespeed.branch': { + 'Meta': {'unique_together': "(('name', 'project'),)", 'object_name': 'Branch'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'branches'", 'to': "orm['codespeed.Project']"}) + }, + 'codespeed.environment': { + 'Meta': {'object_name': 'Environment'}, + 'cpu': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'kernel': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'memory': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'os': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}) + }, + 'codespeed.executable': { + 'Meta': {'object_name': 'Executable'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'executables'", 'to': "orm['codespeed.Project']"}) + }, + 'codespeed.project': { + 'Meta': {'object_name': 'Project'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), + 'repo_pass': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'repo_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'repo_type': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}), + 'repo_user': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'track': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) + }, + 'codespeed.report': { + 'Meta': {'unique_together': "(('revision', 'executable', 'environment'),)", 'object_name': 'Report'}, + '_tablecache': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'colorcode': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '10'}), + 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Environment']"}), + 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Executable']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Revision']"}), + 'summary': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) + }, + 'codespeed.result': { + 'Meta': {'unique_together': "(('revision', 'executable', 'benchmark', 'environment'),)", 'object_name': 'Result'}, + 'benchmark': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Benchmark']"}), + 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Environment']"}), + 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Executable']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Revision']"}), + 'std_dev': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'val_max': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'val_min': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), + 'value': ('django.db.models.fields.FloatField', [], {}) + }, + 'codespeed.revision': { + 'Meta': {'unique_together': "(('commitid', 'branch'),)", 'object_name': 'Revision'}, + 'author': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'branch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['codespeed.Branch']"}), + 'commitid': ('django.db.models.fields.CharField', [], {'max_length': '42'}), + 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['codespeed.Project']"}), + 'tag': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}) + } + } + + complete_apps = ['codespeed'] diff --git a/codespeed/models.py b/codespeed/models.py index 4c707a7b..301c7545 100644 --- a/codespeed/models.py +++ b/codespeed/models.py @@ -104,7 +104,7 @@ def is_less_important_than(self, val, color): @python_2_unicode_compatible class Branch(models.Model): - name = models.CharField(max_length=32) + name = models.CharField(max_length=50) project = models.ForeignKey(Project, related_name="branches") def __str__(self): From 65a938d9870efaf1560555d1877f1b4eb1d4b80c Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 28 Nov 2014 09:10:43 +0200 Subject: [PATCH 042/134] tilt xlabels on Plot 2 --- sample_project/templates/home.html | 1 + 1 file changed, 1 insertion(+) diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 9b137b3d..60be12d8 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -159,6 +159,7 @@

Comparison

xaxis: { renderer: $.jqplot.CategoryAxisRenderer, ticks: ticks + tickOptions: {angle: -40} }, yaxis:{ // ticks: [0.0, 0.25, 0.5, 0.75, 1.0, 1.25], From 3de9041eda0ff9030eab603d9dc51fe465388e20 Mon Sep 17 00:00:00 2001 From: mattip Date: Sat, 29 Nov 2014 21:33:21 +0200 Subject: [PATCH 043/134] whoops --- sample_project/templates/home.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 60be12d8..ce8c4272 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -158,7 +158,7 @@

Comparison

axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, - ticks: ticks + ticks: ticks, tickOptions: {angle: -40} }, yaxis:{ From 92d277dbb3b6d1ccc10df2fef2ceef392a737edd Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 26 Dec 2014 14:39:47 +0200 Subject: [PATCH 044/134] test, fix angling x-axis on cpythonplot2 --- sample_project/templates/home.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index ce8c4272..094c987d 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -150,6 +150,9 @@

Comparison

renderer:$.jqplot.BarRenderer, showMarker: false }, + axesDefaults: { + tickRenderer: $.jqplot.CanvasAxisTickRenderer + }, series:[ { pointLabels:{labels:geolabels} From bfccbec29ef10981762562df821b20fb488d7473 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 08:46:12 -0500 Subject: [PATCH 045/134] add a deploy-requirements.txt --- deploy-requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 deploy-requirements.txt diff --git a/deploy-requirements.txt b/deploy-requirements.txt new file mode 100644 index 00000000..ed1bed4e --- /dev/null +++ b/deploy-requirements.txt @@ -0,0 +1,3 @@ +. +psycopg2==2.7.7 +gunicorn==19.9.0 From 5f4eeedbb97e2a238ce5667d9baaa94f590a545d Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 09:20:55 -0500 Subject: [PATCH 046/134] add wsgi entrypoint --- example/wsgi.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 example/wsgi.py diff --git a/example/wsgi.py b/example/wsgi.py new file mode 100644 index 00000000..20b8f2d1 --- /dev/null +++ b/example/wsgi.py @@ -0,0 +1,8 @@ +# This is used for staging & production +import os +import sys + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() From f15a60584a5f0361a8e1ca2e8a97c7da31346b76 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 10:01:38 -0500 Subject: [PATCH 047/134] allow local_settings.py overrides --- example/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example/settings.py b/example/settings.py index 061232f7..b1dc01ac 100644 --- a/example/settings.py +++ b/example/settings.py @@ -172,3 +172,4 @@ def process_exception(self, request, exception): # ('myexe', '21df2423ra'), # ('myexe', 'L'),] +from .local_settings import * From f7cbe313403dfab7bbcbec9e0b1695e9233ae835 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 10:02:45 -0500 Subject: [PATCH 048/134] seems that this isn't handling Django > 1.4... --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 80ba4b89..025cfd16 100644 --- a/setup.py +++ b/setup.py @@ -31,3 +31,4 @@ 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', ] ) + From a586c60e26effef090f99f30a5c93f5056109727 Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 16:24:37 -0500 Subject: [PATCH 049/134] don't use a relative import --- example/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example/settings.py b/example/settings.py index b1dc01ac..5436a9a1 100644 --- a/example/settings.py +++ b/example/settings.py @@ -173,3 +173,4 @@ def process_exception(self, request, exception): # ('myexe', 'L'),] from .local_settings import * + From 1e08ed172e174aa13a0ba05c853badf90053c5ea Mon Sep 17 00:00:00 2001 From: Ernest W Durbin III Date: Fri, 22 Feb 2019 16:41:55 -0500 Subject: [PATCH 050/134] make it so --- example/settings.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/example/settings.py b/example/settings.py index 5436a9a1..f63cf7ae 100644 --- a/example/settings.py +++ b/example/settings.py @@ -1,6 +1,10 @@ # -*- coding: utf-8 -*- # Django settings for a speedcenter project. import os +import os.path +import sys + +sys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) DEBUG = True TEMPLATE_DEBUG = DEBUG From 984b0d8a240a5237f9116b5ddaf7bc8eca6996e3 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 2 Apr 2019 22:53:46 +0300 Subject: [PATCH 051/134] fix merge and update --- codespeed/commits/mercurial.py | 2 +- .../009_auto__chg_field_branch_name.py | 97 ------------------ codespeed/models.py | 2 +- codespeed/settings.py | 2 +- .../static/images/favicon.ico | Bin codespeed/views.py | 55 ---------- sample_project/settings.py | 14 ++- sample_project/templates/about.html | 7 +- .../templates/codespeed/base_site.html | 2 +- sample_project/templates/home.html | 37 +------ 10 files changed, 24 insertions(+), 194 deletions(-) delete mode 100644 codespeed/migrations/009_auto__chg_field_branch_name.py rename {example/override => codespeed}/static/images/favicon.ico (100%) diff --git a/codespeed/commits/mercurial.py b/codespeed/commits/mercurial.py index de0c63e8..ffe132eb 100644 --- a/codespeed/commits/mercurial.py +++ b/codespeed/commits/mercurial.py @@ -63,7 +63,7 @@ def getlogs(endrev, startrev): if p.returncode != 0: raise CommitLogError(str(stderr)) else: - stdout = stdout.rstrip('\n') # Remove last newline + stdout = stdout.rstrip(b'\n') # Remove last newline logs = [] for log in stdout.split("=newlog=\n"): elements = [] diff --git a/codespeed/migrations/009_auto__chg_field_branch_name.py b/codespeed/migrations/009_auto__chg_field_branch_name.py deleted file mode 100644 index f35dcc57..00000000 --- a/codespeed/migrations/009_auto__chg_field_branch_name.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Changing field 'Branch.name' - db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=50)) - - def backwards(self, orm): - # Changing field 'Branch.name' - db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) - - models = { - 'codespeed.benchmark': { - 'Meta': {'object_name': 'Benchmark'}, - 'benchmark_type': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '1'}), - 'description': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'lessisbetter': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'units': ('django.db.models.fields.CharField', [], {'default': "'seconds'", 'max_length': '20'}), - 'units_title': ('django.db.models.fields.CharField', [], {'default': "'Time'", 'max_length': '30'}) - }, - 'codespeed.branch': { - 'Meta': {'unique_together': "(('name', 'project'),)", 'object_name': 'Branch'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'branches'", 'to': "orm['codespeed.Project']"}) - }, - 'codespeed.environment': { - 'Meta': {'object_name': 'Environment'}, - 'cpu': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'kernel': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'memory': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'os': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}) - }, - 'codespeed.executable': { - 'Meta': {'object_name': 'Executable'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'executables'", 'to': "orm['codespeed.Project']"}) - }, - 'codespeed.project': { - 'Meta': {'object_name': 'Project'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'repo_pass': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), - 'repo_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'repo_type': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}), - 'repo_user': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), - 'track': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'codespeed.report': { - 'Meta': {'unique_together': "(('revision', 'executable', 'environment'),)", 'object_name': 'Report'}, - '_tablecache': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'colorcode': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '10'}), - 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Environment']"}), - 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Executable']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Revision']"}), - 'summary': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) - }, - 'codespeed.result': { - 'Meta': {'unique_together': "(('revision', 'executable', 'benchmark', 'environment'),)", 'object_name': 'Result'}, - 'benchmark': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Benchmark']"}), - 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Environment']"}), - 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Executable']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Revision']"}), - 'std_dev': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'val_max': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'val_min': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'value': ('django.db.models.fields.FloatField', [], {}) - }, - 'codespeed.revision': { - 'Meta': {'unique_together': "(('commitid', 'branch'),)", 'object_name': 'Revision'}, - 'author': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'branch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['codespeed.Branch']"}), - 'commitid': ('django.db.models.fields.CharField', [], {'max_length': '42'}), - 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['codespeed.Project']"}), - 'tag': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}) - } - } - - complete_apps = ['codespeed'] diff --git a/codespeed/models.py b/codespeed/models.py index f673d43c..82e55444 100644 --- a/codespeed/models.py +++ b/codespeed/models.py @@ -475,7 +475,7 @@ def get_changes_table(self, trend_depth=10, force_save=False): val_max = "-" # Calculate percentage change relative to previous result - result = resobj.value + result = max(resobj.value, 0) change = "-" if len(change_list): c = change_list.filter(benchmark=bench) diff --git a/codespeed/settings.py b/codespeed/settings.py index 70390e0e..42a38678 100644 --- a/codespeed/settings.py +++ b/codespeed/settings.py @@ -2,7 +2,7 @@ """Default settings for Codespeed""" ## General default options ## -WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed +WEBSITE_NAME = "MySpeedSite" # This name will be used in the reports RSS feed DEF_ENVIRONMENT = None # Name of the environment which should be selected as default diff --git a/example/override/static/images/favicon.ico b/codespeed/static/images/favicon.ico similarity index 100% rename from example/override/static/images/favicon.ico rename to codespeed/static/images/favicon.ico diff --git a/codespeed/views.py b/codespeed/views.py index 8199db54..b498bdb4 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -926,7 +926,6 @@ def add_json_results(request): return HttpResponse("All result data saved successfully", status=202) -<<<<<<< HEAD def django_has_content_type(): return (django.VERSION[0] > 1 or (django.VERSION[0] == 1 and django.VERSION[1] >= 6)) @@ -960,57 +959,3 @@ def makeimage(request): response['Content-Disposition'] = 'attachment; filename=image.png' return response -def get_home_data(request): - if request.method != 'GET': - return HttpResponseNotAllowed('GET') - data = {'results': {}, 'benchmarks': []} - env = Environment.objects.get(name='tannit') - # Fetch CPython data - cp_exe = Executable.objects.get(name="cpython") - cp_lastrev = Revision.objects.filter( - branch__project=cp_exe.project).order_by('-date')[0] - data['baseline'] = 'CPython ' + cp_lastrev.tag - cp_results = Result.objects.filter( - executable=cp_exe, revision=cp_lastrev, environment=env) - - pp_exe = Executable.objects.get(name="pypy-c-jit") - pp_branch = Branch.objects.get(name="default", project=pp_exe.project) - # Fetch PyPy tagged revisions - pp_taggedrevs = Revision.objects.filter( - branch=pp_branch - ).exclude(tag="").order_by('date') - data['tagged_revs'] = [rev.tag for rev in pp_taggedrevs] - pp_results = {} - for rev in pp_taggedrevs: - pp_results[rev.tag] = Result.objects.filter( - executable=pp_exe, revision=rev, environment=env) - - # Fetch PyPy trunk data - revs = Revision.objects.filter(branch=pp_branch).order_by('-date')[:5] - pp_lastrev = None - for i in range(4): - pp_lastrev = revs[i] - if pp_lastrev.results.filter(executable=pp_exe): - break - pp_lastrev = None - if pp_lastrev is None: - return HttpResponse(json.dumps( data )) - pp_results['PyPy trunk'] = Result.objects.filter( - executable=pp_exe, revision=pp_lastrev, environment=env) - - # Save data - benchmarks = [] - for res in cp_results: - if res == 0: - continue - benchmarks.append(res.benchmark.name) - data['results'][res.benchmark.name] = {data['baseline']: res.value} - for rev_name in pp_results: - val = 0 - for pp_res in pp_results[rev_name]: - if pp_res.benchmark.name == res.benchmark.name: - val = pp_res.value - data['results'][res.benchmark.name][rev_name] = val - benchmarks.sort() - data['benchmarks'] = benchmarks - return HttpResponse(json.dumps( data )) diff --git a/sample_project/settings.py b/sample_project/settings.py index 71a58745..d0c98f79 100644 --- a/sample_project/settings.py +++ b/sample_project/settings.py @@ -2,6 +2,9 @@ # Django settings for a Codespeed project. import os +from codespeed.settings import * +WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed + DEBUG = True BASEDIR = os.path.abspath(os.path.dirname(__file__)) @@ -34,8 +37,6 @@ MEDIA_URL = '/media/' -ADMIN_MEDIA_PREFIX = '/static/admin/' - SECRET_KEY = 'as%n_m#)^vee2pe91^^@c))sl7^c6t-9r8n)_69%)2yt+(la2&' @@ -83,6 +84,11 @@ os.path.join(BASEDIR, 'static'), ) +SHOW_REPORTS = False +SHOW_HISTORICAL = True +DEF_BASELINE = {'executable': 'cpython', 'revision': '2.6.2'} +DEF_EXECUTABLE = 'pypy-c-jit' +DEF_ENVIRONMENT = 'tannit' -# Codespeed settings that can be overwritten here. -from codespeed.settings import * + +from .local_settings import * diff --git a/sample_project/templates/about.html b/sample_project/templates/about.html index 1c4d6a9c..f05d10b1 100644 --- a/sample_project/templates/about.html +++ b/sample_project/templates/about.html @@ -5,10 +5,13 @@

About this site

-

We have nightly benchmark runs of pypy-c-jit and pypy-c, together with cpython 2.6.2 data for comparison.

+

We have nightly benchmark runs of pypy, together with cpython 2.6.2 data for comparison.

This site runs on top of Django and Codespeed

About the benchmarks

-

The code can be found here and here.

+

The code can be found here.

+

This is a benchmark suite based on Unladen Swallow, adapted for PyPY and +runs on Python2. For a port of these benchmarks to Python3 see the python speed site

About PyPy

PyPy is a very compliant implementation of the Python language.

Main website: pypy.org

diff --git a/sample_project/templates/codespeed/base_site.html b/sample_project/templates/codespeed/base_site.html index 0ba7ca30..5f5c6a01 100644 --- a/sample_project/templates/codespeed/base_site.html +++ b/sample_project/templates/codespeed/base_site.html @@ -1,5 +1,5 @@ {% extends "codespeed/base.html" %} {% block title %} - My Own Title + PyPy Speed {% endblock %} diff --git a/sample_project/templates/home.html b/sample_project/templates/home.html index 51ed27c4..2a0ddf3c 100644 --- a/sample_project/templates/home.html +++ b/sample_project/templates/home.html @@ -179,6 +179,9 @@

How has {{ default_exe.project }} performance evolved over time?

renderer:$.jqplot.BarRenderer, showMarker: false }, + axesDefaults: { + tickRenderer: $.jqplot.CanvasAxisTickRenderer + }, series:[ { pointLabels:{labels:geolabels} @@ -187,7 +190,8 @@

How has {{ default_exe.project }} performance evolved over time?

axes: { xaxis: { renderer: $.jqplot.CategoryAxisRenderer, - ticks: ticks + ticks: ticks, + tickOptions: {angle: -40} }, yaxis:{ min: 0, @@ -210,34 +214,3 @@

How has {{ default_exe.project }} performance evolved over time?

}); {% endblock %} -{% block navigation %} -{% endblock navigation %} - -{% block body %} -
- - - -
- -
-

How fast is PyPy?

-
-

Plot 1: The above plot represents PyPy trunk (with JIT) benchmark times normalized to CPython. Smaller is better.

-

It depends greatly on the type of task being performed. The geometric average of all benchmarks is or times faster than CPython

-

How has PyPy performance evolved over time?

- -
-

Plot 2: Speedup compared to CPython, 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).

-
-
-{% endblock body %} From ba2fd712b6f063c20c77acd5e28a351795845e92 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 3 Apr 2019 12:45:28 +0300 Subject: [PATCH 052/134] ENH: handle environment for historical data --- codespeed/views.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index b498bdb4..bff0a0be 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -94,12 +94,20 @@ def gethistoricaldata(request): # Fetch Baseline data baseline_exe = Executable.objects.get( name=settings.DEF_BASELINE['executable']) - baseline_lastrev = Revision.objects.filter( - branch__project=baseline_exe.project).order_by('-date')[0] + baseline_revs = Revision.objects.filter( + branch__project=baseline_exe.project).order_by('-date') + baseline_lastrev = baseline_revs[0] + for rev in baseline_revs: + baseline_results = Result.objects.filter( + executable=baseline_exe, revision=rev, environment=env) + if baseline_results: + baseline_lastrev = rev + break + if len(baseline_results) == 0: + logger.error('Could not find results for {} rev="{}" env="{}"'.format( + baseline_exe, baseline_lastrev, env)) data['baseline'] = '{} {}'.format( settings.DEF_BASELINE['executable'], baseline_lastrev.tag) - baseline_results = Result.objects.filter( - executable=baseline_exe, revision=baseline_lastrev, environment=env) default_exe = Executable.objects.get(name=settings.DEF_EXECUTABLE) default_branch = Branch.objects.get( @@ -108,21 +116,24 @@ def gethistoricaldata(request): # Fetch tagged revisions for default executable default_taggedrevs = Revision.objects.filter( - branch=default_branch - ).exclude(tag="").order_by('date') - data['tagged_revs'] = [rev.tag for rev in default_taggedrevs] + branch=default_branch + ).exclude(tag="").order_by('date') default_results = {} for rev in default_taggedrevs: - default_results[rev.tag] = Result.objects.filter( + res = Result.objects.filter( executable=default_exe, revision=rev, environment=env) - + if not res: + logger.info('no results for %s %s %s' % (str(default_exe), str(rev), str(env))) + continue + default_results[rev.tag] = res + data['tagged_revs'] = [rev.tag for rev in default_taggedrevs if rev.tag in default_results] # Fetch data for latest results revs = Revision.objects.filter( branch=default_branch).order_by('-date')[:5] default_lastrev = None for i in range(4): default_lastrev = revs[i] - if default_lastrev.results.filter(executable=default_exe): + if default_lastrev.results.filter(executable=default_exe, environment=env): break default_lastrev = None if default_lastrev is None: @@ -892,7 +903,6 @@ def add_result(request): return HttpResponseBadRequest(response) else: create_report_if_enough_data(response[0], response[1], response[2]) - logger.debug("add_result: completed") return HttpResponse("Result data saved successfully", status=202) @@ -917,12 +927,9 @@ def add_json_results(request): else: unique_reports.add(response) - logger.debug("add_json_results: about to create reports") for rep in unique_reports: create_report_if_enough_data(rep[0], rep[1], rep[2]) - logger.debug("add_json_results: completed") - return HttpResponse("All result data saved successfully", status=202) From 039f99e05cc2db99ba20ccf70f214d3d7143473f Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 4 Apr 2019 13:01:20 +0300 Subject: [PATCH 053/134] remove file from old data model --- .../009_auto__chg_field_branch_name.py | 97 ------------------- 1 file changed, 97 deletions(-) delete mode 100644 codespeed/migrations/009_auto__chg_field_branch_name.py diff --git a/codespeed/migrations/009_auto__chg_field_branch_name.py b/codespeed/migrations/009_auto__chg_field_branch_name.py deleted file mode 100644 index f35dcc57..00000000 --- a/codespeed/migrations/009_auto__chg_field_branch_name.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Changing field 'Branch.name' - db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=50)) - - def backwards(self, orm): - # Changing field 'Branch.name' - db.alter_column('codespeed_branch', 'name', self.gf('django.db.models.fields.CharField')(max_length=20)) - - models = { - 'codespeed.benchmark': { - 'Meta': {'object_name': 'Benchmark'}, - 'benchmark_type': ('django.db.models.fields.CharField', [], {'default': "'C'", 'max_length': '1'}), - 'description': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'lessisbetter': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'units': ('django.db.models.fields.CharField', [], {'default': "'seconds'", 'max_length': '20'}), - 'units_title': ('django.db.models.fields.CharField', [], {'default': "'Time'", 'max_length': '30'}) - }, - 'codespeed.branch': { - 'Meta': {'unique_together': "(('name', 'project'),)", 'object_name': 'Branch'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'branches'", 'to': "orm['codespeed.Project']"}) - }, - 'codespeed.environment': { - 'Meta': {'object_name': 'Environment'}, - 'cpu': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'kernel': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'memory': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'os': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}) - }, - 'codespeed.executable': { - 'Meta': {'object_name': 'Executable'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'executables'", 'to': "orm['codespeed.Project']"}) - }, - 'codespeed.project': { - 'Meta': {'object_name': 'Project'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}), - 'repo_pass': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), - 'repo_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'repo_type': ('django.db.models.fields.CharField', [], {'default': "'N'", 'max_length': '1'}), - 'repo_user': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), - 'track': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'codespeed.report': { - 'Meta': {'unique_together': "(('revision', 'executable', 'environment'),)", 'object_name': 'Report'}, - '_tablecache': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'colorcode': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '10'}), - 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Environment']"}), - 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Executable']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reports'", 'to': "orm['codespeed.Revision']"}), - 'summary': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}) - }, - 'codespeed.result': { - 'Meta': {'unique_together': "(('revision', 'executable', 'benchmark', 'environment'),)", 'object_name': 'Result'}, - 'benchmark': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Benchmark']"}), - 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'environment': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Environment']"}), - 'executable': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Executable']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'revision': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'results'", 'to': "orm['codespeed.Revision']"}), - 'std_dev': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'val_max': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'val_min': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}), - 'value': ('django.db.models.fields.FloatField', [], {}) - }, - 'codespeed.revision': { - 'Meta': {'unique_together': "(('commitid', 'branch'),)", 'object_name': 'Revision'}, - 'author': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'branch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['codespeed.Branch']"}), - 'commitid': ('django.db.models.fields.CharField', [], {'max_length': '42'}), - 'date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'message': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['codespeed.Project']"}), - 'tag': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}) - } - } - - complete_apps = ['codespeed'] From f3b5c847b44f4d29c7439088f018b8ccc5a3f369 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 4 Apr 2019 13:01:30 +0300 Subject: [PATCH 054/134] fix merge --- codespeed/views.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/codespeed/views.py b/codespeed/views.py index d2fe258b..7cbdfccd 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -931,3 +931,37 @@ def add_json_results(request): create_report_if_enough_data(rep[0], rep[1], rep[2]) return HttpResponse("All result data saved successfully", status=202) + +def django_has_content_type(): + return (django.VERSION[0] > 1 or + (django.VERSION[0] == 1 and django.VERSION[1] >= 6)) + + +@require_GET +def makeimage(request): + data = request.GET + + try: + validate_results_request(data) + except ValidationError as err: + return HttpResponseBadRequest(str(err)) + + try: + result_data = get_benchmark_results(data) + except ObjectDoesNotExist as err: + return HttpResponseNotFound(str(err)) + + image_data = gen_image_from_results( + result_data, + int(data['width']) if 'width' in data else None, + int(data['height']) if 'height' in data else None) + + if django_has_content_type(): + response = HttpResponse(content=image_data, content_type='image/png') + else: + response = HttpResponse(content=image_data, mimetype='image/png') + + response['Content-Length'] = len(image_data) + response['Content-Disposition'] = 'attachment; filename=image.png' + + return response From 4751450236f2b6911767204937f894a1b4555a90 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 8 Apr 2019 19:19:30 +0300 Subject: [PATCH 055/134] move from sample_project to speed_pypy --- sample_project/settings.py | 14 +-- {sample_project => speed_pypy}/README.md | 0 {sample_project => speed_pypy}/__init__.py | 0 speed_pypy/settings.py | 94 +++++++++++++++++++ .../templates/404.html | 0 .../templates/500.html | 0 .../templates/about.html | 0 .../templates/admin/base_site.html | 0 .../templates/codespeed/base_site.html | 0 .../templates/feeds/latest_description.html | 0 .../templates/feeds/latest_title.html | 0 .../templates/home.html | 0 {sample_project => speed_pypy}/urls.py | 0 {example => speed_pypy}/wsgi.py | 0 14 files changed, 98 insertions(+), 10 deletions(-) rename {sample_project => speed_pypy}/README.md (100%) rename {sample_project => speed_pypy}/__init__.py (100%) create mode 100644 speed_pypy/settings.py rename {sample_project => speed_pypy}/templates/404.html (100%) rename {sample_project => speed_pypy}/templates/500.html (100%) rename {sample_project => speed_pypy}/templates/about.html (100%) rename {sample_project => speed_pypy}/templates/admin/base_site.html (100%) rename {sample_project => speed_pypy}/templates/codespeed/base_site.html (100%) rename {sample_project => speed_pypy}/templates/feeds/latest_description.html (100%) rename {sample_project => speed_pypy}/templates/feeds/latest_title.html (100%) rename {sample_project => speed_pypy}/templates/home.html (100%) rename {sample_project => speed_pypy}/urls.py (100%) rename {example => speed_pypy}/wsgi.py (100%) diff --git a/sample_project/settings.py b/sample_project/settings.py index d0c98f79..71a58745 100644 --- a/sample_project/settings.py +++ b/sample_project/settings.py @@ -2,9 +2,6 @@ # Django settings for a Codespeed project. import os -from codespeed.settings import * -WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed - DEBUG = True BASEDIR = os.path.abspath(os.path.dirname(__file__)) @@ -37,6 +34,8 @@ MEDIA_URL = '/media/' +ADMIN_MEDIA_PREFIX = '/static/admin/' + SECRET_KEY = 'as%n_m#)^vee2pe91^^@c))sl7^c6t-9r8n)_69%)2yt+(la2&' @@ -84,11 +83,6 @@ os.path.join(BASEDIR, 'static'), ) -SHOW_REPORTS = False -SHOW_HISTORICAL = True -DEF_BASELINE = {'executable': 'cpython', 'revision': '2.6.2'} -DEF_EXECUTABLE = 'pypy-c-jit' -DEF_ENVIRONMENT = 'tannit' - -from .local_settings import * +# Codespeed settings that can be overwritten here. +from codespeed.settings import * diff --git a/sample_project/README.md b/speed_pypy/README.md similarity index 100% rename from sample_project/README.md rename to speed_pypy/README.md diff --git a/sample_project/__init__.py b/speed_pypy/__init__.py similarity index 100% rename from sample_project/__init__.py rename to speed_pypy/__init__.py diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py new file mode 100644 index 00000000..d0c98f79 --- /dev/null +++ b/speed_pypy/settings.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# Django settings for a Codespeed project. +import os + +from codespeed.settings import * +WEBSITE_NAME = "PyPy's Speed Center" # This name will be used in the reports RSS feed + +DEBUG = True + +BASEDIR = os.path.abspath(os.path.dirname(__file__)) +TOPDIR = os.path.split(BASEDIR)[1] + +#: The directory which should contain checked out source repositories: +REPOSITORY_BASE_PATH = os.path.join(BASEDIR, "repos") + +ADMINS = ( + # ('Your Name', 'your_email@domain.com'), +) + +MANAGERS = ADMINS +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASEDIR, 'data.db'), + } +} + +TIME_ZONE = 'America/Chicago' + +LANGUAGE_CODE = 'en-us' + +SITE_ID = 1 + +USE_I18N = False + +MEDIA_ROOT = os.path.join(BASEDIR, "media") + +MEDIA_URL = '/media/' + +SECRET_KEY = 'as%n_m#)^vee2pe91^^@c))sl7^c6t-9r8n)_69%)2yt+(la2&' + + +MIDDLEWARE = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', +) + +ROOT_URLCONF = '{0}.urls'.format(TOPDIR) + + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASEDIR, 'templates')], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.admin', + 'django.contrib.staticfiles', + 'codespeed', +) + + +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASEDIR, "sitestatic") +STATICFILES_DIRS = ( + os.path.join(BASEDIR, 'static'), +) + +SHOW_REPORTS = False +SHOW_HISTORICAL = True +DEF_BASELINE = {'executable': 'cpython', 'revision': '2.6.2'} +DEF_EXECUTABLE = 'pypy-c-jit' +DEF_ENVIRONMENT = 'tannit' + + +from .local_settings import * diff --git a/sample_project/templates/404.html b/speed_pypy/templates/404.html similarity index 100% rename from sample_project/templates/404.html rename to speed_pypy/templates/404.html diff --git a/sample_project/templates/500.html b/speed_pypy/templates/500.html similarity index 100% rename from sample_project/templates/500.html rename to speed_pypy/templates/500.html diff --git a/sample_project/templates/about.html b/speed_pypy/templates/about.html similarity index 100% rename from sample_project/templates/about.html rename to speed_pypy/templates/about.html 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/sample_project/templates/codespeed/base_site.html b/speed_pypy/templates/codespeed/base_site.html similarity index 100% rename from sample_project/templates/codespeed/base_site.html rename to speed_pypy/templates/codespeed/base_site.html diff --git a/sample_project/templates/feeds/latest_description.html b/speed_pypy/templates/feeds/latest_description.html similarity index 100% rename from sample_project/templates/feeds/latest_description.html rename to speed_pypy/templates/feeds/latest_description.html 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/sample_project/templates/home.html b/speed_pypy/templates/home.html similarity index 100% rename from sample_project/templates/home.html rename to speed_pypy/templates/home.html diff --git a/sample_project/urls.py b/speed_pypy/urls.py similarity index 100% rename from sample_project/urls.py rename to speed_pypy/urls.py diff --git a/example/wsgi.py b/speed_pypy/wsgi.py similarity index 100% rename from example/wsgi.py rename to speed_pypy/wsgi.py From e065bbd79952b4c7cc4b2fb49a6cc0242ae6e137 Mon Sep 17 00:00:00 2001 From: "Ernest W. Durbin III" Date: Mon, 8 Apr 2019 11:35:18 -0500 Subject: [PATCH 056/134] Update wsgi.py --- speed_pypy/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/speed_pypy/wsgi.py b/speed_pypy/wsgi.py index 20b8f2d1..6d7a2a33 100644 --- a/speed_pypy/wsgi.py +++ b/speed_pypy/wsgi.py @@ -2,7 +2,7 @@ import os import sys -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "speed_pypy.settings") from django.core.wsgi import get_wsgi_application application = get_wsgi_application() From 09aa41cd0c11da1cdd8c8ee0804f7f94e6167e28 Mon Sep 17 00:00:00 2001 From: "Ernest W. Durbin III" Date: Mon, 8 Apr 2019 11:46:27 -0500 Subject: [PATCH 057/134] update manage.py settings --- manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage.py b/manage.py index 91328678..7cfa57cd 100755 --- a/manage.py +++ b/manage.py @@ -2,7 +2,7 @@ import os, sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sample_project.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "speed_pypy.settings") from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) From a709f47632b7be5241cdbab3bf0d5dc5038db245 Mon Sep 17 00:00:00 2001 From: "Ernest W. Durbin III" Date: Mon, 8 Apr 2019 12:15:45 -0500 Subject: [PATCH 058/134] make this directory so collectstatic doesn't complain --- speed_pypy/static/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 speed_pypy/static/.gitkeep diff --git a/speed_pypy/static/.gitkeep b/speed_pypy/static/.gitkeep new file mode 100644 index 00000000..e69de29b From 2f3ee82aee95d245dd48bf85e472ccc2b9b41d02 Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 19 Apr 2019 11:56:43 +0300 Subject: [PATCH 059/134] BUG: stdout is bytes, convert to str --- codespeed/commits/mercurial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codespeed/commits/mercurial.py b/codespeed/commits/mercurial.py index ffe132eb..828521f3 100644 --- a/codespeed/commits/mercurial.py +++ b/codespeed/commits/mercurial.py @@ -63,7 +63,7 @@ def getlogs(endrev, startrev): if p.returncode != 0: raise CommitLogError(str(stderr)) else: - stdout = stdout.rstrip(b'\n') # Remove last newline + stdout = str(stdout).rstrip(b'\n') # Remove last newline logs = [] for log in stdout.split("=newlog=\n"): elements = [] From 5e1bdae927ab2fc7b50d0b650ba3a2eb3cba0f96 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 18 Apr 2019 11:43:32 +0300 Subject: [PATCH 060/134] BUG: stdout is bytes on python3 --- codespeed/commits/mercurial.py | 2 +- codespeed/tests/test_commits.py | 62 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 codespeed/tests/test_commits.py diff --git a/codespeed/commits/mercurial.py b/codespeed/commits/mercurial.py index de0c63e8..0f4f5938 100644 --- a/codespeed/commits/mercurial.py +++ b/codespeed/commits/mercurial.py @@ -63,7 +63,7 @@ def getlogs(endrev, startrev): if p.returncode != 0: raise CommitLogError(str(stderr)) else: - stdout = stdout.rstrip('\n') # Remove last newline + stdout = stdout.decode('utf-8').rstrip('\n') # Remove last newline logs = [] for log in stdout.split("=newlog=\n"): elements = [] diff --git a/codespeed/tests/test_commits.py b/codespeed/tests/test_commits.py new file mode 100644 index 00000000..3c09d03e --- /dev/null +++ b/codespeed/tests/test_commits.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +from datetime import datetime, timedelta +import subprocess +import tempfile +import os + +from django.test import TestCase, override_settings +from django.urls import reverse + +from codespeed.models import (Project, Benchmark, Revision, Branch, Executable, + Environment, Result, Report) + +hgdir = '' + +def setUpModule(): + global hgdir + hgdir = tempfile.TemporaryDirectory() + subprocess.check_call(['hg', 'init'], cwd=hgdir.name) + # Add some commits + readme = os.path.join(hgdir.name, 'README.md') + file1 = os.path.join(hgdir.name, 'file1.py') + with open(readme, 'w') as hg_file: + hg_file.write('readme') + subprocess.check_call(['hg', 'add', readme], cwd=hgdir.name) + subprocess.check_call(['hg', 'commit', '-m', "first commit"], cwd=hgdir.name) + with open(file1, 'w') as hg_file: + hg_file.write('value = 10') + subprocess.check_call(['hg', 'add', file1], cwd=hgdir.name) + subprocess.check_call(['hg', 'commit', '-m', "second commit"], cwd=hgdir.name) + +def tearDownModule(): + hgdir.cleanup() + +class TestMercurial(TestCase): + + def setUp(self): + self.days = 0 + self.hgdir = hgdir.name + self.starttime = datetime.now() + timedelta(days=-100) + + Project(repo_type='M', name='pro', + repo_path=str(self.hgdir)).save() + self.pro = Project.objects.get(name='pro') + + Branch(project=self.pro, name='default').save() + self.b = Branch.objects.get(name='default') + + Environment(name='Walden Pond').save() + Executable(name='walden', project=self.pro).save() + Benchmark(name='TestBench').save() + + self.env = Environment.objects.get(name='Walden Pond') + self.exe = Executable.objects.get(name='walden') + self.bench = Benchmark.objects.get(name='TestBench') + cmd = ['hg', '-R', self.hgdir, 'id', '-r', '1'] + self.cid = subprocess.check_output(cmd).split()[0] + Revision(commitid=self.cid.decode('utf-8'), date=self.starttime, branch=self.b, + project=self.pro).save() + + def test_hg(self): + response = self.client.get(reverse('displaylogs'), {'revisionid':1}) + assert response.status_code == 200, 'expected 200 got %d' % response.status_code From da0b957e417cb370356e51a63d118356072a748a Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 May 2019 11:49:15 +0300 Subject: [PATCH 061/134] BUG: extend range for finding latest historical results --- .gitignore | 1 + codespeed/views.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 29f338e0..709d6c1c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .DS_Store *.db sample_project/repos/* +speed_pypy/repos/* override build dist diff --git a/codespeed/views.py b/codespeed/views.py index 7cbdfccd..b8d7941a 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -95,7 +95,8 @@ def gethistoricaldata(request): baseline_exe = Executable.objects.get( name=settings.DEF_BASELINE['executable']) baseline_revs = Revision.objects.filter( - branch__project=baseline_exe.project).order_by('-date') + branch__project=baseline_exe.project, + tag=settings.DEF_BASELINE['revision']).order_by('-date') baseline_lastrev = baseline_revs[0] for rev in baseline_revs: baseline_results = Result.objects.filter( @@ -129,17 +130,16 @@ def gethistoricaldata(request): data['tagged_revs'] = [rev.tag for rev in default_taggedrevs if rev.tag in default_results] # Fetch data for latest results revs = Revision.objects.filter( - branch=default_branch).order_by('-date')[:5] + branch=default_branch).order_by('-date')[:100] default_lastrev = None - for i in range(4): - default_lastrev = revs[i] + for rev in revs: + default_lastrev = rev if default_lastrev.results.filter(executable=default_exe, environment=env): break default_lastrev = None - if default_lastrev is None: - return HttpResponse(json.dumps(data)) - default_results['latest'] = Result.objects.filter( - executable=default_exe, revision=default_lastrev, environment=env) + if default_lastrev is not None: + default_results['latest'] = Result.objects.filter( + executable=default_exe, revision=default_lastrev, environment=env) # Collect data benchmarks = [] From e72b5948bdd3cbb09d0a400ff1314e3bb91a5517 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 May 2019 17:26:18 +0300 Subject: [PATCH 062/134] MAINT: change default environment --- speed_pypy/settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index d0c98f79..37eb4c8f 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -86,9 +86,9 @@ SHOW_REPORTS = False SHOW_HISTORICAL = True -DEF_BASELINE = {'executable': 'cpython', 'revision': '2.6.2'} -DEF_EXECUTABLE = 'pypy-c-jit' -DEF_ENVIRONMENT = 'tannit' +DEF_BASELINE = {'executable': 'cpython', 'revision': '2.7.11'} +DEF_EXECUTABLE = 'pypy-c-jit-64' +DEF_ENVIRONMENT = 'benchmarker' from .local_settings import * From b5573f1d8dbbd301ea5c0dd30d274b82fcb65452 Mon Sep 17 00:00:00 2001 From: mattip Date: Thu, 23 Jan 2020 09:16:01 +1100 Subject: [PATCH 063/134] Change exe for new benchmarks, still report historical data for old exe --- codespeed/views.py | 3 ++- speed_pypy/settings.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index b8d7941a..7393c210 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -122,7 +122,8 @@ def gethistoricaldata(request): default_results = {} for rev in default_taggedrevs: res = Result.objects.filter( - executable=default_exe, revision=rev, environment=env) + # executable=default_exe, + revision=rev, environment=env) if not res: logger.info('no results for %s %s %s' % (str(default_exe), str(rev), str(env))) continue diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index 37eb4c8f..ff952c4c 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -87,7 +87,7 @@ SHOW_REPORTS = False SHOW_HISTORICAL = True DEF_BASELINE = {'executable': 'cpython', 'revision': '2.7.11'} -DEF_EXECUTABLE = 'pypy-c-jit-64' +DEF_EXECUTABLE = 'pypy-jit-64' DEF_ENVIRONMENT = 'benchmarker' From c4e1e8c62d1f35bc5fae92227f95c263fbee3e68 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 28 Jan 2020 07:01:34 +0200 Subject: [PATCH 064/134] avoid zero values when calculating geomean --- speed_pypy/templates/home.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/speed_pypy/templates/home.html b/speed_pypy/templates/home.html index 2a0ddf3c..c3ca1ddf 100644 --- a/speed_pypy/templates/home.html +++ b/speed_pypy/templates/home.html @@ -108,7 +108,9 @@

How has {{ default_exe.project }} performance evolved over time?

plotdata[0].push(relative_value); plotdata[1].push(1.0); labels.push(relative_value.toFixed(2)); - trunk_geomean *= relative_value; + if (relative_value > 0) { + trunk_geomean *= relative_value; + } } trunk_geomean = Math.pow(trunk_geomean, 1/plotdata[0].length); var geofaster = 1/trunk_geomean; From 85ccb1f5a3a1cfd37ca558c7d630ddb3e59e4113 Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 28 Jan 2020 14:13:14 +0200 Subject: [PATCH 065/134] revert change allowing any exe in graph --- codespeed/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codespeed/views.py b/codespeed/views.py index 7393c210..e0add003 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -122,7 +122,7 @@ def gethistoricaldata(request): default_results = {} for rev in default_taggedrevs: res = Result.objects.filter( - # executable=default_exe, + executable=default_exe, revision=rev, environment=env) if not res: logger.info('no results for %s %s %s' % (str(default_exe), str(rev), str(env))) From 270d607bce93c5cbbed9ace60bb2cb0a3fa031ae Mon Sep 17 00:00:00 2001 From: mattip Date: Tue, 28 Jan 2020 22:42:18 +0200 Subject: [PATCH 066/134] comparison page: use the DEF_ENVIRONMENT when loading the page, uncheck "*old" exes --- codespeed/static/js/comparison.js | 2 ++ codespeed/templates/codespeed/comparison.html | 12 ++++++++++++ codespeed/views.py | 2 +- codespeed/views_data.py | 2 +- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index b05d77e6..a76e390b 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -394,10 +394,12 @@ function init(defaults) { $("#baseline").val(defaults.baseline); $("#direction").prop('checked', defaults.direction === "True"); + /* var sel = $("input[name='executables']"); $.each(defaults.executables, function(i, exe) { sel.filter("[value='" + exe + "']").prop('checked', true); }); + */ sel = $("input[name='benchmarks']"); $.each(defaults.benchmarks, function(i, bench) { diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html index 14139577..4256898d 100644 --- a/codespeed/templates/codespeed/comparison.html +++ b/codespeed/templates/codespeed/comparison.html @@ -32,11 +32,19 @@
{% for proj, executable in executables.items %}
    {{ proj }} (All, None) + {% if forloop.counter > 3 %} {% for exe in executable %}
  • {% endfor %} + {% else %} + {% for exe in executable %} +
  • + +
    +
  • {% endfor %} + {% endif %}
{% endfor %}
@@ -92,6 +100,10 @@ -{% endifnotequal %} +{% endif %} diff --git a/codespeed/templates/codespeed/changes_table.html b/codespeed/templates/codespeed/changes_table.html index 95687e15..2b3d7e9d 100644 --- a/codespeed/templates/codespeed/changes_table.html +++ b/codespeed/templates/codespeed/changes_table.html @@ -26,7 +26,7 @@ {% endif%}{% if units.has_stddev %}{{ units.totals.min }} {% endif%}{% if units.hasmax %}{{ units.totals.max }} {% endif%}{{ units.totals.change|percentage }} - {% ifnotequal units.totals.trend "-" %}{{ units.totals.trend|floatformat:2 }}%{% else %}{{ units.totals.trend }}{% endifnotequal %} + {% if units.totals.trend != "-" %}{{ units.totals.trend|floatformat:2 }}%{% else %}{{ units.totals.trend }}{% endif %} @@ -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/timeline.html b/codespeed/templates/codespeed/timeline.html index 2175a4fb..73d3f13a 100644 --- a/codespeed/templates/codespeed/timeline.html +++ b/codespeed/templates/codespeed/timeline.html @@ -54,7 +54,7 @@ From ac68f9b40690feb2e7d3bb41c622c4f6cfdb0333 Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Tue, 23 Jan 2024 16:37:26 +0000 Subject: [PATCH 086/134] Show full date/time in the revision admin view When a revision is shown in the admin interface, the year of the date is not displayed. Change to isoformat to show every field of the DateTimeField. Address https://github.com/python/codespeed/issues/23 --- codespeed/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codespeed/models.py b/codespeed/models.py index 7ada5a38..978a3066 100644 --- a/codespeed/models.py +++ b/codespeed/models.py @@ -139,7 +139,7 @@ def __str__(self): if self.date is None: date = None else: - date = self.date.strftime("%b %d, %H:%M") + date = self.date.isoformat(sep=" ") string = " - ".join(filter(None, (date, self.commitid, self.tag))) if self.branch.name != self.branch.project.default_branch: string += " - " + self.branch.name From dec272f4ea0fd3e4813fc69e14d44ff57eed8c5f Mon Sep 17 00:00:00 2001 From: mattip Date: Sun, 18 Aug 2024 19:16:43 +0300 Subject: [PATCH 087/134] allow more than one DEF_EXECUTABLES to show on historic graph --- codespeed/commits/git.py | 4 +- codespeed/results.py | 2 +- codespeed/views.py | 80 +++++++++++++++++++--------------- codespeed/views_data.py | 8 ++-- speed_pypy/settings.py | 7 ++- speed_pypy/templates/home.html | 10 +++-- 6 files changed, 64 insertions(+), 47 deletions(-) diff --git a/codespeed/commits/git.py b/codespeed/commits/git.py index 06bc8a00..7b8f03e3 100644 --- a/codespeed/commits/git.py +++ b/codespeed/commits/git.py @@ -64,8 +64,8 @@ def getlogs(endrev, startrev): p, stdout, stderr = execute_command(cmd, working_copy) if p.returncode != 0: - raise CommitLogError("%s returned %s: %s" % ( - " ".join(cmd), p.returncode, stderr)) + raise CommitLogError(f"'%s' in '%s' returned %s: %s" % ( + " ".join(cmd), working_copy, p.returncode, stderr)) logs = [] for log in filter(None, stdout.split('\x1e')): (short_commit_id, commit_id, date_t, author_name, author_email, diff --git a/codespeed/results.py b/codespeed/results.py index 662da768..650f4c6d 100644 --- a/codespeed/results.py +++ b/codespeed/results.py @@ -73,7 +73,7 @@ def save_result(data, update_repo=True): b.save() try: - rev = branch.revisions.get(commitid=data['commitid']) + rev = branch.revisions.get(commitid=data['commitid'].split(":")[-1]) except Revision.DoesNotExist: rev_date = data.get("revision_date") # "None" (as string) can happen when we urlencode the POST data diff --git a/codespeed/views.py b/codespeed/views.py index b2827b6c..ddae93bf 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -69,7 +69,7 @@ def get_context_data(self, **kwargs): context = super(HomeView, self).get_context_data(**kwargs) context['show_reports'] = settings.SHOW_REPORTS context['show_historical'] = settings.SHOW_HISTORICAL - historical_settings = ['SHOW_HISTORICAL', 'DEF_BASELINE', 'DEF_EXECUTABLE'] + historical_settings = ['SHOW_HISTORICAL', 'DEF_BASELINE', 'DEF_EXECUTABLES'] if not all(getattr(settings, var) for var in historical_settings): context['show_historical'] = False return context @@ -78,8 +78,8 @@ def get_context_data(self, **kwargs): baseline_exe = Executable.objects.get( name=settings.DEF_BASELINE['executable']) context['baseline'] = baseline_exe - def_name = settings.DEF_EXECUTABLE['name'] - def_project = Project.objects.get(name=settings.DEF_EXECUTABLE['project']) + def_name = settings.DEF_EXECUTABLES[0]['name'] + def_project = Project.objects.get(name=settings.DEF_EXECUTABLES[0]['project']) default_exe = Executable.objects.get(name=def_name, project=def_project, ) @@ -103,42 +103,52 @@ def gethistoricaldata(request): # Fetch Baseline data, filter by executable baseline_exe = Executable.objects.get( name=settings.DEF_BASELINE['executable']) - baseline_revs = Revision.objects.filter( - branch__project=baseline_exe.project).order_by('-date') - baseline_lastrev = baseline_revs[0] - for rev in baseline_revs: - baseline_results = Result.objects.filter( - executable=baseline_exe, revision=rev, environment=env) - if baseline_results: - baseline_lastrev = rev - break - if len(baseline_results) == 0: + tag=settings.DEF_BASELINE['revision'] + rev = Revision.objects.filter(branch__project=baseline_exe.project, tag=tag) + if len(rev) < 1: + return HttpResponse(json.dumps( + f"Could not find {tag=} for {settings.DEF_BASELINE['executable']} in database") + ) + rev0 = rev[0] + baseline_results = Result.objects.filter( + executable=baseline_exe, revision=rev0, environment=env) + if not baseline_results: logger.error('Could not find results for {} rev="{}" env="{}"'.format( - baseline_exe, baseline_lastrev, env)) + baseline_exe, rev0, env)) data['baseline'] = '{} {}'.format( - settings.DEF_BASELINE['executable'], baseline_lastrev.tag) - - def_name = settings.DEF_EXECUTABLE['name'] - def_project = Project.objects.get(name=settings.DEF_EXECUTABLE['project']) - default_exe = Executable.objects.get(name=def_name, project=def_project) - default_branch = Branch.objects.get( - name=default_exe.project.default_branch, - project=default_exe.project) + settings.DEF_BASELINE['executable'], rev0.tag) - # Fetch tagged revisions for executable - default_taggedrevs = Revision.objects.filter( - branch=default_branch - ).exclude(tag="").order_by('date') default_results = {} - for rev in default_taggedrevs: - res = Result.objects.filter( - executable=default_exe, revision=rev, environment=env) - if not res: - logger.info('no results for %s %s %s' % (str(default_exe), str(rev), str(env))) - continue - default_results[rev.tag] = res - data['tagged_revs'] = [rev.tag for rev in default_taggedrevs if rev.tag in default_results] + all_taggedrevs = [] + for executable in settings.DEF_EXECUTABLES: + _def_name = executable['name'] + _def_project = Project.objects.get(name=executable['project']) + _default_exe = Executable.objects.get(name=_def_name, project=_def_project) + _default_branch = Branch.objects.get( + name=_default_exe.project.default_branch, + project=_default_exe.project) + + # Fetch tagged revisions for executable + default_taggedrevs = Revision.objects.filter( + branch=_default_branch + ).exclude(tag="").order_by('date') + all_taggedrevs += default_taggedrevs + for rev in default_taggedrevs: + res = Result.objects.filter( + executable=_default_exe, revision=rev, environment=env) + if not res: + logger.info("no results for '%s' '%s' '%s'" % (str(_default_exe), str(rev), str(env))) + continue + default_results[rev.tag] = res + data['tagged_revs'] = [rev.tag for rev in all_taggedrevs if rev.tag in default_results] # Fetch data for latest results + executable = settings.DEF_EXECUTABLES[0] + def_name = executable['name'] + def_project = Project.objects.get(name=executable['project']) + default_exe = Executable.objects.get(name=def_name, project=def_project) + default_branch = Branch.objects.get( + name=default_exe.project.default_branch, + project=default_exe.project) revs = Revision.objects.filter( branch=default_branch).order_by('-date')[:100] default_lastrev = None @@ -896,7 +906,7 @@ def displaylogs(request): log['commit_browse_url'] = project.commit_browsing_url.format(**log) return render( - request, + request, 'codespeed/changes_logs.html', { 'error': error, 'logs': logs, diff --git a/codespeed/views_data.py b/codespeed/views_data.py index 11d7592c..585158c0 100644 --- a/codespeed/views_data.py +++ b/codespeed/views_data.py @@ -104,11 +104,11 @@ def getbaselineexecutables(include_tags=None): def getdefaultexecutable(): default = None - if (hasattr(settings, 'DEF_EXECUTABLE') and - settings.DEF_EXECUTABLE is not None): + if (hasattr(settings, 'DEF_EXECUTABLES') and + settings.DEF_EXECUTABLES is not None): try: - def_name = settings.DEF_EXECUTABLE['name'] - def_project = Project.objects.get(name=settings.DEF_EXECUTABLE['project']) + def_name = settings.DEF_EXECUTABLES[0]['name'] + def_project = Project.objects.get(name=settings.DEF_EXECUTABLES[0]['project']) default = Executable.objects.get(name=def_name, project=def_project) except Executable.DoesNotExist: pass diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index 6c61bb8c..4f85f9eb 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -89,8 +89,11 @@ SHOW_REPORTS = False SHOW_HISTORICAL = True -DEF_BASELINE = {'executable': 'cpython', 'revision': '3.6.8'} -DEF_EXECUTABLE = {'name': 'pypy3.9-jit-64', 'project': 'PyPy3.9'} +DEF_BASELINE = {'executable': 'cpython', 'revision': '3.7.6'} +DEF_EXECUTABLES = [ + {'name': 'pypy3.10-jit-64', 'project': 'PyPy3.10'}, + {'name': 'pypy3.9-jit-64', 'project': 'PyPy3.9'}, + ] DEF_ENVIRONMENT = 'benchmarker' diff --git a/speed_pypy/templates/home.html b/speed_pypy/templates/home.html index 10e10e20..0ac45965 100644 --- a/speed_pypy/templates/home.html +++ b/speed_pypy/templates/home.html @@ -33,7 +33,7 @@

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?

+

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).

@@ -81,6 +81,10 @@

How has {{ default_exe.project }} performance evolved over time?

$("#baseline-comparison-plot").html(getLoadText('Error retrieving data', 0)); return 1; } + if (typeof data === 'string' || data instanceof String) { + $("#baseline-comparison-plot").html(getLoadText('Error retrieving data ' + data, 0)); + return 1; + } var trunk_geomean = 1; var tagged_data = new Array(); for (i in data['tagged_revs']) { @@ -169,7 +173,7 @@

How has {{ default_exe.project }} performance evolved over time?

for (var i in data['tagged_revs']) { ticks.push(data['tagged_revs'][i]); } - ticks.push('latest'); + ticks.push('latest {{ default_exe.project }}'); var geolabels = new Array(); for (var i in geomeans) { geolabels.push(geomeans[i].toFixed(2) + "x"); @@ -197,7 +201,7 @@

How has {{ default_exe.project }} performance evolved over time?

}, yaxis:{ min: 0, - tickOptions:{formatString:'%.2f'} + tickOptions:{formatString:'%.1f'} } } }; From af1854d87cd1acfd8bd70f691e54f7c9faa83788 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 19 Aug 2024 00:51:56 +0300 Subject: [PATCH 088/134] also allow multiple baselines --- codespeed/views.py | 56 +++++++++++++++++++++------------- codespeed/views_data.py | 6 ++-- speed_pypy/settings.py | 5 ++- speed_pypy/templates/home.html | 7 +++-- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/codespeed/views.py b/codespeed/views.py index ddae93bf..369f517e 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -69,14 +69,14 @@ def get_context_data(self, **kwargs): context = super(HomeView, self).get_context_data(**kwargs) context['show_reports'] = settings.SHOW_REPORTS context['show_historical'] = settings.SHOW_HISTORICAL - historical_settings = ['SHOW_HISTORICAL', 'DEF_BASELINE', 'DEF_EXECUTABLES'] + historical_settings = ['SHOW_HISTORICAL', 'DEF_BASELINES', 'DEF_EXECUTABLES'] if not all(getattr(settings, var) for var in historical_settings): context['show_historical'] = False return context try: baseline_exe = Executable.objects.get( - name=settings.DEF_BASELINE['executable']) + name=settings.DEF_BASELINES[0]['executable']) context['baseline'] = baseline_exe def_name = settings.DEF_EXECUTABLES[0]['name'] def_project = Project.objects.get(name=settings.DEF_EXECUTABLES[0]['project']) @@ -101,22 +101,23 @@ def gethistoricaldata(request): env = env.first() # Fetch Baseline data, filter by executable - baseline_exe = Executable.objects.get( - name=settings.DEF_BASELINE['executable']) - tag=settings.DEF_BASELINE['revision'] - rev = Revision.objects.filter(branch__project=baseline_exe.project, tag=tag) - if len(rev) < 1: - return HttpResponse(json.dumps( - f"Could not find {tag=} for {settings.DEF_BASELINE['executable']} in database") - ) - rev0 = rev[0] - baseline_results = Result.objects.filter( - executable=baseline_exe, revision=rev0, environment=env) - if not baseline_results: - logger.error('Could not find results for {} rev="{}" env="{}"'.format( - baseline_exe, rev0, env)) - data['baseline'] = '{} {}'.format( - settings.DEF_BASELINE['executable'], rev0.tag) + baseline_results = [] + for b in settings.DEF_BASELINES: + baseline_exe = Executable.objects.get( + name=b['executable']) + tag=b['revision'] + rev = Revision.objects.filter(branch__project=baseline_exe.project, tag=tag) + if len(rev) < 1: + return HttpResponse(json.dumps( + f"Could not find {tag=} for {b['executable']} in database") + ) + rev0 = rev[0] + resname = '{} {}'.format(b['executable'], rev0.tag) + baseline_results.append((resname, Result.objects.filter( + executable=baseline_exe, revision=rev0, environment=env))) + if not baseline_results[-1][1]: + logger.error('Could not find results for {} rev="{}" env="{}"'.format( + baseline_exe, rev0, env)) default_results = {} all_taggedrevs = [] @@ -163,17 +164,30 @@ def gethistoricaldata(request): # Collect data benchmarks = [] - for res in baseline_results: + # Collate first baseline and all the default_results + resset = baseline_results[0][1] + resname = baseline_results[0][0] + data['baseline'] = resname + for res in resset: if res == 0: continue benchmarks.append(res.benchmark.name) - data['results'][res.benchmark.name] = {data['baseline']: res.value} + data['results'][res.benchmark.name] = {resname: res.value} for rev_name in default_results: val = 0 for default_res in default_results[rev_name]: if default_res.benchmark.name == res.benchmark.name: val = default_res.value - data['results'][res.benchmark.name][rev_name] = val + data['results'][res.benchmark.name][rev_name] = val + # Collate other baseline + for resname, resset in baseline_results[1:]: + for res in resset: + if res == 0: + continue + if not res.benchmark.name in data['results']: + continue + data['results'][res.benchmark.name][resname] = res.value + data['tagged_revs'].insert(0, resname) benchmarks.sort() data['benchmarks'] = benchmarks return HttpResponse(json.dumps(data)) diff --git a/codespeed/views_data.py b/codespeed/views_data.py index 585158c0..472f8ded 100644 --- a/codespeed/views_data.py +++ b/codespeed/views_data.py @@ -83,10 +83,10 @@ def getbaselineexecutables(include_tags=None): 'name': name, }) # move default to first place - if hasattr(settings, 'DEF_BASELINE') and settings.DEF_BASELINE is not None: + if hasattr(settings, 'DEF_BASELINES') and settings.DEF_BASELINES is not None: try: - exename = settings.DEF_BASELINE['executable'] - commitid = settings.DEF_BASELINE['revision'] + exename = settings.DEF_BASELINES[0]['executable'] + commitid = settings.DEF_BASELINES[0]['revision'] for base in baseline: if base['key'] == "none": continue diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index 4f85f9eb..d5694eb1 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -89,7 +89,10 @@ SHOW_REPORTS = False SHOW_HISTORICAL = True -DEF_BASELINE = {'executable': 'cpython', 'revision': '3.7.6'} +DEF_BASELINES = [ + {'executable': 'cpython', 'revision': '3.7.19'}, + {'executable': 'cpython', 'revision': '3.11.9'}, + ] DEF_EXECUTABLES = [ {'name': 'pypy3.10-jit-64', 'project': 'PyPy3.10'}, {'name': 'pypy3.9-jit-64', 'project': 'PyPy3.9'}, diff --git a/speed_pypy/templates/home.html b/speed_pypy/templates/home.html index 0ac45965..7536e817 100644 --- a/speed_pypy/templates/home.html +++ b/speed_pypy/templates/home.html @@ -112,7 +112,7 @@

How has PyPy performance evolved over time?

plotdata[0].push(relative_value); plotdata[1].push(1.0); labels.push(relative_value.toFixed(2)); - if (relative_value > 0) { + if (relative_value > 0 && !isNaN(relative_value)) { trunk_geomean *= relative_value; } } @@ -162,7 +162,10 @@

How has PyPy performance evolved over time?

num_of_benchs = tagged_data[i].length; var tempgeo = 1; for (var j in tagged_data[i]) { - tempgeo *= tagged_data[i][j]; + value = tagged_data[i][j]; + if (value > 0 && !isNaN(value)) { + tempgeo *= value; + } } tempgeo = Math.pow(tempgeo, 1/tagged_data[i].length); tempgeo = 1/tempgeo; From b62c60d710ab72f6514d1eb68d8b6f8552ec49c3 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 19 Aug 2024 18:16:15 +0300 Subject: [PATCH 089/134] add cpython3.12.4 to homepage --- speed_pypy/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index d5694eb1..fb5b4d92 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -92,6 +92,7 @@ DEF_BASELINES = [ {'executable': 'cpython', 'revision': '3.7.19'}, {'executable': 'cpython', 'revision': '3.11.9'}, + {'executable': 'cpython', 'revision': '3.12.4'}, ] DEF_EXECUTABLES = [ {'name': 'pypy3.10-jit-64', 'project': 'PyPy3.10'}, From d221387916e1b01342bea5c25ddd4ab988ba0518 Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 28 Aug 2024 15:44:26 +0300 Subject: [PATCH 090/134] reverse the historical data sorting --- codespeed/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codespeed/views.py b/codespeed/views.py index 369f517e..62695a70 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -121,7 +121,7 @@ def gethistoricaldata(request): default_results = {} all_taggedrevs = [] - for executable in settings.DEF_EXECUTABLES: + for executable in settings.DEF_EXECUTABLES[::-1]: _def_name = executable['name'] _def_project = Project.objects.get(name=executable['project']) _default_exe = Executable.objects.get(name=_def_name, project=_def_project) From bb3d41ac9a6c6712eeff092f2b0e9a008b12748f Mon Sep 17 00:00:00 2001 From: mattip Date: Wed, 25 Dec 2024 16:24:27 +0200 Subject: [PATCH 091/134] compare to cpython3.11, fix some tools --- speed_pypy/settings.py | 2 +- tools/pypy/import_from_json.py | 132 ++++++++++++++++----------- tools/pypy/saveresults.py | 162 +++++++++++++++++++++++++++------ 3 files changed, 214 insertions(+), 82 deletions(-) diff --git a/speed_pypy/settings.py b/speed_pypy/settings.py index fb5b4d92..15206120 100644 --- a/speed_pypy/settings.py +++ b/speed_pypy/settings.py @@ -90,11 +90,11 @@ SHOW_REPORTS = False SHOW_HISTORICAL = True DEF_BASELINES = [ - {'executable': 'cpython', 'revision': '3.7.19'}, {'executable': 'cpython', 'revision': '3.11.9'}, {'executable': 'cpython', 'revision': '3.12.4'}, ] DEF_EXECUTABLES = [ + {'name': 'pypy3.11-jit-64', 'project': 'PyPy3.11'}, {'name': 'pypy3.10-jit-64', 'project': 'PyPy3.10'}, {'name': 'pypy3.9-jit-64', 'project': 'PyPy3.9'}, ] 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] " + parser = optparse.OptionParser(usage=usage) + parser.add_option('-b', '--base', action='store_true', + help='take base values instead of modified') + parser.add_option('--host', type=str, default=SPEEDURL, + help="codespeed instance, defaults to '%s'" % SPEEDURL) + parser.add_option('--revision', + help=('for cpython, revision number (100 for cpython 2.6.2, 101 for 2.7.2, ' + '110 for cpython3.7.6, 120 for cpython3.11, ' + 'edit admin interface "Revisions" to add more)\n\n' + 'for pypy, use the hash from the json file'), + ) + parser.add_option('--branch', help="branch name (main, py3.11)", default='main') + options, args = parser.parse_args(sys.argv) + if options.host[-1] != '/': + raise ValueError("host must end with '/'") + if not options.host.startswith("http"): + raise ValueError("host must start with 'http'") + if len(args) != 2: + print(parser.usage) + sys.exit(1) + results = json.load(open(args[1]))['results'] + save('cpython', options, results, 'cpython', 'benchmarker', + testing=False) From 0ffc987eb2943a3f51b50c82e0fb18d3d5c65e0d Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 27 Dec 2024 12:11:14 +0200 Subject: [PATCH 092/134] comparison: fix previous commit, make permalink work --- codespeed/templates/codespeed/comparison.html | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html index 4256898d..886e9057 100644 --- a/codespeed/templates/codespeed/comparison.html +++ b/codespeed/templates/codespeed/comparison.html @@ -32,19 +32,15 @@
{% for proj, executable in executables.items %}
    {{ proj }} (All, None) - {% if forloop.counter > 3 %} {% for exe in executable %}
  • - + {% if exe.key in checkedexecutables %} + + {% else %} + + {% endif %}
  • {% endfor %} - {% else %} - {% for exe in executable %} -
  • - -
    -
  • {% endfor %} - {% endif %}
{% endfor %}
From 3ba0525946ddf6f5845ee9879f671d6725c977b9 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 Apr 2026 13:03:15 +0300 Subject: [PATCH 093/134] make comparison page more performant - only pre-check known exes - query only checked benchmarks and exes Co-Authored-By: Claude Opus 4.7 --- codespeed/static/js/comparison.js | 23 +++++++++++------ codespeed/views.py | 43 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index a76e390b..9c3fd3cb 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -64,7 +64,7 @@ function refreshContent() { function savedata(data) { if (data.error !== "None") { var h = $("#content").height();//get height for error message - $("#cplot").html(getLoadText(data.error, h)); + $("#plotwrapper").html(getLoadText(data.error, h)); return 1; } delete data.error; @@ -72,6 +72,14 @@ function savedata(data) { refreshContent(); } +function loadData() { + var conf = getConfiguration(); + if (!conf.exe || !conf.ben) { return; } + var h = $("#content").height(); + $("#plotwrapper").html(getLoadText("Loading...", h)); + $.getJSON("json/", {exe: conf.exe, ben: conf.ben}, savedata); +} + function abortRender(plotid, message) { $("#" + plotid).css("border", "dashed 1px grey"); $("#" + plotid).css("padding", "1em"); @@ -411,19 +419,18 @@ function init(defaults) { sel.filter("[value='" + env + "']").prop('checked', true); }); - $("#chart_type, #baseline, #direction, input[name='executables']," + - "input[name='benchmarks'], input[name='environments']").change(refreshContent); + // Re-fetch when exe or benchmark selection changes + $("input[name='executables'], input[name='benchmarks']").change(loadData); + $('.checkall, .uncheckall').click(loadData); - $('.checkall, .uncheckall').click(refreshContent); + // Re-render without re-fetching for other controls + $("#chart_type, #baseline, #direction, input[name='environments']").change(refreshContent); $.ajaxSetup ({ cache: false }); - // Get comparison data - var h = $("#content").height();//get height for loading text - $("#cplot").html(getLoadText("Loading...", h)); - $.getJSON("json/", savedata); + loadData(); $("#permalink").click(function() { window.location = "?" + $.param(getConfiguration()); diff --git a/codespeed/views.py b/codespeed/views.py index 62695a70..3b26b6bb 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -196,13 +196,32 @@ def gethistoricaldata(request): @require_GET def getcomparisondata(request): executables, exekeys = getcomparisonexes() + + requested_exes = None + if 'exe' in request.GET: + requested_exes = set( + i for i in request.GET['exe'].split(",") if i and i in exekeys + ) + benchmarks = Benchmark.objects.all() + if 'ben' in request.GET: + bench_ids = set() + for i in request.GET['ben'].split(","): + try: + bench_ids.add(int(i)) + except ValueError: + pass + if bench_ids: + benchmarks = benchmarks.filter(id__in=bench_ids) + environments = Environment.objects.all() compdata = {} compdata['error'] = "Unknown error" for proj in executables: for exe in executables[proj]: + if requested_exes is not None and exe['key'] not in requested_exes: + continue compdata[exe['key']] = {} for env in environments: compdata[exe['key']][env.id] = {} @@ -271,6 +290,30 @@ def comparison(request): except Revision.DoesNotExist: #TODO: log pass + if not checkedexecutables: + if hasattr(settings, 'DEF_EXECUTABLES') and settings.DEF_EXECUTABLES: + for exe_spec in settings.DEF_EXECUTABLES: + try: + proj = Project.objects.get(name=exe_spec['project']) + exe = Executable.objects.get(name=exe_spec['name'], project=proj) + for key in exekeys: + if key.startswith(str(exe.id) + "+L+"): + checkedexecutables.append(key) + break + except (Executable.DoesNotExist, Project.DoesNotExist): + pass + if (not checkedexecutables and + hasattr(settings, 'DEF_BASELINES') and settings.DEF_BASELINES): + baselines = getbaselineexecutables() + for base_spec in settings.DEF_BASELINES: + for base in baselines: + if base['key'] == "none": + continue + if (base['executable'].name == base_spec['executable'] and + base['revision'].commitid == base_spec['revision']): + if base['key'] in exekeys: + checkedexecutables.append(base['key']) + break if not checkedexecutables: checkedexecutables = exekeys From 7f6f6c14f43d126ed0f2abfdd94faad1609cee94 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 Apr 2026 13:12:23 +0300 Subject: [PATCH 094/134] comparison: add arrows and pre-fold exe headings Co-Authored-By: Claude Opus 4.7 --- codespeed/static/css/main.css | 11 +++++++++++ codespeed/static/js/codespeed.js | 6 ++++++ codespeed/static/js/comparison.js | 5 ----- codespeed/templates/codespeed/comparison.html | 6 +++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/codespeed/static/css/main.css b/codespeed/static/css/main.css index 5a39e602..07861632 100644 --- a/codespeed/static/css/main.css +++ b/codespeed/static/css/main.css @@ -235,6 +235,17 @@ div.about_content { text-align: left; } #options li { margin-bottom: 0.8em; } .seriescolor { float: right; margin-top: 2px; height: 13px; width: 14px; } a.togglefold { font-size: normal; color: #000000; } +a.togglefold::before { + content: '▶'; + display: inline-block; + margin-right: 0.3em; + font-size: 0.7em; + transition: transform 0.2s ease; + transform: rotate(90deg); +} +a.togglefold.folded::before { + transform: rotate(0deg); +} a.checkall, a.uncheckall { font-size: small; color: #AAAAAA; } p.errormessage { line-height: 10em; margin-bottom: 10em; } diff --git a/codespeed/static/js/codespeed.js b/codespeed/static/js/codespeed.js index 0fca6169..2fd23f9d 100644 --- a/codespeed/static/js/codespeed.js +++ b/codespeed/static/js/codespeed.js @@ -43,8 +43,14 @@ $(function() { $('.togglefold').each(function() { var lis = $(this).parent().children("li"); + var allUnchecked = lis.find("input[type='checkbox']").filter(':checked').length === 0; + if (allUnchecked) { + lis.hide(); + $(this).addClass('folded'); + } $(this).click(function() { lis.slideToggle(); + $(this).toggleClass('folded'); return false; }); }); diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index 9c3fd3cb..33459240 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -409,11 +409,6 @@ function init(defaults) { }); */ - sel = $("input[name='benchmarks']"); - $.each(defaults.benchmarks, function(i, bench) { - sel.filter("[value='" + bench + "']").prop('checked', true); - }); - sel = $("input[name='environments']"); $.each(defaults.environments, function(i, env) { sel.filter("[value='" + env + "']").prop('checked', true); diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html index 886e9057..41fc5cd3 100644 --- a/codespeed/templates/codespeed/comparison.html +++ b/codespeed/templates/codespeed/comparison.html @@ -51,7 +51,11 @@
    {{ key }} (All, None) {% for bench in benchlist|dictsort:"name" %}
  • - + {% if bench in checkedbenchmarks %} + + {% else %} + + {% endif %}
  • {% endfor %}
{% endfor %} From 0d6dba2af5f2f82ff2cd33a18660a9d723a40a07 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 Apr 2026 13:33:12 +0300 Subject: [PATCH 095/134] make normalization pulldown reflect checked exes, default to horizontal Co-Authored-By: Claude Opus 4.7 --- codespeed/static/js/comparison.js | 37 +++++++++++++++++-- codespeed/templates/codespeed/comparison.html | 5 +-- speed_pypy/settings.py | 1 + 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index 33459240..87d4742b 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -72,6 +72,22 @@ function savedata(data) { refreshContent(); } +function updateBaselineDropdown() { + var $baseline = $("#baseline"); + var current = $baseline.val(); + $baseline.find("option:not([value='none'])").remove(); + $("input[name='executables']:checked").each(function() { + var key = $(this).val(); + var name = $(this).next('label').text().trim(); + $baseline.append($('