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 all 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
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)));
}
}
}
27 changes: 20 additions & 7 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 class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new ExceptionsFrequencyMetricDescriptor();
public ExceptionDiagnoserConfig Config { get; }
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;
}
}
}
}
}
42 changes: 34 additions & 8 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 @@ -50,10 +52,15 @@ public IEnumerable<ValidationError> Validate(ValidationParameters validationPara
}
}

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

private ThreadingDiagnoserConfig Config { get; }
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,26 @@ 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 class LockContentionCountMetricDescriptor : IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new LockContentionCountMetricDescriptor();

private ThreadingDiagnoserConfig Config { get; }

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 +97,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; }
}
}
Loading
Loading