@@ -22,7 +22,7 @@ function getConfiguration() {
2222 ben : readCheckbox ( "input[name='benchmarks']:checked" ) ,
2323 env : readCheckbox ( "input[name='environments']:checked" ) ,
2424 hor : $ ( "input[name='direction']" ) . is ( ':checked' ) ,
25- bas : $ ( "#baseline option:selected" ) . val ( ) ,
25+ bas : $ ( "#baseline option:selected" ) . val ( ) || "none" ,
2626 chart : $ ( "#chart_type option:selected" ) . val ( )
2727 } ;
2828}
@@ -52,6 +52,22 @@ function refreshContent() {
5252 msg = '<p class="warning">Normalized stacked bars actually represent the weighted arithmetic sum, useful to spot which individual benchmarks take up the most time. Choosing different weightings from the "Normalization" menu will change the totals relative to one another. For the correct way to calculate total bars, the geometric mean must be used (see <a href="http://portal.acm.org/citation.cfm?id=5666.5673 " title="How not to lie with statistics: the correct way to summarize benchmark results">paper</a>)</p>' ;
5353 }
5454
55+ if ( compdata && compdata . suite_versions ) {
56+ var mismatchedEnvs = enviros . filter ( function ( envId ) {
57+ var versions = new Set ( ) ;
58+ exes . forEach ( function ( exeKey ) {
59+ var sv = compdata . suite_versions [ exeKey ] ;
60+ if ( sv && sv [ envId ] ) {
61+ sv [ envId ] . forEach ( function ( v ) { versions . add ( v ) ; } ) ;
62+ }
63+ } ) ;
64+ return versions . size > 1 ;
65+ } ) ;
66+ if ( mismatchedEnvs . length > 0 ) {
67+ msg += '<p class="warning">The executables being compared used different benchmark suite versions. Results may not be directly comparable.</p>' ;
68+ }
69+ }
70+
5571 chartInstances . forEach ( function ( c ) { c . destroy ( ) ; } ) ;
5672 chartInstances = [ ] ;
5773 $ ( "#plotwrapper" ) . fadeOut ( "fast" , function ( ) {
@@ -90,10 +106,19 @@ function updateBaselineDropdown() {
90106 var $baseline = $ ( "#baseline" ) ;
91107 var current = $baseline . val ( ) ;
92108 $baseline . find ( "option:not([value='none'])" ) . remove ( ) ;
109+ var enviros = readCheckbox ( "input[name='environments']:checked" ) . split ( "," ) . filter ( Boolean ) ;
110+ var multiEnv = enviros . length > 1 ;
93111 $ ( "input[name='executables']:checked" ) . each ( function ( ) {
94112 var key = $ ( this ) . val ( ) ;
95113 var name = $ ( this ) . next ( 'label' ) . text ( ) . trim ( ) ;
96- $baseline . append ( $ ( '<option>' ) . val ( key ) . text ( name ) ) ;
114+ if ( multiEnv ) {
115+ enviros . forEach ( function ( envId ) {
116+ var envName = $ ( "label[for='env_" + envId + "']" ) . text ( ) . trim ( ) ;
117+ $baseline . append ( $ ( '<option>' ) . val ( key + ':' + envId ) . text ( name + ' @ ' + envName ) ) ;
118+ } ) ;
119+ } else {
120+ $baseline . append ( $ ( '<option>' ) . val ( key ) . text ( name ) ) ;
121+ }
97122 } ) ;
98123 if ( $baseline . find ( "option[value='" + current + "']" ) . length ) {
99124 $baseline . val ( current ) ;
@@ -104,7 +129,7 @@ function updateBaselineDropdown() {
104129
105130function loadData ( ) {
106131 var conf = getConfiguration ( ) ;
107- if ( ! conf . exe || ! conf . ben ) { return ; }
132+ if ( ! conf . exe || ! conf . ben ) { refreshContent ( ) ; return ; }
108133 var cacheKey = conf . exe + "|" + conf . ben ;
109134 if ( dataCache [ cacheKey ] ) {
110135 compdata = dataCache [ cacheKey ] ;
@@ -119,7 +144,22 @@ function loadData() {
119144}
120145
121146function renderComparisonPlot ( plotid , unit , benchmarks , exes , enviros , baseline , chart , horizontal ) {
122- var baselineLabel = baseline !== "none" ? $ ( "label[for='exe_" + baseline + "']" ) . text ( ) . trim ( ) : "" ;
147+ // baseline may be "exe_key" or "exe_key:env_id" (for cross-env normalization)
148+ if ( ! baseline ) { baseline = "none" ; }
149+ var baselineExe = baseline , baselineEnv = null ;
150+ if ( baseline !== "none" && baseline . indexOf ( ':' ) !== - 1 ) {
151+ var bparts = baseline . split ( ':' ) ;
152+ baselineExe = bparts [ 0 ] ;
153+ baselineEnv = bparts [ 1 ] ;
154+ }
155+
156+ var baselineLabel = "" ;
157+ if ( baseline !== "none" ) {
158+ baselineLabel = $ ( "label[for='exe_" + baselineExe + "']" ) . text ( ) . trim ( ) ;
159+ if ( baselineEnv !== null ) {
160+ baselineLabel += ' @ ' + $ ( "label[for='env_" + baselineEnv + "']" ) . text ( ) . trim ( ) ;
161+ }
162+ }
123163
124164 var title ;
125165 if ( baseline === "none" ) {
@@ -148,15 +188,17 @@ function renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, baseline,
148188 for ( var i = 0 ; i < exes . length ; i ++ ) {
149189 for ( var j = 0 ; j < enviros . length ; j ++ ) {
150190 var exeLabel = $ ( "label[for='exe_" + exes [ i ] + "']" ) . text ( ) . trim ( ) ;
151- if ( chart === "relative bars" && exes [ i ] === baseline ) { continue ; }
191+ if ( chart === "relative bars" && exes [ i ] === baselineExe &&
192+ ( baselineEnv === null || baselineEnv === enviros [ j ] ) ) { continue ; }
152193 var data = [ ] ;
153194 for ( var b = 0 ; b < benchmarks . length ; b ++ ) {
154195 var val = compdata [ exes [ i ] ] && compdata [ exes [ i ] ] [ enviros [ j ] ]
155196 ? compdata [ exes [ i ] ] [ enviros [ j ] ] [ benchmarks [ b ] ]
156197 : null ;
157198 if ( val !== null && baseline !== "none" ) {
158- var baseval = compdata [ baseline ] && compdata [ baseline ] [ enviros [ j ] ]
159- ? compdata [ baseline ] [ enviros [ j ] ] [ benchmarks [ b ] ]
199+ var envForBase = baselineEnv !== null ? baselineEnv : enviros [ j ] ;
200+ var baseval = compdata [ baselineExe ] && compdata [ baselineExe ] [ envForBase ]
201+ ? compdata [ baselineExe ] [ envForBase ] [ benchmarks [ b ] ]
160202 : null ;
161203 val = ( baseval === null || baseval === 0 ) ? null : val / baseval ;
162204 }
@@ -189,8 +231,9 @@ function renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, baseline,
189231 ? compdata [ exes [ i ] ] [ enviros [ j ] ] [ benchmarks [ b ] ]
190232 : null ;
191233 if ( val !== null && baseline !== "none" ) {
192- var baseval = compdata [ baseline ] && compdata [ baseline ] [ enviros [ j ] ]
193- ? compdata [ baseline ] [ enviros [ j ] ] [ benchmarks [ b ] ]
234+ var envForBase = baselineEnv !== null ? baselineEnv : enviros [ j ] ;
235+ var baseval = compdata [ baselineExe ] && compdata [ baselineExe ] [ envForBase ]
236+ ? compdata [ baselineExe ] [ envForBase ] [ benchmarks [ b ] ]
194237 : null ;
195238 val = ( baseval === null || baseval === 0 ) ? null : val / baseval ;
196239 }
@@ -204,6 +247,11 @@ function renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, baseline,
204247
205248 if ( datasets . length === 0 ) { return ; }
206249
250+ // Mark datasets where all values are null (baseline has no data for that env)
251+ datasets . forEach ( function ( ds ) {
252+ ds . allNull = ds . data . every ( function ( v ) { return v === null ; } ) ;
253+ } ) ;
254+
207255 // Size the container
208256 var wrapWidth = $ ( "#plotwrapper" ) . width ( ) ;
209257 var h = horizontal
@@ -247,7 +295,19 @@ function renderComparisonPlot(plotid, unit, benchmarks, exes, enviros, baseline,
247295 font : { size : FONT_SIZE } ,
248296 boxWidth : 20 ,
249297 boxHeight : FONT_SIZE ,
250- padding : 8
298+ padding : 8 ,
299+ generateLabels : function ( chart ) {
300+ var items = Chart . defaults . plugins . legend . labels . generateLabels ( chart ) ;
301+ items . forEach ( function ( item ) {
302+ var ds = chart . data . datasets [ item . datasetIndex ] ;
303+ if ( ds && ds . allNull ) {
304+ // Apply unicode combining strikethrough to each character
305+ item . text = item . text . split ( '' ) . join ( '\u0336' ) + '\u0336' ;
306+ item . fontColor = '#aaa' ;
307+ }
308+ } ) ;
309+ return items ;
310+ }
251311 }
252312 }
253313 } ,
@@ -298,7 +358,11 @@ function init(defaults) {
298358 $ ( "#benchmark .checkall, #benchmark .uncheckall" ) . click ( loadData ) ;
299359
300360 // Re-render without re-fetching for other controls
301- $ ( "#chart_type, #baseline, #direction, input[name='environments']" ) . change ( refreshContent ) ;
361+ $ ( "#chart_type, #baseline, #direction" ) . change ( refreshContent ) ;
362+ $ ( "input[name='environments']" ) . change ( function ( ) {
363+ updateBaselineDropdown ( ) ;
364+ refreshContent ( ) ;
365+ } ) ;
302366
303367 $ . ajaxSetup ( {
304368 cache : false
@@ -309,6 +373,49 @@ function init(defaults) {
309373 $ ( "#permalink" ) . click ( function ( ) {
310374 window . location = "?" + $ . param ( getConfiguration ( ) ) ;
311375 } ) ;
376+
377+ $ ( "#exportcsv" ) . click ( function ( e ) {
378+ e . preventDefault ( ) ;
379+ if ( ! compdata ) { return ; }
380+ var conf = getConfiguration ( ) ;
381+ var exes = conf . exe ? conf . exe . split ( "," ) . filter ( Boolean ) : [ ] ;
382+ var enviros = readCheckbox ( "input[name='environments']:checked" ) . split ( "," ) . filter ( Boolean ) ;
383+ var benchmarks = conf . ben ? conf . ben . split ( "," ) . filter ( Boolean ) : [ ] ;
384+
385+ // Header row: benchmark, then one column per exe@env
386+ var header = [ "benchmark" ] ;
387+ for ( var i = 0 ; i < exes . length ; i ++ ) {
388+ for ( var j = 0 ; j < enviros . length ; j ++ ) {
389+ var exeLabel = $ ( "label[for='exe_" + exes [ i ] + "']" ) . text ( ) . trim ( ) ;
390+ var envLabel = $ ( "label[for='env_" + enviros [ j ] + "']" ) . text ( ) . trim ( ) ;
391+ header . push ( enviros . length > 1 ? exeLabel + "@" + envLabel : exeLabel ) ;
392+ }
393+ }
394+
395+ var rows = [ header ] ;
396+ for ( var b = 0 ; b < benchmarks . length ; b ++ ) {
397+ var benchLabel = $ ( "label[for='benchmark_" + benchmarks [ b ] + "']" ) . text ( ) . trim ( ) ;
398+ var row = [ benchLabel ] ;
399+ for ( var i = 0 ; i < exes . length ; i ++ ) {
400+ for ( var j = 0 ; j < enviros . length ; j ++ ) {
401+ var val = compdata [ exes [ i ] ] && compdata [ exes [ i ] ] [ enviros [ j ] ]
402+ ? compdata [ exes [ i ] ] [ enviros [ j ] ] [ benchmarks [ b ] ]
403+ : "" ;
404+ row . push ( val === null || val === undefined ? "" : val ) ;
405+ }
406+ }
407+ rows . push ( row ) ;
408+ }
409+
410+ var csv = rows . map ( function ( r ) { return r . join ( "," ) ; } ) . join ( "\n" ) ;
411+ var blob = new Blob ( [ csv ] , { type : "text/csv" } ) ;
412+ var url = URL . createObjectURL ( blob ) ;
413+ var a = document . createElement ( "a" ) ;
414+ a . href = url ;
415+ a . download = "comparison.csv" ;
416+ a . click ( ) ;
417+ URL . revokeObjectURL ( url ) ;
418+ } ) ;
312419}
313420
314421return {
0 commit comments