From 3ba0525946ddf6f5845ee9879f671d6725c977b9 Mon Sep 17 00:00:00 2001 From: mattip Date: Mon, 27 Apr 2026 13:03:15 +0300 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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($('