Skip to content

Commit 88cb483

Browse files
authored
If a metric value could not be calculated, display ? instead of -. (#2106)
* If a metric value could not be calculated, display `?` instead of `-`. * Revert Metric.cs, don't add allocated metric if it could not be calculated. Show allocated column even if no measurements were calculated. * Show metric columns in a more abstract way. Add additional force-show metric columns. * Use constant instead of "?". * Add locks to be safe. * Update interfaces instead of static type dictionaries. * Move logic to Metric class instead of interfaces. * Implement feedback.
1 parent c4debea commit 88cb483

26 files changed

+182
-70
lines changed

src/BenchmarkDotNet.Diagnostics.Windows/JitStatsDiagnoser.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ private sealed class MethodsJittedDescriptor : IMetricDescriptor
6969
public UnitType UnitType => UnitType.Dimensionless;
7070
public string Unit => "Count";
7171
public int PriorityInCategory => 0;
72+
public bool GetIsAvailable(Metric metric) => true;
7273
}
7374

7475
private sealed class MethodsTieredDescriptor : IMetricDescriptor
@@ -83,6 +84,7 @@ private sealed class MethodsTieredDescriptor : IMetricDescriptor
8384
public UnitType UnitType => UnitType.Dimensionless;
8485
public string Unit => "Count";
8586
public int PriorityInCategory => 0;
87+
public bool GetIsAvailable(Metric metric) => true;
8688
}
8789

8890
private sealed class JitAllocatedMemoryDescriptor : IMetricDescriptor
@@ -97,6 +99,7 @@ private sealed class JitAllocatedMemoryDescriptor : IMetricDescriptor
9799
public UnitType UnitType => UnitType.Size;
98100
public string Unit => SizeUnit.B.Name;
99101
public int PriorityInCategory => 0;
102+
public bool GetIsAvailable(Metric metric) => true;
100103
}
101104
}
102105

src/BenchmarkDotNet.Diagnostics.Windows/Tracing/NativeMemoryLogParser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,8 @@ bool IsCallStackIn(StackSourceCallStackIndex index)
262262

263263
return new[]
264264
{
265-
new Metric(new AllocatedNativeMemoryDescriptor(), memoryAllocatedPerOperation),
266-
new Metric(new NativeMemoryLeakDescriptor(), memoryLeakPerOperation)
265+
new Metric(AllocatedNativeMemoryDescriptor.Instance, memoryAllocatedPerOperation),
266+
new Metric(NativeMemoryLeakDescriptor.Instance, memoryLeakPerOperation)
267267
};
268268
}
269269

src/BenchmarkDotNet/Columns/BaselineCustomColumn.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public string GetValue(Summary summary, BenchmarkCase benchmarkCase)
1818
bool isBaseline = summary.IsBaseline(benchmarkCase);
1919

2020
if (ResultsAreInvalid(summary, benchmarkCase, baseline))
21-
return "?";
21+
return MetricColumn.UnknownRepresentation;
2222

2323
var baselineStat = summary[baseline].ResultStatistics;
2424
var baselineMetrics = summary[baseline].Metrics;

src/BenchmarkDotNet/Columns/MetricColumn.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ namespace BenchmarkDotNet.Columns
88
{
99
public class MetricColumn : IColumn
1010
{
11+
internal const string UnknownRepresentation = "?";
12+
1113
private readonly IMetricDescriptor descriptor;
1214

1315
public MetricColumn(IMetricDescriptor metricDescriptor) => descriptor = metricDescriptor;
@@ -23,13 +25,19 @@ public class MetricColumn : IColumn
2325

2426
public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false;
2527

26-
public bool IsAvailable(Summary summary) => summary.Reports.Any(report => report.Metrics.ContainsKey(descriptor.Id));
28+
public bool IsAvailable(Summary summary) => summary.Reports.Any(report =>
29+
report.Metrics.TryGetValue(descriptor.Id, out var metric)
30+
&& metric.Descriptor.GetIsAvailable(metric));
2731

2832
public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => GetValue(summary, benchmarkCase, SummaryStyle.Default);
2933

3034
public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style)
3135
{
32-
if (!summary.HasReport(benchmarkCase) || !summary[benchmarkCase].Metrics.TryGetValue(descriptor.Id, out Metric metric) || (metric.Value == 0.0 && !style.PrintZeroValuesInContent))
36+
if (!summary.HasReport(benchmarkCase) || !summary[benchmarkCase].Metrics.TryGetValue(descriptor.Id, out Metric metric))
37+
return "NA";
38+
if (double.IsNaN(metric.Value))
39+
return UnknownRepresentation;
40+
if (metric.Value == 0.0 && !style.PrintZeroValuesInContent)
3341
return "-";
3442

3543
var cultureInfo = summary.GetCultureInfo();
@@ -38,9 +46,9 @@ public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyl
3846
UnitPresentation unitPresentation = UnitPresentation.FromVisibility(style.PrintUnitsInContent);
3947

4048
if (printUnits && descriptor.UnitType == UnitType.CodeSize)
41-
return SizeValue.FromBytes((long)metric.Value).ToString(style.CodeSizeUnit, cultureInfo, descriptor.NumberFormat, unitPresentation);
49+
return SizeValue.FromBytes((long) metric.Value).ToString(style.CodeSizeUnit, cultureInfo, descriptor.NumberFormat, unitPresentation);
4250
if (printUnits && descriptor.UnitType == UnitType.Size)
43-
return SizeValue.FromBytes((long)metric.Value).ToString(style.SizeUnit, cultureInfo, descriptor.NumberFormat, unitPresentation);
51+
return SizeValue.FromBytes((long) metric.Value).ToString(style.SizeUnit, cultureInfo, descriptor.NumberFormat, unitPresentation);
4452
if (printUnits && descriptor.UnitType == UnitType.Time)
4553
return TimeInterval.FromNanoseconds(metric.Value).ToString(style.TimeUnit, cultureInfo, descriptor.NumberFormat, unitPresentation);
4654

src/BenchmarkDotNet/Columns/RankColumn.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public string GetValue(Summary summary, BenchmarkCase benchmarkCase)
2828
.ToArray();
2929
int index = Array.IndexOf(logicalGroup, benchmarkCase);
3030
if (index == -1)
31-
return "?";
31+
return MetricColumn.UnknownRepresentation;
3232

3333
var ranks = RankHelper.GetRanks(logicalGroup.Select(b => summary[b].ResultStatistics).ToArray());
3434
int rank = ranks[index];

src/BenchmarkDotNet/Diagnosers/AllocatedMemoryMetricDescriptor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ internal class AllocatedMemoryMetricDescriptor : IMetricDescriptor
1616
public string Unit => SizeUnit.B.Name;
1717
public bool TheGreaterTheBetter => false;
1818
public int PriorityInCategory => GC.MaxGeneration + 1;
19+
public bool GetIsAvailable(Metric metric) => true;
1920
}
2021
}

src/BenchmarkDotNet/Diagnosers/AllocatedNativeMemoryDescriptor.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ namespace BenchmarkDotNet.Diagnosers
55
{
66
internal class AllocatedNativeMemoryDescriptor : IMetricDescriptor
77
{
8+
internal static readonly IMetricDescriptor Instance = new AllocatedNativeMemoryDescriptor();
9+
810
public string Id => nameof(AllocatedNativeMemoryDescriptor);
911
public string DisplayName => Column.AllocatedNativeMemory;
1012
public string Legend => $"Allocated native memory per single operation";
@@ -13,10 +15,13 @@ internal class AllocatedNativeMemoryDescriptor : IMetricDescriptor
1315
public string Unit => SizeUnit.B.Name;
1416
public bool TheGreaterTheBetter => false;
1517
public int PriorityInCategory => 0;
18+
public bool GetIsAvailable(Metric metric) => true;
1619
}
1720

1821
internal class NativeMemoryLeakDescriptor : IMetricDescriptor
1922
{
23+
internal static readonly IMetricDescriptor Instance = new NativeMemoryLeakDescriptor();
24+
2025
public string Id => nameof(NativeMemoryLeakDescriptor);
2126
public string DisplayName => Column.NativeMemoryLeak;
2227
public string Legend => $"Native memory leak size in byte.";
@@ -25,5 +30,6 @@ internal class NativeMemoryLeakDescriptor : IMetricDescriptor
2530
public string Unit => SizeUnit.B.Name;
2631
public bool TheGreaterTheBetter => false;
2732
public int PriorityInCategory => 0;
33+
public bool GetIsAvailable(Metric metric) => true;
2834
}
2935
}

src/BenchmarkDotNet/Diagnosers/ExceptionDiagnoser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ private class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
4949
public string Unit => "Count";
5050
public bool TheGreaterTheBetter => false;
5151
public int PriorityInCategory => 0;
52+
public bool GetIsAvailable(Metric metric) => true;
5253
}
5354
}
5455
}

src/BenchmarkDotNet/Diagnosers/MemoryDiagnoser.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,14 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { }
3434

3535
public IEnumerable<Metric> ProcessResults(DiagnoserResults diagnoserResults)
3636
{
37-
if (diagnoserResults.GcStats.Gen0Collections > 0 && Config.DisplayGenColumns)
38-
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen0, diagnoserResults.GcStats.Gen0Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
39-
if (diagnoserResults.GcStats.Gen1Collections > 0 && Config.DisplayGenColumns)
40-
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen1, diagnoserResults.GcStats.Gen1Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
41-
if (diagnoserResults.GcStats.Gen2Collections > 0 && Config.DisplayGenColumns)
42-
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen2, diagnoserResults.GcStats.Gen2Collections / (double)diagnoserResults.GcStats.TotalOperations * 1000);
37+
if (Config.DisplayGenColumns)
38+
{
39+
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen0, diagnoserResults.GcStats.Gen0Collections / (double) diagnoserResults.GcStats.TotalOperations * 1000);
40+
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen1, diagnoserResults.GcStats.Gen1Collections / (double) diagnoserResults.GcStats.TotalOperations * 1000);
41+
yield return new Metric(GarbageCollectionsMetricDescriptor.Gen2, diagnoserResults.GcStats.Gen2Collections / (double) diagnoserResults.GcStats.TotalOperations * 1000);
42+
}
4343

44-
yield return new Metric(AllocatedMemoryMetricDescriptor.Instance, diagnoserResults.GcStats.GetBytesAllocatedPerOperation(diagnoserResults.BenchmarkCase));
44+
yield return new Metric(AllocatedMemoryMetricDescriptor.Instance, diagnoserResults.GcStats.GetBytesAllocatedPerOperation(diagnoserResults.BenchmarkCase) ?? double.NaN);
4545
}
4646

4747
private class GarbageCollectionsMetricDescriptor : IMetricDescriptor
@@ -66,6 +66,7 @@ private GarbageCollectionsMetricDescriptor(int generationId, string columnName)
6666
public string Unit => "Count";
6767
public bool TheGreaterTheBetter => false;
6868
public int PriorityInCategory { get; }
69+
public bool GetIsAvailable(Metric metric) => metric.Value > 0;
6970
}
7071
}
7172
}

src/BenchmarkDotNet/Diagnosers/PmcMetricDescriptor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ internal PmcMetricDescriptor(PreciseMachineCounter counter)
2121
public UnitType UnitType => UnitType.Dimensionless;
2222
public string Unit => "Count";
2323
public int PriorityInCategory => 0;
24+
public bool GetIsAvailable(Metric metric) => true;
2425
}
2526
}

0 commit comments

Comments
 (0)