From 2239844c773e4587865176b5670492e08f3f509e Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 29 May 2026 13:35:45 +0300 Subject: [PATCH 1/2] add geomean summary to comparison page iff two exes and one env --- codespeed/static/js/comparison.js | 86 +++++++++++++++++++ codespeed/templates/codespeed/comparison.html | 1 + 2 files changed, 87 insertions(+) diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index 48415b3e..eb67444e 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -27,6 +27,90 @@ function getConfiguration() { }; } +function updateGeomeanSummary(exes, enviros, bens, baseline, chart) { + var $summary = $("#geomean-summary"); + if (enviros.length !== 1 || exes.length !== 2 || baseline === "none" || + chart === "stacked bars" || !compdata) { + $summary.html(""); + return; + } + + var baselineExe = baseline, baselineEnv = null; + if (baseline.indexOf(':') !== -1) { + var bparts = baseline.split(':'); + baselineExe = bparts[0]; + baselineEnv = bparts[1]; + } + + var otherExes = exes.filter(function(e) { return e !== baselineExe; }); + if (otherExes.length !== 1) { $summary.html(""); return; } + var otherExe = otherExes[0]; + + var envId = enviros[0]; + var envForBase = baselineEnv !== null ? baselineEnv : envId; + + var product = 1, count = 0; + for (var b = 0; b < bens.length; b++) { + var val = compdata[otherExe] && compdata[otherExe][envId] + ? compdata[otherExe][envId][bens[b]] + : null; + var baseval = compdata[baselineExe] && compdata[baselineExe][envForBase] + ? compdata[baselineExe][envForBase][bens[b]] + : null; + if (val !== null && baseval !== null && baseval !== 0 && val > 0) { + product *= val / baseval; + count++; + } + } + + if (count === 0) { $summary.html(""); return; } + + var geomean = Math.pow(product, 1 / count); + + // Determine whether all selected benchmarks are less-is-better or more-is-better + var lessCount = 0, moreCount = 0; + var benSet = {}; + for (var b = 0; b < bens.length; b++) { benSet[bens[b]] = true; } + for (var unit in bench_units) { + var unitBens = bench_units[unit][0]; + var unitLess = bench_units[unit][1].indexOf("less") !== -1; + for (var ub = 0; ub < unitBens.length; ub++) { + if (benSet[unitBens[ub]]) { + if (unitLess) { lessCount++; } else { moreCount++; } + } + } + } + + var otherLabel = $("label[for='exe_" + otherExe + "']").text().trim(); + var baselineLabel = $("label[for='exe_" + baselineExe + "']").text().trim(); + if (baselineEnv !== null) { + baselineLabel += ' @ ' + $("label[for='env_" + baselineEnv + "']").text().trim(); + } + + var suffix; + if (moreCount === 0 && lessCount > 0) { + // All less-is-better: ratio < 1 means faster + if (geomean < 1) { + suffix = ' or ' + (1 / geomean).toFixed(1) + '× faster'; + } else { + suffix = ' or ' + geomean.toFixed(1) + '× slower'; + } + } else if (lessCount === 0 && moreCount > 0) { + // All more-is-better: ratio > 1 means faster + if (geomean > 1) { + suffix = ' or ' + geomean.toFixed(1) + '× faster'; + } else { + suffix = ' or ' + (1 / geomean).toFixed(1) + '× slower'; + } + } else { + suffix = ' relative to baseline'; + } + + $summary.html('The geometric average of ' + count + ' benchmarks for ' + + otherLabel + ' is ' + geomean.toFixed(2) + '' + + suffix + ' than the baseline ' + baselineLabel + ''); +} + function refreshContent() { var conf = getConfiguration(), exes = conf.exe.split(","), @@ -34,6 +118,7 @@ function refreshContent() { enviros = conf.env.split(","), msg = ""; + $("#geomean-summary").html(""); var h = $("#plotwrapper").height();//get height for error message if (exes[0] === "") { $("#plotwrapper").html('

No executables selected

'); @@ -87,6 +172,7 @@ function refreshContent() { plotcounter++; renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, conf.bas, conf.chart, conf.hor); } + updateGeomeanSummary(exes, enviros, bens, conf.bas, conf.chart); }); } diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html index 075d147d..ab6ab61f 100644 --- a/codespeed/templates/codespeed/comparison.html +++ b/codespeed/templates/codespeed/comparison.html @@ -80,6 +80,7 @@ Export CSV +
From a37dc8daa1efc937e30876c9aa31edcaed4d128f Mon Sep 17 00:00:00 2001 From: mattip Date: Fri, 29 May 2026 18:36:34 +0300 Subject: [PATCH 2/2] simplify permalink on comparison page --- codespeed/static/js/comparison.js | 202 ++++++++++-------- codespeed/templates/codespeed/comparison.html | 6 +- codespeed/tests/test_views_data.py | 40 ++-- codespeed/views.py | 70 +++--- codespeed/views_data.py | 4 +- 5 files changed, 188 insertions(+), 134 deletions(-) diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index eb67444e..19ada2bc 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -16,6 +16,10 @@ var COLORS = [ ]; function getColor(i) { return COLORS[i % COLORS.length]; } +function getExeLabel(key) { + return $("label[for='exe_" + key.replace(/:/g, '\\:') + "']").text().trim(); +} + function getConfiguration() { return { exe: readCheckbox("input[name='executables']:checked"), @@ -27,88 +31,84 @@ function getConfiguration() { }; } -function updateGeomeanSummary(exes, enviros, bens, baseline, chart) { - var $summary = $("#geomean-summary"); - if (enviros.length !== 1 || exes.length !== 2 || baseline === "none" || - chart === "stacked bars" || !compdata) { - $summary.html(""); - return; - } +function updateGraphTitle(exes, enviros, bens, baseline, chart, chartTitles) { + var $title = $("#graph-title"); - var baselineExe = baseline, baselineEnv = null; - if (baseline.indexOf(':') !== -1) { - var bparts = baseline.split(':'); - baselineExe = bparts[0]; - baselineEnv = bparts[1]; - } + if (enviros.length === 1 && exes.length === 2 && baseline !== "none" && + chart !== "stacked bars" && compdata) { - var otherExes = exes.filter(function(e) { return e !== baselineExe; }); - if (otherExes.length !== 1) { $summary.html(""); return; } - var otherExe = otherExes[0]; - - var envId = enviros[0]; - var envForBase = baselineEnv !== null ? baselineEnv : envId; - - var product = 1, count = 0; - for (var b = 0; b < bens.length; b++) { - var val = compdata[otherExe] && compdata[otherExe][envId] - ? compdata[otherExe][envId][bens[b]] - : null; - var baseval = compdata[baselineExe] && compdata[baselineExe][envForBase] - ? compdata[baselineExe][envForBase][bens[b]] - : null; - if (val !== null && baseval !== null && baseval !== 0 && val > 0) { - product *= val / baseval; - count++; + var baselineExe = baseline, baselineEnv = null; + if (baseline.indexOf('@') !== -1) { + var bparts = baseline.split('@'); + baselineExe = bparts[0]; + baselineEnv = bparts[1]; } - } - if (count === 0) { $summary.html(""); return; } + var otherExes = exes.filter(function(e) { return e !== baselineExe; }); + if (otherExes.length === 1) { + var otherExe = otherExes[0]; + var envId = enviros[0]; + var envForBase = baselineEnv !== null ? baselineEnv : envId; + + var product = 1, count = 0; + for (var b = 0; b < bens.length; b++) { + var val = compdata[otherExe] && compdata[otherExe][envId] + ? compdata[otherExe][envId][bens[b]] + : null; + var baseval = compdata[baselineExe] && compdata[baselineExe][envForBase] + ? compdata[baselineExe][envForBase][bens[b]] + : null; + if (val !== null && baseval !== null && baseval !== 0 && val > 0) { + product *= val / baseval; + count++; + } + } - var geomean = Math.pow(product, 1 / count); + if (count > 0) { + var geomean = Math.pow(product, 1 / count); + + var lessCount = 0, moreCount = 0; + var benSet = {}; + for (var b = 0; b < bens.length; b++) { benSet[bens[b]] = true; } + for (var u in bench_units) { + var unitBens = bench_units[u][0]; + var unitLess = bench_units[u][1].indexOf("less") !== -1; + for (var ub = 0; ub < unitBens.length; ub++) { + if (benSet[unitBens[ub]]) { + if (unitLess) { lessCount++; } else { moreCount++; } + } + } + } - // Determine whether all selected benchmarks are less-is-better or more-is-better - var lessCount = 0, moreCount = 0; - var benSet = {}; - for (var b = 0; b < bens.length; b++) { benSet[bens[b]] = true; } - for (var unit in bench_units) { - var unitBens = bench_units[unit][0]; - var unitLess = bench_units[unit][1].indexOf("less") !== -1; - for (var ub = 0; ub < unitBens.length; ub++) { - if (benSet[unitBens[ub]]) { - if (unitLess) { lessCount++; } else { moreCount++; } - } - } - } + var otherLabel = getExeLabel(otherExe); + var baselineLabel = getExeLabel(baselineExe); + if (baselineEnv !== null) { + baselineLabel += ' @ ' + $("label[for='env_" + baselineEnv + "']").text().trim(); + } - var otherLabel = $("label[for='exe_" + otherExe + "']").text().trim(); - var baselineLabel = $("label[for='exe_" + baselineExe + "']").text().trim(); - if (baselineEnv !== null) { - baselineLabel += ' @ ' + $("label[for='env_" + baselineEnv + "']").text().trim(); - } + var suffix; + if (moreCount === 0 && lessCount > 0) { + suffix = geomean < 1 + ? ' or ' + (1 / geomean).toFixed(1) + '× faster' + : ' or ' + geomean.toFixed(1) + '× slower'; + } else if (lessCount === 0 && moreCount > 0) { + suffix = geomean > 1 + ? ' or ' + geomean.toFixed(1) + '× faster' + : ' or ' + (1 / geomean).toFixed(1) + '× slower'; + } else { + suffix = ' relative to baseline'; + } - var suffix; - if (moreCount === 0 && lessCount > 0) { - // All less-is-better: ratio < 1 means faster - if (geomean < 1) { - suffix = ' or ' + (1 / geomean).toFixed(1) + '× faster'; - } else { - suffix = ' or ' + geomean.toFixed(1) + '× slower'; - } - } else if (lessCount === 0 && moreCount > 0) { - // All more-is-better: ratio > 1 means faster - if (geomean > 1) { - suffix = ' or ' + geomean.toFixed(1) + '× faster'; - } else { - suffix = ' or ' + (1 / geomean).toFixed(1) + '× slower'; + $title.html('The geometric average of ' + count + ' benchmarks for ' + + otherLabel + ' is ' + geomean.toFixed(2) + '' + + suffix + ' than the baseline ' + baselineLabel + ''); + return; + } } - } else { - suffix = ' relative to baseline'; } - $summary.html('The geometric average of ' + count + ' benchmarks for ' + - otherLabel + ' is ' + geomean.toFixed(2) + '' + - suffix + ' than the baseline ' + baselineLabel + ''); + // Fall back to the chart title(s) + $title.text(chartTitles.join(' / ')); } function refreshContent() { @@ -118,7 +118,7 @@ function refreshContent() { enviros = conf.env.split(","), msg = ""; - $("#geomean-summary").html(""); + $("#graph-title").html(""); var h = $("#plotwrapper").height();//get height for error message if (exes[0] === "") { $("#plotwrapper").html('

No executables selected

'); @@ -158,6 +158,7 @@ function refreshContent() { $("#plotwrapper").fadeOut("fast", function() { $(this).html(msg).show(); var plotcounter = 1; + var chartTitles = []; for (var unit in bench_units) { var benchmarks = []; for (var ben in bens) { @@ -170,9 +171,9 @@ function refreshContent() { var plotid = "plot" + plotcounter; $("#plotwrapper").append('
'); plotcounter++; - renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, conf.bas, conf.chart, conf.hor); + chartTitles.push(renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, conf.bas, conf.chart, conf.hor)); } - updateGeomeanSummary(exes, enviros, bens, conf.bas, conf.chart); + updateGraphTitle(exes, enviros, bens, conf.bas, conf.chart, chartTitles); }); } @@ -200,7 +201,7 @@ function updateBaselineDropdown() { if (multiEnv) { enviros.forEach(function(envId) { var envName = $("label[for='env_" + envId + "']").text().trim(); - $baseline.append($('