BenchmarkDotNet icon indicating copy to clipboard operation
BenchmarkDotNet copied to clipboard

[Bug] `InvalidOperationException` thrown on some conditions when using `BenchmarkDotNetDiagnosers`

Open filzrev opened this issue 5 months ago • 1 comments

When running BenchmarkDotNet.Samples project with following command.

dotnet run -c Release --framework net8.0 --anyCategories Dummy

benchmark project throws following exception.

Unhandled exception. System.InvalidOperationException: Tool CPUUsageTool is already added.

Stacktrace
Unhandled exception. System.InvalidOperationException: Tool CPUUsageTool is already added.
   at Microsoft.VSDiagnostics.VSDiagnosticsDiagnoser..ctor(IDiagnosticsTool tool, String outputFileName, Boolean openDiagsessionInVS, Func`2 validationFunction)
   at Microsoft.VSDiagnostics.VSDiagnosticsToolAttribute.get_Config()
   at Microsoft.VSDiagnostics.CPUUsageDiagnoserAttribute.get_Config()
   at BenchmarkDotNet.Running.BenchmarkConverter.GetFullTypeConfig(Type type, IConfig config) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\BenchmarkConverter.cs:line 94
   at BenchmarkDotNet.Running.BenchmarkConverter.MethodsToBenchmarksWithFullConfig(Type type, MethodInfo[] benchmarkMethods, IConfig config) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\BenchmarkConverter.cs:line 46
   at BenchmarkDotNet.Running.BenchmarkConverter.TypeToBenchmarks(Type type, IConfig config) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\BenchmarkConverter.cs:line 29
   at BenchmarkDotNet.Running.TypeFilter.<>c__DisplayClass1_0.<Filter>b__0(Type type) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\TypeFilter.cs:line 68
   at System.Linq.Enumerable.SelectListIterator`2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator`1.ToArray()
   at BenchmarkDotNet.Running.TypeFilter.Filter(IConfig effectiveConfig, IEnumerable`1 types) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\TypeFilter.cs:line 67
   at BenchmarkDotNet.ConsoleArguments.CorrectionsSuggester..ctor(IReadOnlyList`1 types) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\ConsoleArguments\CorrectionsSuggester.cs:line 20
   at BenchmarkDotNet.Running.UserInteraction.PrintWrongFilterInfo(IReadOnlyList`1 allTypes, ILogger logger, String[] userFilters) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\UserInteraction.cs:line 57
   at BenchmarkDotNet.Running.BenchmarkSwitcher.RunWithDirtyAssemblyResolveHelper(String[] args, IConfig config, Boolean askUserForInput) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\BenchmarkSwitcher.cs:line 138
   at BenchmarkDotNet.Running.BenchmarkSwitcher.Run(String[] args, IConfig config) in C:\Projects\GitHub\thirdparty\BenchmarkDotNet\src\BenchmarkDotNet\Running\BenchmarkSwitcher.cs:line 84
   at BenchmarkDotNet.Samples.Program.Main(String[] args) in C:\Projects\BenchmarkDotNet\samples\BenchmarkDotNet.Samples\Program.cs:line 7

Background When specified benchmark category is not found. BenchmarkDotNet try to call PrintWrongFilterInfo with CorrectionsSuggester.cs. And it internally call VSDiagnosticsDiagnoser's ctor and throw exceptions.

filzrev avatar Jun 08 '25 08:06 filzrev

Same issue can be reproduced when specifying [CPUUsageDiagnoser] attribute on multiple benchmarks. And it can also happens with multiple constructor calls.

var diagnoser1 = new CPUUsageDiagnoser(cpuSampleRate: 0);
var diagnoser2 = new CPUUsageDiagnoser(cpuSampleRate: 50);

I thought it seems to be fixed on [Microsoft.VisualStudio.DiagnosticsHub.BenchmarkDotNetDiagnosers] side.

filzrev avatar Jun 09 '25 03:06 filzrev