Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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, false)]
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)));
}
}
}
26 changes: 19 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,15 +35,23 @@ public void Handle(HostSignal signal, DiagnoserActionParameters parameters) { }

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

if (descriptor is ExceptionsFrequencyMetricDescriptor concreteDescriptor)
{
concreteDescriptor.SetConfiguration(Config);
}

yield return new Metric(descriptor, results.ExceptionFrequency);
}

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

private class ExceptionsFrequencyMetricDescriptor : IMetricDescriptor
private class ExceptionsFrequencyMetricDescriptor: MetricDescriptorConfigurationHandler<ExceptionDiagnoserConfig>, IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new ExceptionsFrequencyMetricDescriptor();
public static IMetricDescriptor Instance
=> MetricDescriptorSingletonBase<ExceptionsFrequencyMetricDescriptor>.Instance;

// IMetricDescriptor properties
public string Id => "ExceptionFrequency";
public string DisplayName => Column.Exceptions;
public string Legend => "Exceptions thrown per single operation";
Expand All @@ -49,7 +60,8 @@ 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) => Config.DisplayExceptionsIfZeroValue || metric.Value > 0;
}
}
}
36 changes: 26 additions & 10 deletions src/BenchmarkDotNet/Diagnosers/ThreadingDiagnoser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
using Perfolizer.Json;

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 +35,20 @@ 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);
var completedWorkItemCountDescriptor = CompletedWorkItemCountMetricDescriptor.Instance;
if (completedWorkItemCountDescriptor is CompletedWorkItemCountMetricDescriptor concreteCompletedWorkItemCountDescriptor)
{
concreteCompletedWorkItemCountDescriptor.SetConfiguration(Config);
}
yield return new Metric(completedWorkItemCountDescriptor, results.ThreadingStats.CompletedWorkItemCount / (double)results.ThreadingStats.TotalOperations);


var lockContentionCountDescriptor = LockContentionCountMetricDescriptor.Instance;
if (lockContentionCountDescriptor is LockContentionCountMetricDescriptor concreteLockContentionCountDescriptor)
{
concreteLockContentionCountDescriptor.SetConfiguration(Config);
}
yield return new Metric(lockContentionCountDescriptor, results.ThreadingStats.LockContentionCount / (double)results.ThreadingStats.TotalOperations);
}

public IEnumerable<ValidationError> Validate(ValidationParameters validationParameters)
Expand All @@ -50,9 +64,10 @@ public IEnumerable<ValidationError> Validate(ValidationParameters validationPara
}
}

private class CompletedWorkItemCountMetricDescriptor : IMetricDescriptor
private class CompletedWorkItemCountMetricDescriptor : MetricDescriptorConfigurationHandler<ThreadingDiagnoserConfig>, IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new CompletedWorkItemCountMetricDescriptor();
public static IMetricDescriptor Instance
=> MetricDescriptorSingletonBase<CompletedWorkItemCountMetricDescriptor>.Instance;

public string Id => "CompletedWorkItemCount";
public string DisplayName => Column.CompletedWorkItems;
Expand All @@ -62,12 +77,13 @@ 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) => Config.DisplayCompletedWorkItemCountWhenZero || metric.Value > 0;
}

private class LockContentionCountMetricDescriptor : IMetricDescriptor
private class LockContentionCountMetricDescriptor : MetricDescriptorConfigurationHandler<ThreadingDiagnoserConfig>, IMetricDescriptor
{
internal static readonly IMetricDescriptor Instance = new LockContentionCountMetricDescriptor();
public static IMetricDescriptor Instance
=> MetricDescriptorSingletonBase<LockContentionCountMetricDescriptor>.Instance;

public string Id => "LockContentionCount";
public string DisplayName => Column.LockContentions;
Expand All @@ -77,7 +93,7 @@ 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) => 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; }
}
}
36 changes: 36 additions & 0 deletions src/BenchmarkDotNet/Reports/Metric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,42 @@ public interface IMetricDescriptor
[PublicAPI] bool GetIsAvailable(Metric metric);
}

public interface IMetricDescriptorConfigurationHandler<TConfig>
{
void SetConfiguration(TConfig config);
}

public class MetricDescriptorConfigurationHandler<TConfig> : IMetricDescriptorConfigurationHandler<TConfig>
{
private TConfig _config;

protected TConfig Config => _config;

public virtual void SetConfiguration(TConfig config)
{
_config = config;
}
}

public abstract class MetricDescriptorSingletonBase<T> where T : class, new()
{
private static T _instance;

protected MetricDescriptorSingletonBase() { }

public static T Instance
{
get
{
if (_instance == null)
{
_instance = new T();
}
return _instance;
}
}
}

public class MetricDescriptorEqualityComparer : EqualityComparer<IMetricDescriptor>
{
public static readonly EqualityComparer<IMetricDescriptor> Instance = new MetricDescriptorEqualityComparer();
Expand Down