C# Academy · Pelajaran

Benchmark dengan BenchmarkDotNet

Tulis benchmark mikro yang akurat dengan BenchmarkDotNet, analisis throughput dan alokasi, serta hindari kesalahan umum.

Pelajaran 4 dari 412 langkah

Benchmark dengan BenchmarkDotNet adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.

Mengapa BenchmarkDotNet?

Pengukuran kinerja mikro ternyata sulit: pemanasan JIT, jeda GC, cache CPU, dan penjadwalan OS semuanya menimbulkan gangguan. BenchmarkDotNet menangani semua ini secara otomatis dan menghasilkan hasil yang andal secara statistik.

Instalasi dan Pengukuran Pertama

Tambahkan paket NuGet, buat kelas dengan metode [Benchmark], lalu jalankan dengan BenchmarkRunner.Run. Selalu jalankan pengukuran dalam mode Rilis.

// 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>();

Membaca Tabel Hasil

BenchmarkDotNet mencetak tabel hasil yang berisi waktu rata-rata, kesalahan, simpangan baku, rasio, dan alokasi memori. Berikut cara menafsirkan setiap kolom.

// 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)

Pengukuran Berparameter

Gunakan [Params] untuk menjalankan pengukuran pada beberapa ukuran masukan. BenchmarkDotNet menjalankan setiap kombinasi dan menghasilkan baris terpisah untuk setiap nilai parameter.

[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;
}

Penyiapan dan Pembersihan

Gunakan atribut siklus hidup untuk menjalankan penyiapan satu kali atau penyiapan/pembersihan per iterasi. Dengan demikian, biaya penyiapan tidak termasuk dalam waktu pengukuran yang diukur.

[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(); }
}

Diagnosis Memori

[MemoryDiagnoser] melaporkan alokasi heap terkelola per operasi. Kombinasikan dengan opsi [GcForce] untuk mengontrol perilaku GC selama pengukuran.

[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;
    }
}

Alat Diagnosis: ETW dan Disassembly

BenchmarkDotNet mendukung beberapa alat diagnosis. DisassemblyDiagnoser menampilkan keluaran rakitan natif yang sebenarnya, cocok untuk memverifikasi optimisasi 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();
}

Konfigurasi Tugas

Tugas mengontrol lingkungan eksekusi pengukuran — jumlah iterasi pemanasan, pemanggilan per iterasi, versi lingkungan eksekusi .NET, dan pengaturan JIT. Gunakan tugas siap pakai atau kustom.

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));
    }
}

Mengekspor Hasil

BenchmarkDotNet mengekspor hasil dalam berbagai format — Markdown (untuk PR GitHub), CSV (untuk lembar bentang), JSON, dan bagan HTML. Opsi ekspor dikonfigurasi dalam konfigurasi tugas.

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)

Dunia Nyata: Optimisasi Sebelum dan Sesudah

Menggunakan BenchmarkDotNet untuk memvalidasi optimisasi kinerja — membandingkan pendekatan sederhana, berbasis kumpulan, dan berbasis 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 _);
}

Pemeriksaan Singkat

Mengapa pengukuran BenchmarkDotNet harus dijalankan dengan dotnet run -c Release?

Ringkasan: Pengukuran dengan BenchmarkDotNet

Hal penting:

  • Instal melalui NuGet; tandai metode dengan [Benchmark]; jalankan dengan dotnet run -c Release
  • [MemoryDiagnoser]: menambahkan kolom alokasi; [RankColumn]: mengurutkan berdasarkan kecepatan
  • [Params]: jalankan pada beberapa ukuran masukan untuk menemukan kompleksitas algoritmik
  • [GlobalSetup] / [GlobalCleanup]: penyiapan satu kali di luar waktu yang diukur
  • [DisassemblyDiagnoser]: periksa ASM natif yang dihasilkan untuk memverifikasi optimisasi JIT
  • Gunakan tugas untuk membandingkan JIT .NET 9 dengan Native AOT dan jumlah iterasi yang berbeda
Gratis untuk memulai

Belajar C# dengan tutor AI — gratis

Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.

Kursus
93
Pelajaran
346

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Benchmark dengan BenchmarkDotNet” gratis?

Ya — teks lengkap “Benchmark dengan BenchmarkDotNet” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Benchmark dengan BenchmarkDotNet”?

Tulis benchmark mikro yang akurat dengan BenchmarkDotNet, analisis throughput dan alokasi, serta hindari kesalahan umum. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai C# Academy?

Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Benchmark dengan BenchmarkDotNet” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?

Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Kompilasi Native AOT
  2. Keterbatasan Trimming & Reflection
  3. ReadyToRun & Kompilasi Bertingkat
  4. Benchmark dengan BenchmarkDotNet
← Kembali ke C# Academy