Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Add ability to automatically hide metric columns if value is not set #2673

Merged
merged 15 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BenchmarkDotNet.Samples
{
[ExceptionDiagnoser]
public class IntroExceptionDiagnoserAfterHideColumns
{
[Benchmark]
public void Benchmark()
{
Thread.Sleep(1);
}

[Benchmark] public void NoThrow() { }
[Benchmark]
public void Throw()
{
try { throw new Exception(); } catch { }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BenchmarkDotNet.Samples
{
[ThreadingDiagnoser(false, true)]
public class IntroThreadingDiagnoserAfterHideColumns
{
[Benchmark]
public void Benchmark()
{
Thread.Sleep(1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public class ExceptionDiagnoserAttribute : Attribute, IConfigSource
{
public IConfig Config { get; }

public ExceptionDiagnoserAttribute() => Config = ManualConfig.CreateEmpty().AddDiagnoser(ExceptionDiagnoser.Default);
/// <param name="displayExceptionsIfZeroValue">Display Exceptions column. True by default.</param>
public ExceptionDiagnoserAttribute(bool displayExceptionsIfZeroValue = true)
{
Config = ManualConfig.CreateEmpty().AddDiagnoser(new ExceptionDiagnoser(new ExceptionDiagnoserConfig(displayExceptionsIfZeroValue)));
}
}
}
20 changes: 20 additions & 0 deletions src/BenchmarkDotNet/Attributes/ExceptionDiagnoserConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Text;

namespace BenchmarkDotNet.Attributes
{
public class ExceptionDiagnoserConfig
{
/// <param name="displayExceptionsIfZeroValue">Determines whether the Exceptions column is displayed when its value is not calculated. True by default.</param>

[PublicAPI]
public ExceptionDiagnoserConfig(bool displayExceptionsIfZeroValue = true)
{
DisplayExceptionsIfZeroValue = displayExceptionsIfZeroValue;
}

public bool DisplayExceptionsIfZeroValue { get; }
}
}
12 changes: 11 additions & 1 deletion src/BenchmarkDotNet/Attributes/ThreadingDiagnoserAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using JetBrains.Annotations;

namespace BenchmarkDotNet.Attributes
{
Expand All @@ -9,6 +10,15 @@ public class ThreadingDiagnoserAttribute : Attribute, IConfigSource
{
public IConfig Config { get; }

public ThreadingDiagnoserAttribute() => Config = ManualConfig.CreateEmpty().AddDiagnoser(ThreadingDiagnoser.Default);
//public ThreadingDiagnoserAttribute() => Config = ManualConfig.CreateEmpty().AddDiagnoser(ThreadingDiagnoser.Default);

/// <param name="displayLockContentionWhenZero">Display configuration for 'LockContentionCount' when it is empty. True (displayed) by default.</param>
/// <param name="displayCompletedWorkItemCountWhenZero">Display configuration for 'CompletedWorkItemCount' when it is empty. True (displayed) by default.</param>

[PublicAPI]
public ThreadingDiagnoserAttribute(bool displayLockContentionWhenZero = true, bool displayCompletedWorkItemCountWhenZero = true)
{
Config = ManualConfig.CreateEmpty().AddDiagnoser(new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayLockContentionWhenZero, displayCompletedWorkItemCountWhenZero)));
}
}
}
25 changes: 19 additions & 6 deletions src/BenchmarkDotNet/Diagnosers/ExceptionDiagnoser.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Engines;
using BenchmarkDotNet.Exporters;
Expand All @@ -14,9 +15,11 @@ namespace BenchmarkDotNet.Diagnosers
{
public class ExceptionDiagnoser : IDiagnoser
{
public static readonly ExceptionDiagnoser Default = new ExceptionDiagnoser();
public static readonly ExceptionDiagnoser Default = new ExceptionDiagnoser(new ExceptionDiagnoserConfig(displayExceptionsIfZeroValue: true));

private ExceptionDiagnoser() { }
public ExceptionDiagnoser(ExceptionDiagnoserConfig config) => Config = config;

public ExceptionDiagnoserConfig Config { get; }

public IEnumerable<string> Ids => new[] { nameof(ExceptionDiagnoser) };

Expand All @@ -32,14 +35,18 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { }

public IEnumerable<Metric> ProcessResults(DiagnoserResults results)
{
yield return new Metric(ExceptionsFrequencyMetricDescriptor.Instance, results.ExceptionFrequency);
yield return new Metric(new ExceptionsFrequencyMetricDescriptor(Config), results.ExceptionFrequency);
}

public IEnumerable<ValidationError> Validate(ValidationParameters validationParameters) => Enumerable.Empty<ValidationError>();

private class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new ExceptionsFrequencyMetricDescriptor();
private readonly ExceptionDiagnoserConfig? _config;
public ExceptionsFrequencyMetricDescriptor(ExceptionDiagnoserConfig config = null)
{
_config = config;
}

public string Id => "ExceptionFrequency";
public string DisplayName => Column.Exceptions;
Expand All @@ -49,7 +56,13 @@ private class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric) => true;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayExceptionsIfZeroValue || metric.Value > 0;
}
}
}
}
}
37 changes: 31 additions & 6 deletions src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ namespace BenchmarkDotNet.Diagnosers
{
public class ThreadingDiagnoser : IDiagnoser
{
public static readonly ThreadingDiagnoser Default = new ThreadingDiagnoser();
public static readonly ThreadingDiagnoser Default = new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayCompletedWorkItemCountWhenZero: true, displayLockContentionWhenZero: true));

private ThreadingDiagnoser() { }
public ThreadingDiagnoser(ThreadingDiagnoserConfig config) => Config = config;
public ThreadingDiagnoserConfig Config { get; }

public IEnumerable<string> Ids => new[] { nameof(ThreadingDiagnoser) };

Expand All @@ -33,8 +34,9 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { }

public IEnumerable<Metric> ProcessResults(DiagnoserResults results)
{
yield return new Metric(CompletedWorkItemCountMetricDescriptor.Instance, results.ThreadingStats.CompletedWorkItemCount / (double)results.ThreadingStats.TotalOperations);
yield return new Metric(LockContentionCountMetricDescriptor.Instance, results.ThreadingStats.LockContentionCount / (double)results.ThreadingStats.TotalOperations);

yield return new Metric(new CompletedWorkItemCountMetricDescriptor(Config), results.ThreadingStats.CompletedWorkItemCount / (double)results.ThreadingStats.TotalOperations);
yield return new Metric(new LockContentionCountMetricDescriptor(Config), results.ThreadingStats.LockContentionCount / (double)results.ThreadingStats.TotalOperations);
}

public IEnumerable<ValidationError> Validate(ValidationParameters validationParameters)
Expand All @@ -54,6 +56,11 @@ private class CompletedWorkItemCountMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new CompletedWorkItemCountMetricDescriptor();

private readonly ThreadingDiagnoserConfig? _config;
public CompletedWorkItemCountMetricDescriptor(ThreadingDiagnoserConfig config = null)
{
_config = config;
}
public string Id => "CompletedWorkItemCount";
public string DisplayName => Column.CompletedWorkItems;
public string Legend => "The number of work items that have been processed in ThreadPool (per single operation)";
Expand All @@ -62,13 +69,25 @@ private class CompletedWorkItemCountMetricDescriptor : IMetricDescriptor
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric) => true;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayCompletedWorkItemCountWhenZero || metric.Value > 0;
}
}

private class LockContentionCountMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new LockContentionCountMetricDescriptor();

private readonly ThreadingDiagnoserConfig? _config;
public LockContentionCountMetricDescriptor(ThreadingDiagnoserConfig config = null)
{
_config = config;
}

public string Id => "LockContentionCount";
public string DisplayName => Column.LockContentions;
public string Legend => "The number of times there was contention upon trying to take a Monitor's lock (per single operation)";
Expand All @@ -77,7 +96,13 @@ private class LockContentionCountMetricDescriptor : IMetricDescriptor
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric) => true;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayLockContentionWhenZero || metric.Value > 0;
}
}
}
}
23 changes: 23 additions & 0 deletions src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoserConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Text;

namespace BenchmarkDotNet.Diagnosers
{
public class ThreadingDiagnoserConfig
{
/// <param name="displayLockContentionWhenZero">Display configuration for 'LockContentionCount' when it is empty. True (displayed) by default.</param>
/// <param name="displayCompletedWorkItemCountWhenZero">Display configuration for 'CompletedWorkItemCount' when it is empty. True (displayed) by default.</param>

[PublicAPI]
public ThreadingDiagnoserConfig(bool displayLockContentionWhenZero = true, bool displayCompletedWorkItemCountWhenZero = true)
{
DisplayLockContentionWhenZero = displayLockContentionWhenZero;
DisplayCompletedWorkItemCountWhenZero = displayCompletedWorkItemCountWhenZero;
}

public bool DisplayLockContentionWhenZero { get; }
public bool DisplayCompletedWorkItemCountWhenZero { get; }
}
}
AvishaiDotan marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Reports;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BenchmarkDotNet.Tests.Reports
{
public class DescriptorWithConfigurations
{
public class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
{
private readonly ExceptionDiagnoserConfig? _config;
public ExceptionsFrequencyMetricDescriptor(ExceptionDiagnoserConfig config = null)
{
_config = config;
}

public string Id => "ExceptionFrequency";
public string DisplayName => Column.Exceptions;
public string Legend => "Exceptions thrown per single operation";
public string NumberFormat => "#0.0000";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayExceptionsIfZeroValue || metric.Value > 0;
}
}

public class CompletedWorkItemCountMetricDescriptor : IMetricDescriptor
{
private readonly ThreadingDiagnoserConfig? _config;
public CompletedWorkItemCountMetricDescriptor(ThreadingDiagnoserConfig config = null)
{
_config = config;
}
public string Id => "CompletedWorkItemCount";
public string DisplayName => Column.CompletedWorkItems;
public string Legend => "The number of work items that have been processed in ThreadPool (per single operation)";
public string NumberFormat => "#0.0000";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayCompletedWorkItemCountWhenZero || metric.Value > 0;
}
}

public class LockContentionCountMetricDescriptor : IMetricDescriptor
{
private readonly ThreadingDiagnoserConfig? _config;
public LockContentionCountMetricDescriptor(ThreadingDiagnoserConfig config = null)
{
_config = config;
}

public string Id => "LockContentionCount";
public string DisplayName => Column.LockContentions;
public string Legend => "The number of times there was contention upon trying to take a Monitor's lock (per single operation)";
public string NumberFormat => "#0.0000";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public bool TheGreaterTheBetter => false;
public int PriorityInCategory => 0;
public bool GetIsAvailable(Metric metric)
{
if (_config == null)
return metric.Value > 0;
else
return _config.DisplayLockContentionWhenZero || metric.Value > 0;
}
}
}
}
Loading
Loading