Skip to content

Latest commit

 

History

History
398 lines (283 loc) · 11.1 KB

File metadata and controls

398 lines (283 loc) · 11.1 KB

🔝 Retour au Sommaire

18.4.1 Profiling Windows (DProf)

Introduction au Profiling

Le profiling est une technique qui permet d'analyser les performances de votre application en identifiant les parties du code qui consomment le plus de temps d'exécution ou de ressources. C'est un outil essentiel pour optimiser vos programmes.

Pourquoi faire du profiling ?

  • Identifier les goulots d'étranglement : découvrir quelles fonctions ralentissent votre application
  • Optimiser de manière ciblée : concentrer vos efforts là où ils auront le plus d'impact
  • Mesurer l'amélioration : vérifier que vos optimisations sont efficaces
  • Comprendre le comportement : voir comment votre code s'exécute réellement

Qu'est-ce que DProf ?

DProf (Delphi Profiler) est un outil de profiling compatible avec FreePascal sur Windows. Il analyse votre programme pendant son exécution et génère un rapport détaillé sur :

  • Le temps passé dans chaque fonction
  • Le nombre d'appels de chaque fonction
  • La hiérarchie des appels (qui appelle quoi)

Installation et Configuration

Prérequis

DProf nécessite :

  • FreePascal/Lazarus installé sur Windows
  • Votre projet doit être compilé avec des options spéciales
  • L'outil DProf.exe (généralement fourni avec certaines distributions ou téléchargeable séparément)

Configuration du Projet

Pour que votre programme puisse être profilé avec DProf, vous devez le compiler avec des informations de débogage spéciales.

Dans Lazarus IDE

  1. Ouvrez votre projet

  2. Allez dans Projet → Options du projet

  3. Section Compilation et liaison :

    • Cochez Générer les informations de débogage pour GDB
    • Cochez Utiliser Heaptrc (optionnel, pour le suivi mémoire)
  4. Section Options du compilateur personnalisées : Ajoutez ces options :

    -pg
    

En ligne de commande

Compilez votre projet avec l'option -pg :

fpc -pg -gl MonProgramme.pas

Explications des options :

  • -pg : Active l'instrumentation pour le profiling (génère du code supplémentaire qui enregistre les appels)
  • -gl : Inclut les informations de ligne pour un débogage détaillé

Utilisation de DProf

Étape 1 : Exécuter votre Programme

Une fois compilé avec -pg, exécutez normalement votre programme :

MonProgramme.exe

Pendant l'exécution, le programme génère automatiquement un fichier gmon.out dans le répertoire courant. Ce fichier contient toutes les données de profiling brutes.

Important : Le fichier gmon.out est écrasé à chaque exécution, donc sauvegardez-le si vous voulez comparer plusieurs sessions.

Étape 2 : Analyser avec gprof

Sur Windows, vous utilisez gprof (GNU Profiler) pour lire le fichier gmon.out :

gprof MonProgramme.exe gmon.out > rapport_profiling.txt

Cette commande génère un rapport texte lisible.

Étape 3 : Analyser avec DProf (interface graphique)

Si vous avez DProf.exe :

dprof MonProgramme.exe gmon.out

DProf ouvre une interface graphique qui affiche :

  • La liste des fonctions triées par temps d'exécution
  • Des graphiques de répartition du temps
  • L'arbre d'appels (call graph)

Comprendre le Rapport de Profiling

Structure du Rapport gprof

Le rapport gprof contient trois sections principales :

1. Flat Profile (Profil Plat)

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
 45.20      1.35     1.35   100000     0.01     0.02  CalculComplexe
 23.40      2.05     0.70    50000     0.01     0.01  TrierTableau
 12.70      2.43     0.38   200000     0.00     0.00  RechercherElement

Colonnes expliquées :

  • % time : Pourcentage du temps total passé dans cette fonction
  • cumulative seconds : Temps cumulé depuis le début du rapport
  • self seconds : Temps passé uniquement dans cette fonction (sans les sous-fonctions)
  • calls : Nombre de fois que la fonction a été appelée
  • self ms/call : Temps moyen par appel (en millisecondes)
  • total ms/call : Temps moyen incluant les sous-fonctions
  • name : Nom de la fonction

2. Call Graph (Graphe d'Appels)

index % time    self  children    called     name
[1]    68.3    1.35     0.70  100000/100000      Principal [2]
              0.70     0.00   50000/50000       TrierTableau [3]
-----------------------------------------------
              1.35     0.70  100000/100000      Principal [2]
[2]    68.3    1.35     0.70                   CalculComplexe [1]
              0.70     0.00   50000/50000       TrierTableau [3]

Cette section montre :

  • Qui appelle chaque fonction (parents)
  • Quelles fonctions sont appelées (enfants)
  • La distribution du temps entre appelants et appelés

3. Index des Fonctions

Une liste alphabétique de toutes les fonctions avec leur index pour référence croisée.

Interpréter les Résultats

Identifier les Fonctions Critiques

Les fonctions à optimiser en priorité sont celles qui ont :

  1. Un % time élevé (>10% du temps total)
  2. Un grand nombre d'appels avec un temps self significatif
  3. Un temps total élevé même si le temps self est faible (elles appellent des fonctions lentes)

Exemple d'Analyse

Si vous voyez :

 45.20    1.35     1.35   100000     0.01     0.02  CalculComplexe

Interprétation :

  • Cette fonction consomme 45% du temps total d'exécution
  • Elle est appelée 100 000 fois
  • Chaque appel prend en moyenne 0.01 ms
  • Action : C'est la priorité numéro 1 pour l'optimisation

Si vous voyez :

  2.10    2.50     0.06        1    60.00   2500.00  FonctionPrincipale

Interprétation :

  • Cette fonction ne prend que 2% du temps directement
  • Mais le temps total incluant les sous-fonctions est de 2500 ms
  • Elle est appelée une seule fois
  • Action : Le problème vient des fonctions qu'elle appelle, pas d'elle-même

Optimisations Courantes

1. Réduire le Nombre d'Appels

Si une fonction est appelée très fréquemment avec un temps faible :

Avant :

for i := 1 to 10000 do  
begin
  valeur := ObtenirConfiguration('cle'); // Appelé 10000 fois
  Traiter(valeur);
end;

Après :

valeur := ObtenirConfiguration('cle'); // Appelé 1 fois  
for i := 1 to 10000 do  
begin
  Traiter(valeur);
end;

2. Optimiser les Algorithmes

Si une fonction a un temps self élevé, améliorez son algorithme :

Avant (O(n²)) :

function Rechercher(tableau: array of Integer; valeur: Integer): Integer;  
var
  i: Integer;
begin
  for i := 0 to High(tableau) do
    if tableau[i] = valeur then
      Exit(i);
  Result := -1;
end;

Après (utiliser une structure appropriée) :

// Utiliser un TDictionary pour O(1) au lieu de O(n)
var
  dictionnaire: TDictionary<Integer, Integer>;

3. Mise en Cache

Si une fonction calcule souvent la même chose :

var
  CacheResultats: TDictionary<string, Integer>;

function CalculCouteux(parametre: string): Integer;  
begin
  if CacheResultats.ContainsKey(parametre) then
    Exit(CacheResultats[parametre]); // Retour immédiat

  // Calcul complexe uniquement si pas en cache
  Result := FaireCalculComplexe(parametre);
  CacheResultats.Add(parametre, Result);
end;

Conseils et Bonnes Pratiques

1. Profilez le Code Réel

  • Utilisez des données réalistes, pas des données de test minimales
  • Profilez le scénario d'utilisation typique de votre application
  • Exécutez suffisamment longtemps pour obtenir des statistiques significatives

2. Profilez en Mode Release

Compilez avec optimisations activées (-O2 ou -O3) pour profiler le code tel qu'il sera en production :

fpc -pg -O2 MonProgramme.pas

3. Concentrez-vous sur les 20%

La règle des 80/20 s'applique : généralement 20% du code consomme 80% du temps. Concentrez-vous sur ces 20%.

4. Mesurez Avant et Après

Toujours profiler avant et après une optimisation pour vérifier son efficacité :

# Avant optimisation
gprof MonProgramme.exe gmon.out > avant.txt

# Après optimisation
gprof MonProgramme.exe gmon.out > apres.txt

# Comparer les deux fichiers

5. Attention aux Effets de Bord

Le profiling lui-même ajoute de l'overhead (surcoût). Le code avec -pg est environ 10-20% plus lent que le code normal. C'est normal, les temps relatifs restent corrects.

Limitations de DProf/gprof

Ce que gprof ne fait pas

  • Profiling de la mémoire : gprof mesure uniquement le temps CPU, pas l'utilisation mémoire
  • Profiling multi-thread : les résultats peuvent être imprécis pour les applications multi-threadées
  • Profiling temps réel : gprof compte les échantillons CPU, pas le temps réel (temps d'attente I/O non compté)

Alternatives sur Windows

Pour des besoins avancés :

  • Valgrind (via WSL) : profiling mémoire et cache
  • Intel VTune : profiling très détaillé (commercial)
  • Very Sleepy : profiler simple et gratuit pour Windows
  • AQtime : profiler commercial avec interface graphique avancée

Workflow Complet d'Optimisation

  1. Identifier le problème : "Mon programme est lent"
  2. Profiler : Compiler avec -pg et exécuter
  3. Analyser : Identifier les fonctions critiques avec gprof
  4. Optimiser : Améliorer le code des fonctions identifiées
  5. Re-profiler : Vérifier l'amélioration
  6. Répéter : Continuer jusqu'à atteindre les performances souhaitées

Exemple Complet

Code à profiler

program ExempleProfilage;

{$mode objfpc}{$H+}

uses
  SysUtils;

function Fibonacci(n: Integer): Int64;  
begin
  if n <= 1 then
    Exit(n)
  else
    Result := Fibonacci(n-1) + Fibonacci(n-2);
end;

function FibonacciOptimise(n: Integer): Int64;  
var
  a, b, i: Int64;
begin
  if n <= 1 then Exit(n);
  a := 0;
  b := 1;
  for i := 2 to n do
  begin
    Result := a + b;
    a := b;
    b := Result;
  end;
end;

var
  i: Integer;
  debut, fin: TDateTime;
begin
  WriteLn('Test Fibonacci récursif...');
  debut := Now;
  for i := 1 to 35 do
    Fibonacci(i);
  fin := Now;
  WriteLn('Temps: ', MilliSecondsBetween(fin, debut), ' ms');

  WriteLn('Test Fibonacci optimisé...');
  debut := Now;
  for i := 1 to 35 do
    FibonacciOptimise(i);
  fin := Now;
  WriteLn('Temps: ', MilliSecondsBetween(fin, debut), ' ms');
end.

Compilation et Profiling

# Compiler avec profiling
fpc -pg -gl ExempleProfilage.pas

# Exécuter
ExempleProfilage.exe

# Analyser
gprof ExempleProfilage.exe gmon.out > rapport.txt

Résultat Attendu

Le rapport montrera clairement que Fibonacci consomme beaucoup plus de temps que FibonacciOptimise, démontrant l'importance de l'algorithme choisi.

Conclusion

Le profiling avec DProf/gprof sur Windows est un outil puissant mais simple pour :

  • Mesurer objectivement les performances
  • Identifier précisément les problèmes
  • Guider intelligemment vos optimisations

N'optimisez jamais à l'aveugle : mesurez d'abord, optimisez ensuite, et mesurez à nouveau pour confirmer l'amélioration.

Règle d'or : "On n'optimise pas ce qu'on ne mesure pas !"

⏭️ Profiling Linux (gprof, Valgrind)