Codebelt

Codebelt.Extensions.BenchmarkDotNet.Console

Run BenchmarkDotNet through a Generic Host with repository-aware workspace services.

.NET 10.0 / .NET 9.0 MIT v1.3.0 3,269 downloads

Overview

Codebelt.Extensions.BenchmarkDotNet.Console turns the core workspace abstractions from Codebelt.Extensions.BenchmarkDotNet into a console-hosted execution model. BenchmarkProgram creates a Generic Host, registers BenchmarkContext and an IBenchmarkWorkspace, executes discovered benchmarks through BenchmarkDotNet, and always invokes artifact post-processing when execution finishes.

The package is for repositories that want benchmarks to run like other hosted workloads. Instead of repeating host bootstrapping, workspace registration, build-configuration checks, and artifact cleanup in each Program.cs, you call one of the provided Run overloads and keep repository-specific behavior in options, services, or a custom workspace implementation.

Key APIs

BenchmarkProgram.Run<TWorkspace>(string[] args, Action<IServiceCollection> serviceConfigurator = null, Action<BenchmarkWorkspaceOptions> setup = null) is the package's most flexible entry point. It builds the host, registers BenchmarkContext, adds the chosen IBenchmarkWorkspace, applies workspace options, lets callers register extra services, and then runs the host.

BenchmarkProgram.Run(string[] args, Action<BenchmarkWorkspaceOptions> setup = null) is the shorter entry point for the default BenchmarkWorkspace. Use it when the standard repository discovery and artifact handling behavior is enough and you only need to tweak BenchmarkWorkspaceOptions.

BenchmarkProgram.BuildConfiguration exposes whether the entry assembly resolved to Debug or Release. The static constructor computes it once from the entry assembly when possible, and the value is then reused by the host runner.

BenchmarkProgram.IsDebugBuild is the boolean companion to BuildConfiguration. It is useful when workspace options should enable Debug builds only when the current entry assembly was actually compiled for debugging.

BenchmarkContext carries the original command-line arguments into the hosted execution pipeline. Consumers can inject it into custom workspace implementations or other services when benchmark selection or runner behavior depends on the raw console arguments.

Basic usage

using System;
using System.Reflection;
using Codebelt.Extensions.BenchmarkDotNet;
using Codebelt.Extensions.BenchmarkDotNet.Console;
using Codebelt.Extensions.Xunit;
using Xunit;

namespace MyProject.Tests;

public class BenchmarkProgramUsageTests : Test
{
    public BenchmarkProgramUsageTests(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void Run_ComposesWorkspaceLifecycle()
    {
        RecordingWorkspace.Reset();

        BenchmarkProgram.Run<RecordingWorkspace>(Array.Empty<string>(), options =>
        {
            options.AllowDebugBuild = BenchmarkProgram.IsDebugBuild;
        });

        TestOutput.WriteLines(
            $"Build configuration: {BenchmarkProgram.BuildConfiguration}",
            $"Workspace loaded assemblies: {RecordingWorkspace.LoadedAssemblies}",
            $"Workspace post-processed artifacts: {RecordingWorkspace.PostProcessedArtifacts}");

        Assert.Empty(RecordingWorkspace.CapturedArgs);
        Assert.True(RecordingWorkspace.LoadedAssemblies);
        Assert.True(RecordingWorkspace.PostProcessedArtifacts);
    }

    private sealed class RecordingWorkspace : IBenchmarkWorkspace
    {
        public static string[] CapturedArgs { get; private set; } = Array.Empty<string>();
        public static bool LoadedAssemblies { get; private set; }
        public static bool PostProcessedArtifacts { get; private set; }

        private readonly BenchmarkContext _context;

        public RecordingWorkspace(BenchmarkContext context)
        {
            _context = context;
        }

        public Assembly[] LoadBenchmarkAssemblies()
        {
            CapturedArgs = _context.Args;
            LoadedAssemblies = true;
            return Array.Empty<Assembly>();
        }

        public void PostProcessArtifacts()
        {
            PostProcessedArtifacts = true;
        }

        public static void Reset()
        {
            CapturedArgs = Array.Empty<string>();
            LoadedAssemblies = false;
            PostProcessedArtifacts = false;
        }
    }
}

Use this pattern when a benchmark runner should execute inside a Generic Host and still control how assemblies are discovered or how artifacts are finalized. It matters because the package gives the runner one hosted entry point that composes command-line context, DI registration, workspace discovery, and cleanup around BenchmarkDotNet execution.

Installation

dotnet add package Codebelt.Extensions.BenchmarkDotNet.Console

Usage guidance

Adopt this package when benchmarks should run as a hosted console application with predictable DI composition and one place to coordinate workspace options. If your benchmarks do not need hosting, service registration, or custom workspace orchestration, Codebelt.Extensions.BenchmarkDotNet or plain BenchmarkDotNet entry-point code will be a smaller fit.

Family packages