Skip to content

Commit 8ec00dd

Browse files
Hiding columns (#1890)
* Move literals into a class; In future it will be used for cli code completion; StatisticalTest/HardwareCounters/CiLower are missing * Add HideColumns * Do not start printing a table when no columns, Replace it with the message * Show legends only for visible columns i.e. hide the time legend when Mean&Error are hidden * Replace AllocRatio ctor creation to the static field, like BaselineRatioColumn.RatioMean * Encapsulate tight logic in SummaryTableColumn * Add CLI support * Print common columns when all columns are hidden * solve warnings and errors * improvements: - don't store Names in the field when there is no need to - make it possible to apply `[HideColumnsAttribute]` to entire assembly - add comment explaining why Column class is public - make two existing column hiding rules public so they can be reused - Column.IsCommon is better name than Column.IsCommonColumn - simplify LINQ -add sample Co-authored-by: Adam Sitnik <[email protected]>
1 parent 8380003 commit 8ec00dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+375
-70
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Columns;
3+
4+
namespace BenchmarkDotNet.Samples
5+
{
6+
[MemoryDiagnoser] // adds Gen0, Gen1, Gen2 and Allocated Bytes columns
7+
[HideColumns(Column.Gen0, Column.Gen1, Column.Gen2)] // dont display GenX columns
8+
public class IntroHidingColumns
9+
{
10+
[Benchmark]
11+
public byte[] AllocateArray() => new byte[100_000];
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using BenchmarkDotNet.Extensions;
4+
using BenchmarkDotNet.Reports;
5+
6+
namespace BenchmarkDotNet.Analysers
7+
{
8+
public class HideColumnsAnalyser : AnalyserBase
9+
{
10+
public static readonly IAnalyser Default = new HideColumnsAnalyser();
11+
12+
public override string Id => nameof(HideColumnsAnalyser);
13+
14+
protected override IEnumerable<Conclusion> AnalyseSummary(Summary summary)
15+
{
16+
var hiddenColumns = summary.GetTable(summary.Style).Columns.Where(c => c.WasHidden).ToArray();
17+
18+
if (hiddenColumns.IsEmpty())
19+
yield break;
20+
21+
var columnNames = string.Join(", ", hiddenColumns.Select(c => c.OriginalColumn.ColumnName));
22+
23+
var message = $"Hidden columns: {columnNames}";
24+
yield return Conclusion.CreateHint(Id, message);
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using BenchmarkDotNet.Configs;
3+
using JetBrains.Annotations;
4+
5+
namespace BenchmarkDotNet.Attributes
6+
{
7+
[PublicAPI]
8+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)]
9+
public class HideColumnsAttribute : Attribute, IConfigSource
10+
{
11+
public IConfig Config { get; }
12+
13+
// CLS-Compliant Code requires a constructor without an array in the argument list
14+
protected HideColumnsAttribute() => Config = ManualConfig.CreateEmpty();
15+
16+
public HideColumnsAttribute(params string[] names) => Config = ManualConfig.CreateEmpty().HideColumns(names);
17+
}
18+
}

src/BenchmarkDotNet/Columns/BaselineAllocationRatioColumn.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ namespace BenchmarkDotNet.Columns
1212
public class BaselineAllocationRatioColumn : BaselineCustomColumn
1313
{
1414
public override string Id => nameof(BaselineAllocationRatioColumn);
15-
public override string ColumnName => "Alloc Ratio";
15+
16+
public override string ColumnName => Column.AllocRatio;
17+
18+
public static readonly IColumn RatioMean = new BaselineAllocationRatioColumn();
19+
20+
private BaselineAllocationRatioColumn() { }
1621

1722
public override string GetValue(Summary summary, BenchmarkCase benchmarkCase, Statistics baseline, IReadOnlyDictionary<string, Metric> baselineMetrics,
1823
Statistics current, IReadOnlyDictionary<string, Metric> currentMetrics, bool isBaseline)

src/BenchmarkDotNet/Columns/BaselineColumn.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class BaselineColumn : IColumn
99
[PublicAPI] public static readonly IColumn Default = new BaselineColumn();
1010

1111
public string Id => nameof(BaselineColumn);
12-
public string ColumnName => "Baseline";
12+
public string ColumnName => Column.Baseline;
1313

1414
public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => summary.IsBaseline(benchmarkCase) ? "Yes" : "No";
1515
public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase);

src/BenchmarkDotNet/Columns/BaselineRatioColumn.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ public override string ColumnName
3535
switch (Metric)
3636
{
3737
case RatioMetric.Mean:
38-
return "Ratio";
38+
return Column.Ratio;
3939
case RatioMetric.StdDev:
40-
return "RatioSD";
40+
return Column.RatioSD;
4141
default:
4242
throw new NotSupportedException();
4343
}

src/BenchmarkDotNet/Columns/CategoriesColumn.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class CategoriesColumn : IColumn
1010
public static readonly IColumn Default = new CategoriesColumn();
1111

1212
public string Id => nameof(CategoriesColumn);
13-
public string ColumnName => "Categories";
13+
public string ColumnName => Column.Categories;
1414
public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => string.Join(",", benchmarkCase.Descriptor.Categories);
1515
public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase);
1616
public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false;

src/BenchmarkDotNet/Columns/Column.cs

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using JetBrains.Annotations;
2+
3+
namespace BenchmarkDotNet.Columns
4+
{
5+
// ReSharper disable once InconsistentNaming
6+
[PublicAPI] // this type is public, so the users can do things like [HideColumns(Column.$)] and get suggestions from IDE
7+
public static class Column
8+
{
9+
public const string Namespace = "Namespace";
10+
public const string Type = "Type";
11+
public const string Method = "Method";
12+
13+
public const string Job = "Job";
14+
15+
public const string Mean = "Mean";
16+
public const string StdErr = "StdErr";
17+
public const string StdDev = "StdDev";
18+
public const string Error = "Error";
19+
public const string OperationPerSecond = "Op/s";
20+
public const string Min = "Min";
21+
public const string Q1 = "Q1";
22+
public const string Median = "Median";
23+
public const string Q3 = "Q3";
24+
public const string Max = "Max";
25+
public const string Skewness = "Skewness";
26+
public const string Kurtosis = "Kurtosis";
27+
public const string MValue = "MValue";
28+
public const string Iterations = "Iterations";
29+
30+
public const string P0 = "P0";
31+
public const string P25 = "P25";
32+
public const string P50 = "P50";
33+
public const string P67 = "P67";
34+
public const string P80 = "P80";
35+
public const string P85 = "P85";
36+
public const string P90 = "P90";
37+
public const string P95 = "P95";
38+
public const string P100 = "P100";
39+
40+
public const string Categories = "Categories";
41+
public const string LogicalGroup = "LogicalGroup";
42+
public const string Rank = "Rank";
43+
44+
public const string Ratio = "Ratio";
45+
public const string RatioSD = "RatioSD";
46+
public const string AllocRatio = "Alloc Ratio";
47+
48+
public const string Allocated = "Allocated";
49+
public const string Gen0 = "Gen0";
50+
public const string Gen1 = "Gen1";
51+
public const string Gen2 = "Gen2";
52+
53+
public const string AllocatedNativeMemory = "Allocated native memory";
54+
public const string NativeMemoryLeak = "Native memory leak";
55+
public const string CompletedWorkItems = "Completed Work Items";
56+
public const string LockContentions = "Lock Contentions";
57+
public const string CodeSize = "Code Size";
58+
59+
//Characteristics:
60+
public const string Id = "Id";
61+
62+
public const string MaxRelativeError = "MaxRelativeError";
63+
public const string MaxAbsoluteError = "MaxAbsoluteError";
64+
public const string MinIterationTime = "MinIterationTime";
65+
public const string MinInvokeCount = "MinInvokeCount";
66+
public const string EvaluateOverhead = "EvaluateOverhead";
67+
public const string OutlierMode = "OutlierMode";
68+
public const string AnalyzeLaunchVariance = "AnalyzeLaunchVariance";
69+
70+
public const string Platform = "Platform";
71+
public const string Jit = "Jit";
72+
public const string Runtime = "Runtime";
73+
public const string Affinity = "Affinity";
74+
public const string Gc = "Gc";
75+
public const string EnvironmentVariables = "EnvironmentVariables";
76+
public const string PowerPlanMode = "PowerPlanMode";
77+
78+
public const string Server = "Server";
79+
public const string Concurrent = "Concurrent";
80+
public const string CpuGroups = "CpuGroups";
81+
public const string Force = "Force";
82+
public const string AllowVeryLargeObjects = "AllowVeryLargeObjects";
83+
public const string RetainVm = "RetainVm";
84+
public const string NoAffinitize = "NoAffinitize";
85+
public const string HeapAffinitizeMask = "HeapAffinitizeMask";
86+
public const string HeapCount = "HeapCount";
87+
88+
public const string Toolchain = "Toolchain";
89+
public const string Clock = "Clock";
90+
public const string EngineFactory = "EngineFactory";
91+
public const string BuildConfiguration = "BuildConfiguration";
92+
public const string Arguments = "Arguments";
93+
public const string NuGetReferences = "NuGetReferences";
94+
95+
public const string Environment = "Environment";
96+
public const string Run = "Run";
97+
public const string Infrastructure = "Infrastructure";
98+
public const string Accuracy = "Accuracy";
99+
public const string Meta = "Meta";
100+
101+
public const string Baseline = "Baseline";
102+
public const string IsMutator = "IsMutator";
103+
public const string IsDefault = "IsDefault";
104+
105+
public const string RunStrategy = "RunStrategy";
106+
public const string LaunchCount = "LaunchCount";
107+
public const string InvocationCount = "InvocationCount";
108+
public const string UnrollFactor = "UnrollFactor";
109+
public const string IterationCount = "IterationCount";
110+
public const string MinIterationCount = "MinIterationCount";
111+
public const string MaxIterationCount = "MaxIterationCount";
112+
public const string IterationTime = "IterationTime";
113+
public const string WarmupCount = "WarmupCount";
114+
public const string MinWarmupIterationCount = "MinWarmupIterationCount";
115+
public const string MaxWarmupIterationCount = "MaxWarmupIterationCount";
116+
public const string MemoryRandomization = "MemoryRandomization";
117+
}
118+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using JetBrains.Annotations;
2+
3+
namespace BenchmarkDotNet.Columns
4+
{
5+
[PublicAPI]
6+
public class ColumnHidingByIdRule: IColumnHidingRule
7+
{
8+
public string Id { get; }
9+
10+
public ColumnHidingByIdRule(IColumn column) => Id = column.Id;
11+
12+
public bool NeedToHide(IColumn column) => column.Id == Id;
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using JetBrains.Annotations;
2+
3+
namespace BenchmarkDotNet.Columns
4+
{
5+
[PublicAPI]
6+
public class ColumnHidingByNameRule: IColumnHidingRule
7+
{
8+
public string Name { get; }
9+
10+
public ColumnHidingByNameRule(string name) => Name = name;
11+
12+
public bool NeedToHide(IColumn column) => column.ColumnName == Name;
13+
}
14+
}

src/BenchmarkDotNet/Columns/DefaultColumnProvider.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public IEnumerable<IColumn> GetColumns(Summary summary)
6666

6767
if (HasMemoryDiagnoser(summary))
6868
{
69-
yield return new BaselineAllocationRatioColumn();
69+
yield return BaselineAllocationRatioColumn.RatioMean;
7070
}
7171
}
7272
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace BenchmarkDotNet.Columns
2+
{
3+
public interface IColumnHidingRule
4+
{
5+
bool NeedToHide(IColumn column);
6+
}
7+
}

src/BenchmarkDotNet/Columns/JobCharacteristicColumn.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ private JobCharacteristicColumn(Characteristic characteristic)
2323
// The 'Id' characteristic is a special case:
2424
// here we just print 'Job'
2525
if (characteristic.Id == "Id")
26-
ColumnName = "Job";
26+
ColumnName = Column.Job;
2727
}
2828

2929
public string Id { get; }

src/BenchmarkDotNet/Columns/LogicalGroupColumn.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class LogicalGroupColumn : IColumn
99
[PublicAPI] public static readonly IColumn Default = new LogicalGroupColumn();
1010

1111
public string Id => nameof(LogicalGroupColumn);
12-
public string ColumnName => "LogicalGroup";
12+
public string ColumnName => Column.LogicalGroup;
1313

1414
public string GetValue(Summary summary, BenchmarkCase benchmarkCase) => summary.GetLogicalGroupKey(benchmarkCase);
1515
public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase);

src/BenchmarkDotNet/Columns/RankColumn.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class RankColumn : IColumn
1818
[PublicAPI] public static readonly IColumn Stars = new RankColumn(NumeralSystem.Stars);
1919

2020
public string Id => nameof(RankColumn) + "." + numeralSystem;
21-
public string ColumnName => "Rank";
21+
public string ColumnName => Column.Rank;
2222

2323
public string GetValue(Summary summary, BenchmarkCase benchmarkCase)
2424
{

src/BenchmarkDotNet/Columns/StatisticColumn.cs

+25-25
Original file line numberDiff line numberDiff line change
@@ -28,59 +28,59 @@ private enum Priority
2828
Additional
2929
}
3030

31-
public static readonly IStatisticColumn Mean = new StatisticColumn("Mean", "Arithmetic mean of all measurements",
31+
public static readonly IStatisticColumn Mean = new StatisticColumn(Column.Mean, "Arithmetic mean of all measurements",
3232
s => s.Mean, Priority.Main);
3333

34-
public static readonly IColumn StdErr = new StatisticColumn("StdErr", "Standard error of all measurements",
34+
public static readonly IColumn StdErr = new StatisticColumn(Column.StdErr, "Standard error of all measurements",
3535
s => s.StandardError, Priority.Main, parentColumn: Mean);
3636

37-
public static readonly IColumn StdDev = new StatisticColumn("StdDev", "Standard deviation of all measurements",
37+
public static readonly IColumn StdDev = new StatisticColumn(Column.StdDev, "Standard deviation of all measurements",
3838
s => s.StandardDeviation, Priority.Main, parentColumn: Mean);
3939

40-
public static readonly IColumn Error = new StatisticColumn("Error", "Half of 99.9% confidence interval",
40+
public static readonly IColumn Error = new StatisticColumn(Column.Error, "Half of 99.9% confidence interval",
4141
s => new ConfidenceInterval(s.Mean, s.StandardError, s.N, ConfidenceLevel.L999).Margin, Priority.Main, parentColumn: Mean);
4242

43-
public static readonly IColumn OperationsPerSecond = new StatisticColumn("Op/s", "Operation per second",
43+
public static readonly IColumn OperationsPerSecond = new StatisticColumn(Column.OperationPerSecond, "Operation per second",
4444
s => 1.0 * 1000 * 1000 * 1000 / s.Mean, Priority.Additional, UnitType.Dimensionless);
4545

46-
public static readonly IColumn Min = new StatisticColumn("Min", "Minimum",
46+
public static readonly IColumn Min = new StatisticColumn(Column.Min, "Minimum",
4747
s => s.Min, Priority.Quartile);
4848

49-
public static readonly IColumn Q1 = new StatisticColumn("Q1", "Quartile 1 (25th percentile)",
49+
public static readonly IColumn Q1 = new StatisticColumn(Column.Q1, "Quartile 1 (25th percentile)",
5050
s => s.Q1, Priority.Quartile);
5151

52-
public static readonly IColumn Median = new StatisticColumn("Median", "Value separating the higher half of all measurements (50th percentile)",
52+
public static readonly IColumn Median = new StatisticColumn(Column.Median, "Value separating the higher half of all measurements (50th percentile)",
5353
s => s.Median, Priority.Quartile);
5454

55-
public static readonly IColumn Q3 = new StatisticColumn("Q3", "Quartile 3 (75th percentile)",
55+
public static readonly IColumn Q3 = new StatisticColumn(Column.Q3, "Quartile 3 (75th percentile)",
5656
s => s.Q3, Priority.Quartile);
5757

58-
public static readonly IColumn Max = new StatisticColumn("Max", "Maximum", s => s.Max, Priority.Quartile);
58+
public static readonly IColumn Max = new StatisticColumn(Column.Max, "Maximum", s => s.Max, Priority.Quartile);
5959

60-
public static readonly IColumn Skewness = new StatisticColumn("Skewness", "Measure of the asymmetry (third standardized moment)",
60+
public static readonly IColumn Skewness = new StatisticColumn(Column.Skewness, "Measure of the asymmetry (third standardized moment)",
6161
s => s.Skewness, Priority.Additional, UnitType.Dimensionless);
6262

63-
public static readonly IColumn Kurtosis = new StatisticColumn("Kurtosis", "Measure of the tailedness ( fourth standardized moment)",
63+
public static readonly IColumn Kurtosis = new StatisticColumn(Column.Kurtosis, "Measure of the tailedness ( fourth standardized moment)",
6464
s => s.Kurtosis, Priority.Additional, UnitType.Dimensionless);
6565

6666
/// <summary>
6767
/// See http://www.brendangregg.com/FrequencyTrails/modes.html
6868
/// </summary>
69-
public static readonly IColumn MValue = new StatisticColumn("MValue", "Modal value, see http://www.brendangregg.com/FrequencyTrails/modes.html",
69+
public static readonly IColumn MValue = new StatisticColumn(Column.MValue, "Modal value, see http://www.brendangregg.com/FrequencyTrails/modes.html",
7070
s => MValueCalculator.Calculate(s.OriginalValues), Priority.Additional, UnitType.Dimensionless);
7171

72-
public static readonly IColumn Iterations = new StatisticColumn("Iterations", "Number of target iterations",
72+
public static readonly IColumn Iterations = new StatisticColumn(Column.Iterations, "Number of target iterations",
7373
s => s.N, Priority.Additional, UnitType.Dimensionless);
7474

75-
public static readonly IColumn P0 = CreatePercentileColumn(0, s => s.Percentiles.P0);
76-
public static readonly IColumn P25 = CreatePercentileColumn(25, s => s.Percentiles.P25);
77-
public static readonly IColumn P50 = CreatePercentileColumn(50, s => s.Percentiles.P50);
78-
public static readonly IColumn P67 = CreatePercentileColumn(67, s => s.Percentiles.P67);
79-
public static readonly IColumn P80 = CreatePercentileColumn(80, s => s.Percentiles.P80);
80-
public static readonly IColumn P85 = CreatePercentileColumn(85, s => s.Percentiles.P85);
81-
public static readonly IColumn P90 = CreatePercentileColumn(90, s => s.Percentiles.P90);
82-
public static readonly IColumn P95 = CreatePercentileColumn(95, s => s.Percentiles.P95);
83-
public static readonly IColumn P100 = CreatePercentileColumn(100, s => s.Percentiles.P100);
75+
public static readonly IColumn P0 = CreatePercentileColumn(0, Column.P0, s => s.Percentiles.P0);
76+
public static readonly IColumn P25 = CreatePercentileColumn(25, Column.P25, s => s.Percentiles.P25);
77+
public static readonly IColumn P50 = CreatePercentileColumn(50, Column.P50, s => s.Percentiles.P50);
78+
public static readonly IColumn P67 = CreatePercentileColumn(67, Column.P67, s => s.Percentiles.P67);
79+
public static readonly IColumn P80 = CreatePercentileColumn(80, Column.P80, s => s.Percentiles.P80);
80+
public static readonly IColumn P85 = CreatePercentileColumn(85, Column.P85, s => s.Percentiles.P85);
81+
public static readonly IColumn P90 = CreatePercentileColumn(90, Column.P90, s => s.Percentiles.P90);
82+
public static readonly IColumn P95 = CreatePercentileColumn(95, Column.P95, s => s.Percentiles.P95);
83+
public static readonly IColumn P100 = CreatePercentileColumn(100, Column.P100, s => s.Percentiles.P100);
8484

8585
[PublicAPI]
8686
public static IColumn CiLower(ConfidenceLevel level) => new StatisticColumn(
@@ -165,7 +165,7 @@ private string Format(Summary summary, ImmutableConfig config, Statistics statis
165165

166166
public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false;
167167

168-
private static IColumn CreatePercentileColumn(int percentiles, Func<Statistics, double> calc) => new StatisticColumn(
169-
"P" + percentiles, "Percentile " + percentiles, calc, Priority.Percentiles);
168+
private static IColumn CreatePercentileColumn(int percentiles, string columnName, Func<Statistics, double> calc) => new StatisticColumn(
169+
columnName, "Percentile " + percentiles, calc, Priority.Percentiles);
170170
}
171171
}

0 commit comments

Comments
 (0)