1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Linq ;
4
+ using BenchmarkDotNet . Diagnosers ;
5
+ using BenchmarkDotNet . Mathematics ;
6
+ using BenchmarkDotNet . Reports ;
7
+ using BenchmarkDotNet . Running ;
8
+ using JetBrains . Annotations ;
9
+
10
+ namespace BenchmarkDotNet . Columns
11
+ {
12
+ public class BaselineAllocationRatioColumn : BaselineCustomColumn
13
+ {
14
+ public override string Id => nameof ( BaselineAllocationRatioColumn ) ;
15
+ public override string ColumnName => "Alloc Ratio" ;
16
+
17
+ public override string GetValue ( Summary summary , BenchmarkCase benchmarkCase , Statistics baseline , IReadOnlyDictionary < string , Metric > baselineMetrics ,
18
+ Statistics current , IReadOnlyDictionary < string , Metric > currentMetrics , bool isBaseline )
19
+ {
20
+ double ? ratio = GetAllocationRatio ( currentMetrics , baselineMetrics ) ;
21
+ double ? invertedRatio = GetAllocationRatio ( baselineMetrics , currentMetrics ) ;
22
+
23
+ if ( ratio == null )
24
+ return "NA" ;
25
+
26
+ var cultureInfo = summary . GetCultureInfo ( ) ;
27
+ var ratioStyle = summary ? . Style ? . RatioStyle ?? RatioStyle . Value ;
28
+
29
+ bool advancedPrecision = IsNonBaselinesPrecise ( summary , baselineMetrics , benchmarkCase ) ;
30
+ switch ( ratioStyle )
31
+ {
32
+ case RatioStyle . Value :
33
+ return ratio . Value . ToString ( advancedPrecision ? "N3" : "N2" , cultureInfo ) ;
34
+ case RatioStyle . Percentage :
35
+ return isBaseline
36
+ ? ""
37
+ : ratio . Value >= 1.0
38
+ ? "+" + ( ( ratio . Value - 1.0 ) * 100 ) . ToString ( advancedPrecision ? "N1" : "N0" , cultureInfo ) + "%"
39
+ : "-" + ( ( 1.0 - ratio . Value ) * 100 ) . ToString ( advancedPrecision ? "N1" : "N0" , cultureInfo ) + "%" ;
40
+ case RatioStyle . Trend :
41
+ return isBaseline
42
+ ? ""
43
+ : ratio . Value >= 1.0
44
+ ? ratio . Value . ToString ( advancedPrecision ? "N3" : "N2" , cultureInfo ) + "x more"
45
+ : invertedRatio == null
46
+ ? "NA"
47
+ : invertedRatio . Value . ToString ( advancedPrecision ? "N3" : "N2" , cultureInfo ) + "x less" ;
48
+ default :
49
+ throw new ArgumentOutOfRangeException ( nameof ( summary ) , ratioStyle , "RatioStyle is not supported" ) ;
50
+ }
51
+ }
52
+
53
+ private static bool IsNonBaselinesPrecise ( Summary summary , IReadOnlyDictionary < string , Metric > baselineMetric , BenchmarkCase benchmarkCase )
54
+ {
55
+ string logicalGroupKey = summary . GetLogicalGroupKey ( benchmarkCase ) ;
56
+ var nonBaselines = summary . GetNonBaselines ( logicalGroupKey ) ;
57
+ return nonBaselines . Any ( c => GetAllocationRatio ( summary [ c ] . Metrics , baselineMetric ) is > 0 and < 0.01 ) ;
58
+ }
59
+
60
+ private static double ? GetAllocationRatio (
61
+ [ CanBeNull ] IReadOnlyDictionary < string , Metric > current ,
62
+ [ CanBeNull ] IReadOnlyDictionary < string , Metric > baseline )
63
+ {
64
+ double ? currentBytes = GetAllocatedBytes ( current ) ;
65
+ double ? baselineBytes = GetAllocatedBytes ( baseline ) ;
66
+
67
+ if ( currentBytes == null || baselineBytes == null )
68
+ return null ;
69
+
70
+ if ( baselineBytes == 0 )
71
+ return null ;
72
+
73
+ return currentBytes / baselineBytes ;
74
+ }
75
+
76
+ private static double ? GetAllocatedBytes ( [ CanBeNull ] IReadOnlyDictionary < string , Metric > metrics )
77
+ {
78
+ var metric = metrics ? . Values . FirstOrDefault ( m => m . Descriptor is AllocatedMemoryMetricDescriptor ) ;
79
+ return metric ? . Value ;
80
+ }
81
+
82
+ public override ColumnCategory Category => ColumnCategory . Metric ; //it should be displayed after Allocated column
83
+ public override int PriorityInCategory => AllocatedMemoryMetricDescriptor . Instance . PriorityInCategory + 1 ;
84
+ public override bool IsNumeric => true ;
85
+ public override UnitType UnitType => UnitType . Dimensionless ;
86
+ public override string Legend => "Allocated memory ratio distribution ([Current]/[Baseline])" ;
87
+ }
88
+ }
0 commit comments