11using BenchmarkDotNet . Exporters ;
2- using BenchmarkDotNet . Reports ;
3- using Plotly . NET . ImageExport ;
42using BenchmarkDotNet . Loggers ;
3+ using BenchmarkDotNet . Reports ;
4+
55using Plotly . NET ;
6+ using Plotly . NET . ImageExport ;
67using Plotly . NET . LayoutObjects ;
78using static Plotly . NET . StyleParam ;
9+
810using Microsoft . FSharp . Core ;
911
1012namespace Benchly
@@ -22,24 +24,120 @@ public IEnumerable<string> ExportToFiles(Summary summary, ILogger consoleLogger)
2224 return Array . Empty < string > ( ) ;
2325 }
2426
25- if ( summary . Reports [ 0 ] . BenchmarkCase . HasParameters )
27+ return Info . OutputMode switch
2628 {
27- int paramCount = summary . Reports [ 0 ] . BenchmarkCase . Parameters . Count ;
29+ OutputMode . PerMethod => PerMethod ( summary ) ,
30+ OutputMode . PerJob => PerJob ( summary ) ,
31+ OutputMode . Combined => Combined ( summary ) ,
32+ _ => Array . Empty < string > ( ) ,
33+ } ;
34+ }
2835
29- if ( paramCount == 1 )
36+ public void ExportToLog ( Summary summary , ILogger logger )
37+ {
38+ }
39+
40+ // Revisit this in terms of params:
41+ // This would make most sense if used with params, so that you
42+ // could look at the results for all param values for each method
43+ private IEnumerable < string > PerMethod ( Summary summary )
44+ {
45+ var files = new List < string > ( ) ;
46+
47+ foreach ( var report in summary . Reports )
48+ {
49+ if ( ! report . Success )
3050 {
31- return OneParameter ( summary ) ;
51+ continue ;
3252 }
53+
54+ int paramCount = report . BenchmarkCase . Parameters . Count ;
55+
56+ var title = this . Info . Title ?? summary . Title ;
57+ var fileSlug = paramCount == 0
58+ ? report . BenchmarkCase . Job . ResolvedId + "-" + report . BenchmarkCase . Descriptor . WorkloadMethodDisplayInfo
59+ : report . BenchmarkCase . Job . ResolvedId + "-" + report . BenchmarkCase . Descriptor . WorkloadMethodDisplayInfo + "-" + report . BenchmarkCase . Parameters . PrintInfo ;
60+
61+ fileSlug += "-columnchart" ;
62+ var file = Path . Combine ( summary . ResultsDirectoryPath , ExporterBase . GetFileName ( summary ) + fileSlug ) ;
63+
64+ var mean = new [ ] { ConvertNanosToMs ( report . ResultStatistics . Mean ) } ;
65+ var name = report . BenchmarkCase . Descriptor . WorkloadMethodDisplayInfo ;
66+
67+ Chart2D . Chart . Column < double , string , string , double , double > ( mean , Name : name )
68+ . WithAxisTitles ( "Time (ms)" )
69+ . WithoutVerticalGridlines ( )
70+ . WithLayout ( title )
71+ . SaveSVG ( file , Width : Info . Width , Height : Info . Height ) ;
72+
73+ files . Add ( file + ".svg" ) ;
74+ }
75+ return files ;
76+ }
77+ private IEnumerable < string > PerJob ( Summary summary )
78+ {
79+ // don't support params for now
80+ if ( summary . Reports [ 0 ] . BenchmarkCase . HasParameters )
81+ {
82+ return Array . Empty < string > ( ) ;
83+ }
84+
85+ var files = new List < string > ( ) ;
86+
87+ var jobs = summary . Reports . Select ( r => new
88+ {
89+ job = r . BenchmarkCase . Job . ResolvedId ,
90+ name = r . BenchmarkCase . Descriptor . WorkloadMethodDisplayInfo ,
91+ mean = r . Success ? ConvertNanosToMs ( r . ResultStatistics . Mean ) : 0
92+ } ) . GroupBy ( r => r . job ) ;
93+
94+ foreach ( var job in jobs )
95+ {
96+ var title = this . Info . Title ?? summary . Title ;
97+ var file = Path . Combine ( summary . ResultsDirectoryPath , ExporterBase . GetFileName ( summary ) + "-" + job . Key + "-columnchart" ) ;
98+
99+ var colors = ColorMap . GetColorList ( Info ) ;
100+
101+ // make 1 chart per column so that we can color by bar index. Legend is disabled since it is not needed.
102+ var charts = job
103+ . Select ( ( j , i ) => Chart2D . Chart . Column < double , string , string , double , double > (
104+ new [ ] { j . mean } ,
105+ new [ ] { j . name } ,
106+ Name : job . Key ,
107+ MarkerColor : colors [ i % colors . Length ] )
108+ . WithLegendGroup ( job . Key , false ) ) ;
109+
110+ Chart . Combine ( charts )
111+ . WithAxisTitles ( "Time (ms)" )
112+ . WithoutVerticalGridlines ( )
113+ . WithLayout ( title )
114+ . SaveSVG ( file , Width : Info . Width , Height : Info . Height ) ;
115+
116+ files . Add ( file + ".svg" ) ;
33117 }
34118
35- return NoParameter ( summary ) ;
119+ return files ;
36120 }
37121
38- public void ExportToLog ( Summary summary , ILogger logger )
122+ private IEnumerable < string > Combined ( Summary summary )
39123 {
124+ if ( summary . Reports [ 0 ] . BenchmarkCase . HasParameters )
125+ {
126+ int paramCount = summary . Reports [ 0 ] . BenchmarkCase . Parameters . Count ;
127+
128+ if ( paramCount == 1 )
129+ {
130+ return OneParameterCombined ( summary ) ;
131+ }
132+
133+ // we only support 0 or 1 params
134+ return Array . Empty < string > ( ) ;
135+ }
136+
137+ return NoParameterCombined ( summary ) ;
40138 }
41139
42- private IEnumerable < string > NoParameter ( Summary summary )
140+ private IEnumerable < string > NoParameterCombined ( Summary summary )
43141 {
44142 var title = this . Info . Title ?? summary . Title ;
45143 var file = Path . Combine ( summary . ResultsDirectoryPath , ExporterBase . GetFileName ( summary ) + "-columnchart" ) ;
@@ -72,7 +170,7 @@ private IEnumerable<string> NoParameter(Summary summary)
72170 return new [ ] { file + ".svg" } ;
73171 }
74172
75- private IEnumerable < string > OneParameter ( Summary summary )
173+ private IEnumerable < string > OneParameterCombined ( Summary summary )
76174 {
77175 var title = this . Info . Title ?? summary . Title ;
78176 var file = Path . Combine ( summary . ResultsDirectoryPath , ExporterBase . GetFileName ( summary ) + "-columnchart" ) ;
@@ -112,7 +210,6 @@ private IEnumerable<string> OneParameter(Summary summary)
112210 }
113211
114212 // https://github.com/plotly/Plotly.NET/issues/387
115- // The alignment of this isn't 100% correct. Another approach may be to give each sub chart an x axis title
116213 double xWidth = 1.0d / byParam . Count ( ) ;
117214 double xMidpoint = xWidth / 2.0d ;
118215 double [ ] xs = byParam . Select ( ( _ , index ) => xMidpoint + ( xWidth * index ) ) . ToArray ( ) ;
0 commit comments