From 2c95efe8daa01f8c2772774ab793ddb118ed7326 Mon Sep 17 00:00:00 2001
From: filzrev <103790468+filzrev@users.noreply.github.com>
Date: Mon, 5 Jan 2026 12:48:44 +0900
Subject: [PATCH] chore: add analyzer debug settings and sandbox project
---
BenchmarkDotNet.slnx | 1 +
samples/BenchmarkDotNet.Samples.Sandbox.slnf | 11 ++
.../.runsettings | 9 ++
.../BenchmarkDotNet.Samples.Sandbox.csproj | 38 ++++++
.../Configs/BaseBenchmarkConfig.cs | 121 ++++++++++++++++++
.../Configs/DebugBenchmarkConfig.cs | 28 ++++
.../Configs/DebugInProcessBenchmarkConfig.cs | 40 ++++++
.../Configs/DefaultBenchmarkConfig.cs | 22 ++++
.../TargetFrameworksBenchmarkConfig.cs | 50 ++++++++
.../ExtensionMethods/SummariesExtensions.cs | 23 ++++
.../Filters/TargetFrameworkFilter.cs | 47 +++++++
.../Helpers/AssemblyConfigProvider.cs | 35 +++++
.../Benchmarks/DefaultBenchmarks.cs | 42 ++++++
.../Constants.cs | 25 ++++
.../Program.cs | 51 ++++++++
.../Properties/PropertyInfo.cs | 3 +
.../Properties/launchSettings.json | 37 ++++++
.../BenchmarkDotNet.Analyzers.csproj | 2 +
.../Properties/launchSettings.json | 8 ++
.../Fixtures/AnalyzerTestFixture.cs | 1 +
20 files changed, 594 insertions(+)
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox.slnf
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/.runsettings
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet.Samples.Sandbox.csproj
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/BaseBenchmarkConfig.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugBenchmarkConfig.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugInProcessBenchmarkConfig.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DefaultBenchmarkConfig.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/TargetFrameworksBenchmarkConfig.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/ExtensionMethods/SummariesExtensions.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Filters/TargetFrameworkFilter.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Helpers/AssemblyConfigProvider.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/Benchmarks/DefaultBenchmarks.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/Constants.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/Program.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/Properties/PropertyInfo.cs
create mode 100644 samples/BenchmarkDotNet.Samples.Sandbox/Properties/launchSettings.json
create mode 100644 src/BenchmarkDotNet.Analyzers/Properties/launchSettings.json
diff --git a/BenchmarkDotNet.slnx b/BenchmarkDotNet.slnx
index 1d2b3755ad..ffadc5d113 100644
--- a/BenchmarkDotNet.slnx
+++ b/BenchmarkDotNet.slnx
@@ -6,6 +6,7 @@
+
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox.slnf b/samples/BenchmarkDotNet.Samples.Sandbox.slnf
new file mode 100644
index 0000000000..f8357fd4a2
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox.slnf
@@ -0,0 +1,11 @@
+{
+ "solution": {
+ "path": "..\\BenchmarkDotNet.slnx",
+ "projects": [
+ "samples\\BenchmarkDotNet.Samples.Sandbox\\BenchmarkDotNet.Samples.Sandbox.csproj",
+ "src\\BenchmarkDotNet.Analyzers\\BenchmarkDotNet.Analyzers.csproj",
+ "src\\BenchmarkDotNet.TestAdapter\\BenchmarkDotNet.TestAdapter.csproj",
+ "src\\BenchmarkDotNet\\BenchmarkDotNet.csproj"
+ ]
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/.runsettings b/samples/BenchmarkDotNet.Samples.Sandbox/.runsettings
new file mode 100644
index 0000000000..4c125cf1f5
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/.runsettings
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet.Samples.Sandbox.csproj b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet.Samples.Sandbox.csproj
new file mode 100644
index 0000000000..b6b9b4ac31
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet.Samples.Sandbox.csproj
@@ -0,0 +1,38 @@
+
+
+
+
+ Exe
+ net8.0;net9.0;net10.0
+ enable
+
+
+
+ $(TargetFrameworks);net48
+
+
+
+
+ false
+
+ false
+
+ $(MSBuildProjectDirectory)\.runsettings
+
+
+
+
+
+ Analyzer
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/BaseBenchmarkConfig.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/BaseBenchmarkConfig.cs
new file mode 100644
index 0000000000..43925d9bfd
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/BaseBenchmarkConfig.cs
@@ -0,0 +1,121 @@
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Columns;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Diagnosers;
+using BenchmarkDotNet.Exporters;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Loggers;
+using BenchmarkDotNet.Order;
+using BenchmarkDotNet.Reports;
+using Perfolizer.Horology;
+
+namespace BenchmarkDotNet;
+
+public class BaseBenchmarkConfig : ManualConfig
+{
+ public BaseBenchmarkConfig()
+ {
+ WithSummaryStyle(SummaryStyle.Default.WithMaxParameterColumnWidth(40)); // Default: 20 chars
+ WithBuildTimeout(TimeSpan.FromMinutes(10)); // Default: 120 seconds
+
+ WithOrderer(new DefaultOrderer());
+ WithUnionRule(ConfigUnionRule.Union);
+ WithArtifactsPath(DefaultConfig.Instance.ArtifactsPath!);
+
+#if DEBUG
+ // Allow benchmarks for debug build.
+ WithOptions(ConfigOptions.DisableOptimizationsValidator);
+#endif
+
+ // Enable following settings for debugging
+ // WithOptions(ConfigOptions.StopOnFirstError);
+ // WithOptions(ConfigOptions.KeepBenchmarkFiles);
+ // WithOptions(ConfigOptions.GenerateMSBuildBinLog);
+ }
+
+ // Use ShortRun based settings (LaunchCount=1 IterationCount=3 WarmupCount = 3)
+ // And use RecommendedConfig setting that used by `dotnet/performance` repository.
+ // https://github.com/dotnet/performance/blob/main/src/harness/BenchmarkDotNet.Extensions/RecommendedConfig.cs
+ protected virtual Job GetBaseJobConfig() =>
+ Job.Default
+ .WithLaunchCount(1)
+ .WithWarmupCount(3)
+ .WithIterationTime(TimeInterval.FromMilliseconds(250)) // Default: 500 [ms]
+ .WithMinIterationCount(15) // Default: 15
+ .WithMaxIterationCount(20); // Default: 100
+
+ ///
+ /// Add configurations.
+ ///
+ protected void AddConfigurations()
+ {
+ AddAnalyzers();
+ AddColumnHidingRules();
+ AddColumnProviders();
+ AddDiagnosers();
+ AddEventProcessors();
+ AddExporters();
+ AddFilters();
+ AddHardwareCounters();
+ AddLoggers();
+ AddLogicalGroupRules();
+ AddValidators();
+ }
+
+ protected virtual void AddAnalyzers()
+ {
+ AddAnalyser(DefaultConfig.Instance.GetAnalysers().ToArray());
+ }
+
+ protected virtual void AddColumnHidingRules()
+ {
+ }
+
+ protected virtual void AddColumnProviders()
+ {
+ AddColumnProvider(DefaultColumnProviders.Instance);
+ }
+
+ protected virtual void AddDiagnosers()
+ {
+ AddDiagnoser(MemoryDiagnoser.Default);
+ AddDiagnoser(new ExceptionDiagnoser(new ExceptionDiagnoserConfig(displayExceptionsIfZeroValue: false)));
+
+#if NETCOREAPP3_0_OR_GREATER
+ AddDiagnoser(new ThreadingDiagnoser(new ThreadingDiagnoserConfig(displayCompletedWorkItemCountWhenZero: false, displayLockContentionWhenZero: false)));
+#endif
+ }
+
+ protected virtual void AddExporters()
+ {
+ // Use ConsoleMarkdownExporter to disable group higligting with `**`.
+ AddExporter(MarkdownExporter.Console);
+ }
+
+ protected virtual void AddEventProcessors()
+ {
+ }
+
+ protected virtual void AddFilters()
+ {
+ AddFilter(TargetFrameworkFilter.Instance);
+ }
+
+ protected virtual void AddHardwareCounters()
+ {
+ }
+
+ protected virtual void AddLoggers()
+ {
+ AddLogger(ConsoleLogger.Default);
+ }
+
+ protected virtual void AddLogicalGroupRules()
+ {
+ }
+
+ protected virtual void AddValidators()
+ {
+ AddValidator(DefaultConfig.Instance.GetValidators().ToArray());
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugBenchmarkConfig.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugBenchmarkConfig.cs
new file mode 100644
index 0000000000..7b0669687c
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugBenchmarkConfig.cs
@@ -0,0 +1,28 @@
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Engines;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Toolchains.InProcess.Emit;
+using System.Runtime.InteropServices;
+
+namespace BenchmarkDotNet;
+
+public class DebugBenchmarkConfig : BaseBenchmarkConfig
+{
+ public DebugBenchmarkConfig()
+ {
+ // Configure base job config
+ var baseJobConfig = GetBaseJobConfig();
+
+ // Add benchmark job.
+ AddJob(baseJobConfig.WithCustomBuildConfiguration("Debug")
+ .WithWarmupCount(1)
+ .WithStrategy(RunStrategy.Monitoring)
+ .WithId($"Debug({RuntimeInformation.FrameworkDescription})"));
+
+ // Set DebugConfig comatible option
+ WithOptions(ConfigOptions.KeepBenchmarkFiles);
+
+ // Configure additional settings.
+ AddConfigurations();
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugInProcessBenchmarkConfig.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugInProcessBenchmarkConfig.cs
new file mode 100644
index 0000000000..3447788af0
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DebugInProcessBenchmarkConfig.cs
@@ -0,0 +1,40 @@
+using BenchmarkDotNet.Analysers;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Engines;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Toolchains.InProcess.Emit;
+using System.Runtime.InteropServices;
+
+namespace BenchmarkDotNet;
+
+public class DebugInProcessBenchmarkConfig : BaseBenchmarkConfig
+{
+ public DebugInProcessBenchmarkConfig() : base()
+ {
+ // Configure base job config
+ var baseJobConfig = GetBaseJobConfig();
+
+ // Add benchmark job.
+ AddJob(baseJobConfig.WithToolchain(InProcessEmitToolchain.Default)
+ .WithWarmupCount(1)
+ .WithStrategy(RunStrategy.Monitoring)
+ .WithId($"DebugInProcess({RuntimeInformation.FrameworkDescription})"));
+
+ // Set DebugConfig comatible option
+ WithOptions(ConfigOptions.KeepBenchmarkFiles);
+
+ // Configure additional settings.
+ AddConfigurations();
+ }
+
+ protected override void AddAnalyzers()
+ {
+ // Exclude MinIterationTimeAnalyser that cause warning when using RunStrategy.Monitoring.
+ var analyzers = DefaultConfig.Instance
+ .GetAnalysers()
+ .Where(x => x is not MinIterationTimeAnalyser)
+ .ToArray();
+
+ AddAnalyser(analyzers);
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DefaultBenchmarkConfig.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DefaultBenchmarkConfig.cs
new file mode 100644
index 0000000000..60246b8b98
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/DefaultBenchmarkConfig.cs
@@ -0,0 +1,22 @@
+using BenchmarkDotNet.Jobs;
+using System.Runtime.InteropServices;
+
+namespace BenchmarkDotNet;
+
+public class DefaultBenchmarkConfig : BaseBenchmarkConfig
+{
+ public DefaultBenchmarkConfig() : base()
+ {
+ // Configure base job config
+ var baseJobConfig = GetBaseJobConfig();
+
+ // Create benchmark job.
+ var job = baseJobConfig.WithId($"Default({RuntimeInformation.FrameworkDescription})");
+
+ // Add job.
+ AddJob(job);
+
+ // Configure additional settings.
+ AddConfigurations();
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/TargetFrameworksBenchmarkConfig.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/TargetFrameworksBenchmarkConfig.cs
new file mode 100644
index 0000000000..32711dcaa0
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Configs/TargetFrameworksBenchmarkConfig.cs
@@ -0,0 +1,50 @@
+using BenchmarkDotNet.Analysers;
+using BenchmarkDotNet.Columns;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Jobs;
+using BenchmarkDotNet.Toolchains.CsProj;
+
+namespace BenchmarkDotNet;
+
+///
+/// BenchmarkConfig that run benchmarks for multiple target frameworks.
+///
+public class TargetFrameworksBenchmarkConfig : BaseBenchmarkConfig
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TargetFrameworksBenchmarkConfig() : base()
+ {
+ // Configure base job config
+ var baseJobConfig = GetBaseJobConfig();
+
+ // Add jobs
+ AddJob(baseJobConfig.WithToolchain(CsProjCoreToolchain.NetCoreApp80).WithId(".NET 8").AsBaseline());
+ AddJob(baseJobConfig.WithToolchain(CsProjCoreToolchain.NetCoreApp90).WithId(".NET 9"));
+ AddJob(baseJobConfig.WithToolchain(CsProjCoreToolchain.NetCoreApp10_0).WithId(".NET 10"));
+
+ // AddJob(baseJobConfig.WithToolchain(CsProjClassicNetToolchain.Net48).WithId(".NET Framework 4.8"));
+
+ // Configure additional settings.
+ AddConfigurations();
+ }
+
+ protected override void AddLogicalGroupRules()
+ {
+ // Grouping benchmarks by method.
+ // Note: When following conditions are met. BaselineCustomAnalyzer raise warning. See: https://github.com/dotnet/BenchmarkDotNet/issues/2956
+ // 1. Job contains Baseline=true
+ // 2. Benchmark method contains Baseline=true
+ // 3. Enable grouping with method.
+ AddLogicalGroupRules(
+ [
+ BenchmarkLogicalGroupRule.ByMethod,
+ ]);
+ }
+
+ protected override void AddColumnHidingRules()
+ {
+ HideColumns(Column.Toolchain); // Toolchain information are shown at JobId column.
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/ExtensionMethods/SummariesExtensions.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/ExtensionMethods/SummariesExtensions.cs
new file mode 100644
index 0000000000..8be1d0452a
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/ExtensionMethods/SummariesExtensions.cs
@@ -0,0 +1,23 @@
+using BenchmarkDotNet.Reports;
+
+namespace BenchmarkDotNet;
+
+public static class SummariesExtensions
+{
+ public static bool HasError(this Summary[] summaries)
+ {
+ if (summaries.Length == 0)
+ {
+ var hashSet = new HashSet(["--help", "--list", "--info", "--version"]);
+
+ var args = Environment.GetCommandLineArgs();
+ return !args.Any(hashSet.Contains);
+ }
+
+ if (summaries.Any(x => x.HasCriticalValidationErrors))
+ return true;
+
+ return summaries.Any(x => x.Reports.Any(r => !r.Success));
+ }
+}
+
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Filters/TargetFrameworkFilter.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Filters/TargetFrameworkFilter.cs
new file mode 100644
index 0000000000..53a87300a7
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Filters/TargetFrameworkFilter.cs
@@ -0,0 +1,47 @@
+using BenchmarkDotNet.Filters;
+using BenchmarkDotNet.Running;
+using BenchmarkDotNet.Samples.Sandbox;
+using BenchmarkDotNet.Toolchains.CsProj;
+using System.Linq;
+
+namespace BenchmarkDotNet;
+
+///
+/// Custom BenchmarkDotNet filter to exclude benchmarks based on target framework category.
+/// This filter is required because BenchmarkDotNet don't support conditional benchmarks with `#if` directive.
+///
+public partial class TargetFrameworkFilter : IFilter
+{
+ public static readonly TargetFrameworkFilter Instance = new();
+
+ private TargetFrameworkFilter() { }
+
+ public virtual bool Predicate(BenchmarkCase benchmarkCase)
+ {
+ var toolchain = benchmarkCase.Job.Infrastructure.Toolchain;
+ if (toolchain == null || toolchain is not CsProjCoreToolchain)
+ return true;
+
+ var versionText = toolchain.Name.Split(' ').Last(); // Expected `.NET 8.0` format.
+ if (!Version.TryParse(versionText, out var targetVersion))
+ return true; // Return true if failed to resolve target version.
+
+ var categories = benchmarkCase.Descriptor.Categories;
+ foreach (var category in categories)
+ {
+ switch (category)
+ {
+ case Categories.Filters.NET8_0_OR_GREATER:
+ return targetVersion.Major >= 8;
+ case Categories.Filters.NET9_0_OR_GREATER:
+ return targetVersion.Major >= 9;
+ case Categories.Filters.NET10_0_OR_GREATER:
+ return targetVersion.Major >= 10;
+ default:
+ continue;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Helpers/AssemblyConfigProvider.cs b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Helpers/AssemblyConfigProvider.cs
new file mode 100644
index 0000000000..eca3e3b5b3
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/BenchmarkDotNet/Helpers/AssemblyConfigProvider.cs
@@ -0,0 +1,35 @@
+using BenchmarkDotNet.Configs;
+
+namespace BenchmarkDotNet;
+
+///
+/// This class provide assembly level benchmark config.
+/// It's required because `Program.cs` and `launchSettings.json` is not used when running on VS TestExplorer.
+///
+[AttributeUsage(AttributeTargets.Assembly)]
+internal class AssemblyConfigProvider : Attribute, IConfigSource
+{
+ public static IConfig GetConfig() => config.Value;
+
+ public IConfig Config => config.Value;
+
+ private static readonly Lazy config = new(() =>
+ {
+ var configKey = Environment.GetEnvironmentVariable(Constants.EnvironmentVariables.BenchmarkDotNetConfig) ?? "";
+
+ switch (configKey)
+ {
+ case "":
+ case "Default":
+ return new DefaultBenchmarkConfig();
+ case "Debug":
+ return new DebugBenchmarkConfig();
+ case "DebugInProcess":
+ return new DebugInProcessBenchmarkConfig();
+ case "TargetFrameworks":
+ return new TargetFrameworksBenchmarkConfig();
+ default:
+ throw new InvalidOperationException($"Unknown benchmark config key is specified: {configKey}");
+ }
+ });
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/Benchmarks/DefaultBenchmarks.cs b/samples/BenchmarkDotNet.Samples.Sandbox/Benchmarks/DefaultBenchmarks.cs
new file mode 100644
index 0000000000..555b3d5367
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/Benchmarks/DefaultBenchmarks.cs
@@ -0,0 +1,42 @@
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Engines;
+
+namespace BenchmarkDotNet.Samples.Sandbox;
+
+public class DefaultBenchmarks
+{
+ private readonly Consumer Consumer = new();
+
+ // [Params(1_000_000)]
+ public int N { get; set; } = 1_000_000;
+
+ private readonly IEnumerable EnumerableDataSource;
+ private readonly int[] ArrayDataSource;
+
+ public DefaultBenchmarks()
+ {
+ var rand = new Random(0);
+ var source = Enumerable.Range(1, N).Select(x => rand.Next());
+
+ EnumerableDataSource = source;
+ ArrayDataSource = EnumerableDataSource.ToArray();
+ }
+
+ [Benchmark(Baseline = true)]
+ public void Benchmark01()
+ {
+ foreach (var i in EnumerableDataSource.OrderBy(x => x))
+ {
+ Consumer.Consume(i);
+ }
+ }
+
+ [Benchmark]
+ public void Benchmark02()
+ {
+ foreach (var i in ArrayDataSource.OrderBy(x => x))
+ {
+ Consumer.Consume(i);
+ }
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/Constants.cs b/samples/BenchmarkDotNet.Samples.Sandbox/Constants.cs
new file mode 100644
index 0000000000..c19240c275
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/Constants.cs
@@ -0,0 +1,25 @@
+using BenchmarkDotNet.Toolchains;
+using BenchmarkDotNet.Toolchains.CsProj;
+
+namespace BenchmarkDotNet;
+
+internal class Constants
+{
+ public static readonly IToolchain DefaultToolchain = CsProjCoreToolchain.NetCoreApp10_0;
+
+ public class EnvironmentVariables
+ {
+ public const string BenchmarkDotNetConfig = "BENCHMARKDOTNET_CONFIG";
+ }
+}
+
+internal class Categories
+{
+ // Categories that is used to filter benchmarks.
+ public static class Filters
+ {
+ public const string NET8_0_OR_GREATER = "NET8_0_OR_GREATER";
+ public const string NET9_0_OR_GREATER = "NET9_0_OR_GREATER";
+ public const string NET10_0_OR_GREATER = "NET10_0_OR_GREATER";
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/Program.cs b/samples/BenchmarkDotNet.Samples.Sandbox/Program.cs
new file mode 100644
index 0000000000..1f64e1aa8b
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/Program.cs
@@ -0,0 +1,51 @@
+using BenchmarkDotNet.Columns;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Engines;
+using BenchmarkDotNet.Exporters;
+using BenchmarkDotNet.Loggers;
+using BenchmarkDotNet.Running;
+
+namespace BenchmarkDotNet.Samples.Sandbox;
+
+internal class Program
+{
+ public static int Main(string[] args)
+ {
+ var logger = ConsoleLogger.Default;
+#if DEBUG
+ logger.WriteLineWarning("Benchmark is executed with DEBUG configuration.");
+ logger.WriteLine();
+#endif
+
+ if (args.Length != 0)
+ logger.WriteLine($"Start benchmarks with args: {string.Join(" ", args)}");
+
+ try
+ {
+ // Get benchmark config
+ var config = AssemblyConfigProvider.GetConfig();
+ logger.WriteLine($"Selected benchmark config: {config.GetType().Name}");
+ logger.WriteLine();
+
+ // Run benchmarks
+ var summaries = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly)
+ .Run(args, config)
+ .ToArray();
+
+ // Check benchmark results.
+ if (summaries.HasError())
+ {
+ logger.WriteLine();
+ logger.WriteLineError("Failed to run benchmarks.");
+ return 1;
+ }
+
+ return 0;
+ }
+ catch (Exception ex)
+ {
+ logger.WriteLineError(ex.ToString());
+ return 1;
+ }
+ }
+}
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/Properties/PropertyInfo.cs b/samples/BenchmarkDotNet.Samples.Sandbox/Properties/PropertyInfo.cs
new file mode 100644
index 0000000000..0254732fbf
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/Properties/PropertyInfo.cs
@@ -0,0 +1,3 @@
+using BenchmarkDotNet;
+
+[assembly: AssemblyConfigProvider]
diff --git a/samples/BenchmarkDotNet.Samples.Sandbox/Properties/launchSettings.json b/samples/BenchmarkDotNet.Samples.Sandbox/Properties/launchSettings.json
new file mode 100644
index 0000000000..7bf430c88a
--- /dev/null
+++ b/samples/BenchmarkDotNet.Samples.Sandbox/Properties/launchSettings.json
@@ -0,0 +1,37 @@
+{
+ "profiles": {
+ "Default": {
+ "commandName": "Project",
+ "commandLineArgs": "--filter *DefaultBenchmarks*",
+ "environmentVariables": {
+ }
+ },
+ "Debug": {
+ "commandName": "Project",
+ "commandLineArgs": "--filter *DefaultBenchmarks*",
+ "environmentVariables": {
+ "BENCHMARKDOTNET_CONFIG": "Debug"
+ }
+ },
+ "DebugInProcess": {
+ "commandName": "Project",
+ "commandLineArgs": "--filter *DefaultBenchmarks*",
+ "environmentVariables": {
+ "BENCHMARKDOTNET_CONFIG": "DebugInProcess"
+ }
+ },
+ "TargetFrameworks": {
+ "commandName": "Project",
+ "commandLineArgs": "--filter *DefaultBenchmarks*",
+ "environmentVariables": {
+ "BENCHMARKDOTNET_CONFIG": "TargetFrameworks"
+ }
+ },
+ "Help": {
+ "commandName": "Project",
+ "commandLineArgs": "--help",
+ "environmentVariables": {
+ }
+ }
+ }
+}
diff --git a/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj b/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj
index 647308d606..1db648deb0 100644
--- a/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj
+++ b/src/BenchmarkDotNet.Analyzers/BenchmarkDotNet.Analyzers.csproj
@@ -5,6 +5,8 @@
false
BenchmarkDotNet.Analyzers
+ cs
+ true
true
$(NoWarn);CS1591
diff --git a/src/BenchmarkDotNet.Analyzers/Properties/launchSettings.json b/src/BenchmarkDotNet.Analyzers/Properties/launchSettings.json
new file mode 100644
index 0000000000..84a45213e0
--- /dev/null
+++ b/src/BenchmarkDotNet.Analyzers/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Debug": {
+ "commandName": "DebugRoslynComponent",
+ "targetProject": "..\\..\\samples\\BenchmarkDotNet.Samples.Sandbox\\BenchmarkDotNet.Samples.Sandbox.csproj"
+ }
+ }
+}
diff --git a/tests/BenchmarkDotNet.Analyzers.Tests/Fixtures/AnalyzerTestFixture.cs b/tests/BenchmarkDotNet.Analyzers.Tests/Fixtures/AnalyzerTestFixture.cs
index 7b3cd39fe6..8114f9a6ce 100644
--- a/tests/BenchmarkDotNet.Analyzers.Tests/Fixtures/AnalyzerTestFixture.cs
+++ b/tests/BenchmarkDotNet.Analyzers.Tests/Fixtures/AnalyzerTestFixture.cs
@@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.Testing;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;