Introduction : Pourquoi le Profilage est Important
Chaque développeur C# a déjà rencontré une situation où une application tourne lentement, sans que l'on sache pourquoi. Les suppositions intuitives sont souvent fausses : un code qui semble lent peut être rapide, et des optimisations « évidentes » peuvent être inutiles. C'est là que le profilage vient à la rescousse — une analyse systématique des performances du code pour identifier les goulots d'étranglement.
Le profilage dans .NET ne se résume pas à mesurer le temps d'exécution. C'est tout un ensemble de techniques : d'un simple Stopwatch à des outils avancés comme BenchmarkDotNet et PerfView. Sans profilage, vous risquez d'optimiser les mauvais éléments, en passant des heures sur des modifications inutiles.
Dans cet article, nous allons décomposer les méthodes pratiques pour profiler du code C#, apprendre à trouver les vrais goulots d'étranglement, et comprendre quels outils utiliser dans chaque cas spécifique.
1. Profilage de Base avec Stopwatch
La façon la plus simple de mesurer le temps d'exécution est d'utiliser la classe System.Diagnostics.Stopwatch. Elle est adaptée pour des vérifications rapides et des scénarios simples, mais a des limites : une surcharge importante (nanosecondes) et un manque de statistiques.
using System.Diagnostics;
public class SimpleProfiler{ public static void Measure() { var sw = Stopwatch.StartNew(); // Code under test var list = Enumerable.Range(0, 10_000_000).ToList(); sw.Stop(); Console.WriteLine($"Time: {sw.ElapsedMilliseconds} ms"); }}Quand l'utiliser : pour une estimation grossière, quand vous avez besoin d'une réponse rapide sans installer de paquets supplémentaires. Pas adapté pour des mesures précises (par exemple, lors de la comparaison d'algorithmes).
Inconvénients : une seule mesure peut être aléatoire (GC, processus en arrière-plan). Vous devez l'exécuter plusieurs fois et faire la moyenne des résultats — c'est déjà ce que fait BenchmarkDotNet.
2. BenchmarkDotNet : La Référence pour les Tests de Performance
BenchmarkDotNet est une bibliothèque pour créer des benchmarks précis et reproductibles. Elle réchauffe automatiquement le JIT, évite l'influence du GC et fournit des statistiques détaillées.
Installation et Exemple de Base
// Installation: dotnet add package BenchmarkDotNetusing BenchmarkDotNet.Attributes;using BenchmarkDotNet.Running;
public class StringBenchmark{ private string _text = "Hello, World!"; [Benchmark] public bool ContainsWithOrdinal() => _text.Contains("World", StringComparison.Ordinal); [Benchmark] public bool ContainsWithInvariant() => _text.Contains("World", StringComparison.InvariantCulture);}
class Program{ static void Main() => BenchmarkRunner.Run<StringBenchmark>();}Le résultat montrera que Ordinal est 2 à 3 fois plus rapide. Sans benchmark, vous ne l'auriez pas remarqué.
Fonctionnalités Avancées
- Params : tester avec différentes tailles de données.
- MemoryDiagnoser : montre les allocations mémoire.
- Baseline : comparer les performances par rapport à une référence.
[MemoryDiagnoser]public class ListBenchmark{ [Params(100, 1000, 10000)] public int N; private List<int> _list; [GlobalSetup] public void Setup() => _list = Enumerable.Range(0, N).ToList(); [Benchmark(Baseline = true)] public int ForLoop() { int sum = 0; for (int i = 0; i < _list.Count; i++) sum += _list[i]; return sum; } [Benchmark] public int ForeachLoop() { int sum = 0; foreach (var item in _list) sum += item; return sum; }}3. Profilage Mémoire et GC
Les fuites mémoire et les nettoyages fréquents du garbage collector sont une cause courante de ralentissements dans .NET. Pour l'analyse, utilisez :