0Pricing
C# Academy · レッスン

BenchmarkDotNetによるベンチマーク

BenchmarkDotNetで正確なマイクロベンチマークを記述し、スループットとアロケーションを分析して、よくある問題を避けます。

「BenchmarkDotNetによるベンチマーク」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

なぜBenchmarkDotNetを使うのか

マイクロベンチマークは意外に難しいものです。JITのウォームアップ、GCの一時停止、CPUキャッシュ、OSのスケジューリングがすべてノイズを生み出します。BenchmarkDotNetはこれらを自動的に処理し、統計的に信頼できる結果を生成します。

インストールと最初のベンチマーク

NuGetパッケージを追加し、[Benchmark]メソッドを持つクラスを作成して、BenchmarkRunner.Runで実行します。ベンチマークは必ずReleaseモードで実行してください。

// dotnet add package BenchmarkDotNet

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

[MemoryDiagnoser]           // report allocations
[RankColumn]                // rank methods by speed
public class StringBenchmarks
{
    [Benchmark(Baseline = true)]
    public string Concatenation()
    {
        var s = "";
        for (int i = 0; i < 100; i++) s += i;
        return s;
    }

    [Benchmark]
    public string StringBuilder()
    {
        var sb = new System.Text.StringBuilder();
        for (int i = 0; i < 100; i++) sb.Append(i);
        return sb.ToString();
    }
}

// Program.cs (must run as Release):
BenchmarkRunner.Run<StringBenchmarks>();

結果テーブルの読み方

BenchmarkDotNetは、平均時間、誤差、標準偏差、比率、メモリ割り当てを含む結果テーブルを出力します。ここでは各列の解釈方法を説明します。

// Example output:
// | Method        |     Mean |   Error |  StdDev | Ratio | Alloc |
// |-------------- |---------:|--------:|--------:|------:|------:|
// | Concatenation | 4,210 ns |  81 ns  |  76 ns  |  1.00 | 6.4KB |
// | StringBuilder |   312 ns |   4 ns  |   4 ns  |  0.07 | 1.6KB |

// Mean:  average time per operation
// Error: half of 99.9% confidence interval
// StdDev: standard deviation — high value = noisy environment
// Ratio: relative to Baseline=true method (1.00)
// Alloc: managed heap allocated per operation

// Rule of thumb:
// Error should be < 5% of Mean for reliable results
// Run on an isolated machine (no background tasks)

パラメーター化されたベンチマーク

[Params]を使用すると、複数の入力サイズでベンチマークを実行できます。BenchmarkDotNetはすべての組み合わせを実行し、パラメーター値ごとに個別の行を生成します。

[MemoryDiagnoser]
public class SearchBenchmarks
{
    [Params(10, 100, 1000, 10000)]
    public int N;

    private int[] _data = Array.Empty<int>();

    [GlobalSetup]
    public void Setup()
        => _data = Enumerable.Range(0, N).ToArray();

    [Benchmark]
    public bool LinearSearch()
        => Array.IndexOf(_data, N - 1) >= 0;

    [Benchmark]
    public bool BinarySearch()
        => Array.BinarySearch(_data, N - 1) >= 0;
}

セットアップとクリーンアップ

ライフサイクル属性を使用して、1回だけ実行するセットアップや、反復ごとのセットアップとクリーンアップを実行します。これにより、セットアップのコストを測定対象のベンチマーク時間から除外できます。

[MemoryDiagnoser]
public class DbQueryBenchmarks
{
    private NpgsqlConnection _conn = null!;
    private NpgsqlCommand _cmd = null!;

    [GlobalSetup]              // runs once before all benchmarks
    public void Setup()
    {
        _conn = new NpgsqlConnection("...");
        _conn.Open();
        _cmd = new NpgsqlCommand("SELECT id FROM orders LIMIT 100", _conn);
    }

    [IterationSetup]           // runs before EACH benchmark iteration
    public void IterationSetup() { /* per-iteration prep */ }

    [Benchmark]
    public int QueryOrders() => (int)_cmd.ExecuteScalar()!;

    [GlobalCleanup]            // runs once after all benchmarks
    public void Cleanup() { _cmd.Dispose(); _conn.Dispose(); }
}

メモリ診断

[MemoryDiagnoser]は、操作ごとのマネージヒープ割り当てを報告します。[GcForce]オプションと組み合わせて、ベンチマーク中のGCの動作を制御できます。

[MemoryDiagnoser]  // adds Alloc column to results
public class AllocationBenchmarks
{
    [Benchmark]
    public int[] AllocateArray() => new int[1000];

    [Benchmark]
    public Span<int> UseStackalloc()
    {
        Span<int> span = stackalloc int[1000];
        return span; // WARN: for illustration; don't return stackalloc
    }

    [Benchmark]
    public int[] ArrayPoolRent()
    {
        var arr = System.Buffers.ArrayPool<int>.Shared.Rent(1000);
        System.Buffers.ArrayPool<int>.Shared.Return(arr);
        return arr;
    }
}

診断ツール:ETWと逆アセンブリ

BenchmarkDotNetは複数の診断ツールをサポートしています。DisassemblyDiagnoserは実際に生成されたネイティブアセンブリを表示するため、JITの最適化を検証するのに最適です。

using BenchmarkDotNet.Diagnosers;

[DisassemblyDiagnoser(          // show generated ASM
    maxDepth: 2,
    printSource: true,
    exportGithubMarkdown: true)]
[MemoryDiagnoser]
public class VectorizationBenchmarks
{
    private float[] _data = new float[1024];

    [Benchmark]
    public float SumScalar()
    {
        float sum = 0;
        foreach (var v in _data) sum += v;
        return sum;
    }

    [Benchmark]
    public float SumVectorized()
        => System.Numerics.Vector<float>.Count > 1
            ? VectorSum(_data)
            : SumScalar();
}

ジョブ構成

ジョブは、ウォームアップ反復回数、反復ごとの呼び出し回数、.NETランタイムのバージョン、JIT設定など、ベンチマークの実行環境を制御します。定義済みのジョブまたはカスタムジョブを使用できます。

using BenchmarkDotNet.Jobs;

// Compare JIT vs Native AOT performance:
[SimpleJob(RuntimeMoniker.Net90)]    // .NET 9 JIT
[SimpleJob(RuntimeMoniker.NativeAot90)] // .NET 9 AOT
[MemoryDiagnoser]
public class RuntimeComparison
{
    [Benchmark]
    public string SerializeJson()
    {
        var obj = new { Name = "Alice", Age = 30 };
        return System.Text.Json.JsonSerializer.Serialize(obj);
    }
}

// Custom job for more warmup:
[Config(typeof(MyConfig))]
public class PreciseBenchmarks
{
    private class MyConfig : ManualConfig
    {
        public MyConfig()
            => AddJob(Job.Default.WithWarmupCount(5).WithIterationCount(20));
    }
}

結果のエクスポート

BenchmarkDotNetは、Markdown(GitHubのPR向け)、CSV(スプレッドシート向け)、JSON、HTMLチャートなど、複数の形式で結果をエクスポートします。エクスポートのオプションはジョブ構成で設定します。

using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;

[Config(typeof(ExportConfig))]
public class MyBenchmarks { /* ... */ }

public class ExportConfig : ManualConfig
{
    public ExportConfig()
    {
        AddExporter(MarkdownExporter.GitHub);
        AddExporter(CsvExporter.Default);
        AddExporter(HtmlExporter.Default);
        // Results in: BenchmarkDotNet.Artifacts/results/
    }
}

// CLI usage to run specific benchmarks:
// dotnet run -c Release -- --filter "*StringBenchmarks*"
// dotnet run -c Release -- --list all  (list all benchmarks)

実践例:最適化前と最適化後

BenchmarkDotNetを使用してパフォーマンス最適化を検証します。単純なアプローチ、プールを使用するアプローチ、Spanベースのアプローチを比較します。

[MemoryDiagnoser]
[RankColumn]
public class ParsingBenchmarks
{
    private const string Input = "2025-06-15T08:30:00Z";

    [Benchmark(Baseline = true)]
    public DateTime ParseViaString()
        => DateTime.Parse(Input);

    [Benchmark]
    public DateTime ParseExact()
        => DateTime.ParseExact(Input,
            "yyyy-MM-ddTHH:mm:ssZ",
            System.Globalization.CultureInfo.InvariantCulture);

    [Benchmark]
    public bool TryParse()
        => DateTime.TryParseExact(Input.AsSpan(),
            "yyyy-MM-ddTHH:mm:ssZ",
            System.Globalization.CultureInfo.InvariantCulture,
            System.Globalization.DateTimeStyles.None,
            out _);
}

確認問題

BenchmarkDotNetのベンチマークは、なぜdotnet run -c Releaseで実行する必要があるのでしょうか。

まとめ:BenchmarkDotNetによるベンチマーク

主なポイント:

  • NuGetでインストールし、メソッドに[Benchmark]を付け、dotnet run -c Releaseで実行します
  • [MemoryDiagnoser]:割り当て列を追加します。[RankColumn]:速度順にランク付けします
  • [Params]:複数の入力サイズで実行し、アルゴリズムの計算量を確認します
  • [GlobalSetup] / [GlobalCleanup]:測定時間の外で1回だけセットアップまたはクリーンアップを行います
  • [DisassemblyDiagnoser]:生成されたネイティブASMを調べて、JITの最適化を検証します
  • ジョブを使用して、.NET 9 JITとNative AOT、または異なる反復回数を比較します

よくある質問

「BenchmarkDotNetによるベンチマーク」レッスンは無料ですか?

はい。「BenchmarkDotNetによるベンチマーク」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「BenchmarkDotNetによるベンチマーク」で何を学びますか?

BenchmarkDotNetで正確なマイクロベンチマークを記述し、スループットとアロケーションを分析して、よくある問題を避けます。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「BenchmarkDotNetによるベンチマーク」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Native AOTコンパイル
  2. トリミングとリフレクションの制限
  3. ReadyToRunと階層型コンパイル
  4. BenchmarkDotNetによるベンチマーク
← C# Academyに戻る