diff --git a/codespeed/static/js/comparison.js b/codespeed/static/js/comparison.js index abec6ef0..f041d946 100644 --- a/codespeed/static/js/comparison.js +++ b/codespeed/static/js/comparison.js @@ -29,6 +29,7 @@ function getConfiguration() { ben: readCheckbox("input[name='benchmarks']:checked"), env: readCheckbox("input[name='environments']:checked"), hor: $("input[name='direction']").is(':checked'), + com: $("input[name='common_only']").is(':checked'), bas: $("#baseline option:selected").val() || "none", chart: $("#chart_type option:selected").val() }; @@ -141,11 +142,28 @@ function updateGraphTitle(exes, enviros, bens, baseline, chart, chartTitles) { $title.text(chartTitles.join(' / ')); } +// Keep only the benchmarks that have a result for every selected +// executable/environment pair, so each bar group covers the same set. +function filterCommonBenchmarks(bens, exes, enviros) { + if (!compdata) { return bens; } + return bens.filter(function(ben) { + return exes.every(function(exe) { + return enviros.every(function(env) { + var val = compdata[exe] && compdata[exe][env] + ? compdata[exe][env][ben] + : null; + return val !== null && val !== undefined; + }); + }); + }); +} + function refreshContent() { var conf = getConfiguration(), exes = conf.exe.split(","), bens = conf.ben.split(","), enviros = conf.env.split(","), + hiddenCount = 0, msg = ""; $("#graph-title").html(""); @@ -159,7 +177,19 @@ function refreshContent() { } else if (enviros[0] === "") { $("#plotwrapper").html('

No environments selected

'); return false; - } else if (conf.chart === "relative bars" && conf.bas === "none") { + } + + if (conf.com) { + var common = filterCommonBenchmarks(bens, exes, enviros); + hiddenCount = bens.length - common.length; + bens = common; + if (bens.length === 0) { + $("#plotwrapper").html('

No benchmark has results for every selected executable and environment

'); + return false; + } + } + + if (conf.chart === "relative bars" && conf.bas === "none") { msg = '

For relative bar charts, you must select a baseline to normalize to.

'; $("#plotwrapper").html(msg); return false; @@ -183,6 +213,14 @@ function refreshContent() { } } + var hiddenMsg = ""; + if (hiddenCount > 0) { + hiddenMsg = '

' + hiddenCount + ' benchmark' + + (hiddenCount === 1 ? '' : 's') + + ' hidden because not every selected executable has a result for ' + + (hiddenCount === 1 ? 'it' : 'them') + '.

'; + } + chartInstances.forEach(function(c) { c.destroy(); }); chartInstances = []; $("#plotwrapper").fadeOut("fast", function() { @@ -204,6 +242,8 @@ function refreshContent() { var t = renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, conf.bas, conf.chart, conf.hor); chartTitles.push(t); } + // Shown below the chart(s) so it does not push them down + $("#plotwrapper").append(hiddenMsg); updateGraphTitle(exes, enviros, bens, conf.bas, conf.chart, chartTitles); }); } @@ -445,6 +485,7 @@ function init(defaults) { // Set default values $("#chart_type").val(defaults.chart_type); $("#direction").prop('checked', defaults.direction === "True"); + $("#common_only").prop('checked', defaults.common_only === "True"); /* var sel = $("input[name='executables']"); @@ -477,7 +518,7 @@ function init(defaults) { $("#benchmark .checkall, #benchmark .uncheckall").click(loadData); // Re-render without re-fetching for other controls - $("#chart_type, #baseline, #direction").change(refreshContent); + $("#chart_type, #baseline, #direction, #common_only").change(refreshContent); $("input[name='environments']").change(function() { updateBaselineDropdown(); refreshContent(); @@ -536,6 +577,9 @@ function init(defaults) { var exes = conf.exe ? conf.exe.split(",").filter(Boolean) : []; var enviros = readCheckbox("input[name='environments']:checked").split(",").filter(Boolean); var benchmarks = conf.ben ? conf.ben.split(",").filter(Boolean) : []; + if (conf.com) { + benchmarks = filterCommonBenchmarks(benchmarks, exes, enviros); + } // Header row: benchmark, then one column per exe@env var header = ["benchmark"]; diff --git a/codespeed/templates/codespeed/comparison.html b/codespeed/templates/codespeed/comparison.html index 02c85424..863c8cf1 100644 --- a/codespeed/templates/codespeed/comparison.html +++ b/codespeed/templates/codespeed/comparison.html @@ -78,6 +78,10 @@ + + + + {% comment %}Bootstrap Icons "download" glyph (MIT, twbs/icons).{% endcomment %} Export CSV {% include "codespeed/permalink.html" %} @@ -99,6 +103,7 @@ chart_type: "{{ selectedchart }}", baseline: "{{ selectedbaseline }}", direction: "{{ selecteddirection }}", + common_only: "{{ selectedcommon }}", executables: [{% for e in checkedexecutables %}"{{ e }}",{% endfor %}], benchmarks: [{% for b in checkedbenchmarks %}{{ b.id }},{% endfor %}], environments: [{% for e in checkedenviros %}{{ e.id }},{% endfor %}], diff --git a/codespeed/views.py b/codespeed/views.py index 02c081c8..d903eb7a 100644 --- a/codespeed/views.py +++ b/codespeed/views.py @@ -476,6 +476,10 @@ def comparison(request): settings.CHART_ORIENTATION == 'horizontal'): selecteddirection = True + # Hide benchmarks that lack a result for any selected executable, so + # every bar group covers the same set of benchmarks. + selectedcommon = data.get('com') == 'true' + return render(request, 'codespeed/comparison.html', { 'checkedexecutables': checkedexecutables, 'checkedbenchmarks': checkedbenchmarks, @@ -487,7 +491,8 @@ def comparison(request): 'charts': charts, 'selectedbaseline': selectedbaseline, 'selectedchart': selectedchart, - 'selecteddirection': selecteddirection + 'selecteddirection': selecteddirection, + 'selectedcommon': selectedcommon, }) def get_setting(name, default = None):