0Pricing
C# Academy · Leçon

Évaluation des performances avec BenchmarkDotNet

Écrivez des micro-évaluations précises avec BenchmarkDotNet, analysez le débit et les allocations, puis évitez les pièges courants.

Évaluation des performances avec BenchmarkDotNet est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Pourquoi utiliser BenchmarkDotNet ?

Les micro-évaluations de performances sont étonnamment difficiles : la phase de chauffe de JIT, les pauses du GC, les caches du CPU et l'ordonnancement du système d'exploitation introduisent tous du bruit. BenchmarkDotNet gère automatiquement tous ces éléments et produit des résultats statistiquement fiables.

Installation et première évaluation

Ajoutez le package NuGet, créez une classe contenant des méthodes [Benchmark], puis exécutez-la avec BenchmarkRunner.Run. Exécutez toujours les évaluations en mode 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>();

Lire le tableau de résultats

BenchmarkDotNet affiche un tableau de résultats contenant le temps moyen, l'erreur, l'écart type, le ratio et l'allocation mémoire. Voici comment interpréter chaque colonne.

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

Évaluations paramétrées

Utilisez [Params] pour exécuter une évaluation sur plusieurs tailles d'entrée. BenchmarkDotNet exécute chaque combinaison et génère une ligne distincte pour chaque valeur de paramètre.

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

Initialisation et nettoyage

Utilisez les attributs de cycle de vie pour effectuer une initialisation unique ou une initialisation et un nettoyage à chaque itération. Cela exclut le coût de l'initialisation du temps mesuré de l'évaluation.

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

Diagnostics de la mémoire

[MemoryDiagnoser] indique les allocations du tas managé par opération. Associez-le aux options [GcForce] pour contrôler le comportement du GC pendant les évaluations.

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

Outils de diagnostic : ETW et désassemblage

BenchmarkDotNet prend en charge plusieurs outils de diagnostic. DisassemblyDiagnoser affiche le code assembleur natif réellement produit, ce qui est idéal pour vérifier les optimisations de 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();
}

Configurations des tâches

Les tâches contrôlent l'environnement d'exécution des évaluations : nombre d'itérations de chauffe, invocations par itération, version de l'environnement d'exécution .NET et paramètres de JIT. Utilisez des tâches prédéfinies ou personnalisées.

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

Exporter les résultats

BenchmarkDotNet exporte les résultats dans plusieurs formats : Markdown (pour les demandes de fusion GitHub), CSV (pour les feuilles de calcul), JSON et graphiques HTML. Les options d'exportation sont configurées dans la configuration de la tâche.

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)

Dans la pratique : optimisation avant/après

Utiliser BenchmarkDotNet pour valider une optimisation des performances en comparant des approches naïve, avec pool et fondée sur 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 _);
}

Vérification rapide

Pourquoi les évaluations BenchmarkDotNet doivent-elles être exécutées avec dotnet run -c Release ?

Récapitulatif : évaluer les performances avec BenchmarkDotNet

Points essentiels :

  • Installez via NuGet, marquez les méthodes avec [Benchmark], puis exécutez avec dotnet run -c Release
  • [MemoryDiagnoser] : ajoute une colonne d'allocation ; [RankColumn] : classe les résultats par vitesse
  • [Params] : exécutez l'évaluation sur plusieurs tailles d'entrée pour déterminer la complexité algorithmique
  • [GlobalSetup] / [GlobalCleanup] : initialisation unique effectuée en dehors du temps mesuré
  • [DisassemblyDiagnoser] : examinez l'ASM natif généré pour vérifier les optimisations de JIT
  • Utilisez des tâches pour comparer JIT de .NET 9, Native AOT et différents nombres d'itérations

Questions Fréquemment Posées

La leçon « Évaluation des performances avec BenchmarkDotNet » est-elle gratuite ?

Oui — le texte complet de « Évaluation des performances avec BenchmarkDotNet » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Évaluation des performances avec BenchmarkDotNet » ?

Écrivez des micro-évaluations précises avec BenchmarkDotNet, analysez le débit et les allocations, puis évitez les pièges courants. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Évaluation des performances avec BenchmarkDotNet » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Compilation Native AOT
  2. Limites de la réduction et de la réflexion
  3. ReadyToRun et compilation par niveaux
  4. Évaluation des performances avec BenchmarkDotNet
← Retour à C# Academy