TinyProfiler

Vous est-il déjà arrivé d’évaluer le temps d’exécution d’un bout de code, à partir des logs ? Si oui et que vous trouvez cela laborieux, TinyProfiler est un exemple minimaliste (mais complet) pour mesurer le temps d’exécution par régions de code, en implémentant l’interface IDisposable.


Il est souvent nécessaire d’identifier les parties les moins performantes dans une application. Pour cela, les logs sont encore instructifs. Mais une fois une zone d’optimisation trouvée – par exemple: une région de code anormalement lente qui impact négativement une grande partie de l’expérience utilisateur -, on a besoin de circonscrire puis d’identifier précisément le code problématique. Soit l’application est assez simple ou assez bien faite pour que les traces se suffisent à elles-mêmes; soit il faut mettre en oeuvre une solution pour mesurer le temps consommé par régions de code.

Une solution que je présente ici consiste à profiler des régions de code (en termes de temps d’exécution) à partir d’un objet qui implémente l’interface IDisposable; cela permet une syntaxe claire avec le mot-clé using:

void MethodA() 
{
 using (var profiler = profilerFactory.Create("MethodA"))
 {
  using (var step1 = profiler.CreateChild("Step 1"))
  {
   // [...]
   SomeOperation();
   // [...]
  }
  using (var step2 = profiler.CreateChild("Step 2"))
  {
   // [...]
   SomeOperation();
   // [...]
  }
  using (var step2 = profiler.CreateChild("Step 3"))
  {
   // [...]
   SomeOperation();
   // [...]
  }
 }
}

/*
Output sample :
MethodA: 1204 ms
  Step 1: 50 ms
  Step 2: 998 ms (+50)
  Step 3: 156 ms (+1048)
*/

Les mesures peuvent aussi être imbriquées :

using (var profiler = profilerFactory.Create("MethodA"))
{
 using (var step1 = profiler.CreateChild("Step 1"))
 {
  using (var step1a = step1.CreateChild("Step 1a"))
  {
   // [...]
  }
 }
}

Bien sûr, l’idée n’est pas d’appliquer ce mécanisme à tout le code d’une application mais uniquement dans les régions déjà identifiées comme anormalement lentes.

Je connais l’excellent MiniProfiler, et le principe est le même (en très simplifié). Cependant j’avais besoin d’une solution similaire pour un projet non web, et qui soit légère en termes d’empreinte: sans référencer un assemblage supplémentaire.

Le code ci-dessous présente l’API (et c’est effectivement minimaliste):

    public interface IProfiler : IDisposable
    {
        IProfiler StartStep(string name);

        void Discard();
    }

    public interface IProfilerFactory
    {
        IProfiler StartProfiling(string name);
    }

Une implémentation complète est disponible sur GitHub et sur Nuget, sous forme de code source uniquement, pas de nouvelle référence requise. Dernière précision: compatible .NET 3.5.