Skip to content

Commit

Permalink
Feature Request: Add ability to automatically hide metric columns if …
Browse files Browse the repository at this point in the history
…value is not set (#2673)

* Hide the columns described in the issue & add samples for test

* Polish sample names

* remove irrelevant commit from pr

* remove leftovers

* Added some helper classes to inject the configuration into the descriptor handler.
Added attribute parameters instead of checking the metric.Value directly.

* change the injection of configuration

* add tests

* return the singleton pattern

* change private descriptors into internal
Implement descriptorConfigInjector base class to keep the code dry

* remove DescriptorConfigInjector

* remove samples
  • Loading branch information
AvishaiDotan authored Jan 2, 2025
1 parent cd50f7b commit cac4f6e
Show file tree
Hide file tree
Showing 7 changed files with 421 additions and 17 deletions.
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

0 comments on commit cac4f6e

Please sign in to comment.