1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
|
<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
<!ENTITY tdecachegrind '<application>KCachegrind</application>'>
<!ENTITY cachegrind "<application>Cachegrind</application>">
<!ENTITY calltree "<application>Calltree</application>">
<!ENTITY callgrind "<application>Callgrind</application>">
<!ENTITY valgrind "<application>Valgrind</application>">
<!ENTITY oprofile "<application>OProfile</application>">
<!ENTITY kappname "&tdecachegrind;">
<!ENTITY package "tdesdk">
<!ENTITY % addindex "IGNORE">
<!ENTITY % French "INCLUDE">
]>
<!-- ................................................................ -->
<book lang="&language;">
<bookinfo>
<title>Manuel de &tdecachegrind;</title>
<authorgroup>
<author><firstname>Josef</firstname> <surname>Weidendorfer</surname> <affiliation> <address><email>Josef.Weidendorfer@gmx.de</email></address>
</affiliation>
</author>
&traducteurYannVerley; &traducteurLudovicGrossard; &traducteurDamienRaudeMorvan;
</authorgroup>
<copyright>
<year>2002-2004</year>
<holder>Josef Weidendorfer</holder>
</copyright>
<legalnotice>&FDLNotice;</legalnotice>
<date>2004-07-27</date>
<releaseinfo>0.4.6</releaseinfo>
<abstract>
<para>&tdecachegrind; est un outil de visualisation de données de profilage écrit pour l'environnement &kde;. </para>
</abstract>
<keywordset>
<keyword>KDE</keyword>
<keyword>tdesdk</keyword>
<keyword>Cachegrind</keyword>
<keyword>Callgrind</keyword>
<keyword>Valgrind</keyword>
<keyword>Profilage</keyword>
</keywordset>
</bookinfo>
<chapter id="introduction">
<title>Introduction</title>
<para>&kappname; est un navigateur pour les données produites par des outils de profilage. Ce chapitre explique à quoi sert le profilage, comment cela fonctionne, et donne quelques exemples d'outils de profilage disponibles. </para>
<sect1 id="introduction-profiling">
<title>Profilage</title>
<para>Habituellement, quand on développe un programme, une des dernières étapes est d'optimiser les performances. C'est une perte de temps d'optimiser les fonctions rarement utilisées. Il est donc intéressant de savoir où votre programme passe le plus de temps. </para>
<para>Pour du code séquentiel, la récupération des données statistiques des caractéristiques de l'exécution des programmes, comme par exemple le temps passé dans les fonctions ou dans les lignes de code est habituellement suffisant. C'est ce que l'on appelle le profilage. Le programme est exécuté sous le contrôle d'un outil de profilage, qui donne les résultats de l'exécution à la fin. Au contraire, pour du code parallèle, les problèmes de performance proviennent généralement de l'attente par un processeur de données d'un autre processeur. Comme ce temps d'attente ne peut habituellement être facilement attribué, il est préférable de générer ici des traces d'évènements horodatées. KCachegrind ne peut pas visualiser ce type de données. </para>
<para>Après analyse des données de profilage produites, il devrait être plus facile de voir les points chauds et les goulots d'étranglement du code. Par exemple, on peut vérifier les hypothèses par rapport au nombre d'appels, et les régions identifiées du code peuvent être optimisées. Après cela, on doit valider l'optimisation effectuée avec une autre exécution profilée. </para>
</sect1>
<sect1 id="introduction-methods">
<title>Méthodes de profilage</title>
<para>La mesure exacte du temps passé par des événements se produisant pendant l'exécution d'une région de code (par exemple, une fonction) nécessite que soit effectué un rajout de code de mesure avant et après cette région. Ce code lit le temps ou bien un compteur global d'évènement, et calcule les différences. Le code original doit ainsi être changé avant l'exécution. C'est ce que l'on appelle l'instrumentation. L'instrumentation peut être faite par le programmeur lui-même, le compilateur, ou bien par le système d'exécution. Comme les régions intéressantes sont généralement imbriquées, la surcharge due à la mesure influence toujours la mesure elle-même. Ainsi, l'instrumentation doit être effectuée sélectivement et les résultats doivent être interprétés avec précaution. Bien sûr, ceci fait que l'analyse des performances se basant sur la mesure exacte est un processus très complexe.</para>
<para>La mesure exacte est possible grâce à des compteurs matériels (ce qui inclut des compteurs s'incrémentant sur un tic de temps) fournis dans les processeurs modernes et qui sont incrémentés quand un évènement se produit. Comme nous voulons attribuer des évènements à des régions de code, sans utiliser de compteurs, nous devons gérer chaque évènement en incrémentant un compteur pour la région de code courante nous-mêmes. Faire ceci au niveau logiciel n'est bien sûr pas possible. Toutefois, si on part de l'hypothèse que la distribution des évènements sur le code source est identique quand on regarde à chaque nième évènement, au lieu de chaque évènement, nous avons construit une méthode de mesure réglable par rapport à la surcharge induite. C'est ce que l'on appelle l'échantillonnage. L'échantillonnage à base de temps (NdT : Time Based Sampling ou TBS) utilise un temporisateur pour regarder régulièrement le compteur de programme, afin de créer un histogramme sur le code du programme. L'échantillonnage à base d'évènements (NdT : Event Based Sampling ou EBS) se sert des compteurs matériels des processeurs modernes et utilise un mode dans lequel le gestionnaire d'interruptions est appelé sur les valeurs basses du compteur, en générant un histogramme de la distribution d'évènements correspondante. Dans le gestionnaire, le compteur d'évènement est toujours réinitialisé au « n » de la méthode d'échantillonnage. L'avantage de l'échantillonnage est que le code n'a pas besoin d'être modifié, mais ceci reste un compromis : la supposition d'au-dessus est correcte si n est petit, mais plus n est petit, plus la surcharge du gestionnaire d'interruptions est importante.</para>
<para>Il existe une autre méthode de mesure qui est de simuler ce qui arrive au niveau de l'ordinateur quand on exécute un code donné, c'est-à-dire une simulation contrôlée de code. La simulation est toujours dépendante du modèle de la machine qui est plus ou moins précis. Cependant, pour des modèles très détaillés de machine, s'approchant de la réalité, le temps de simulation peut être assez inacceptable pour une utilisation courante. L'avantage est que l'on peut insérer dans un code donné un code de mesure/simulation aussi complexe qu'il soit sans perturber les résultats. Faire ceci directement avant l'exécution (ce que l'on appelle instrumentation dynamique), en utilisant le binaire original, est très confortable pour l'utilisateur : Aucune recompilation n'est nécessaire. Cette méthode devient utilisable quand on ne simule que quelques parties de la machine avec un modèle simple. En outre, les résultats produits par des modèles simples sont souvent plus faciles à comprendre : le problème fréquent avec le vrai matériel est que les résultats incluent des effets de chevauchement de différentes parties de la machine.</para>
</sect1>
<sect1 id="introduction-tools">
<title>Outils de profilage</title>
<para>Le plus connu des outils de profilage est l'outil de la suite GCC, <application>gprof</application> : On doit compiler le programme avec l'option <option>-pg</option> ; le lancement du programme génère un fichier <filename>gmon.out</filename>, que l'utilisateur peut lire avec <command>gprof</command>. L'inconvénient principal de cette méthode est l'obligation de passer par une recompilation pour préparer l'exécutable, qui doit être lié de façon statique. La méthode utilisée ici est l'instrumentation générée par le compilateur. Celle-ci mesure les arcs d'appels se produisant dans les fonctions et en accord avec des compteurs d'appels, en conjonction avec un TBS, qui donne un histogramme de distribution du temps sur le code. En utilisant les deux informations, il est possible de calculer de manière heuristique le temps d'inclusion des fonctions, c'est-à-dire le temps passé dans une fonction ainsi que toutes les fonctions qu'elle a appelées. </para>
<para>Pour une mesure exacte des évènements, il existe des librairies avec des fonctions capables de lire les compteurs de performance matériels. Les plus connus sont le patch PerfCtr pour Linux et les librairies indépendantes de l'architecture PAPI et PCL. Comme toujours, une mesure exacte nécessite une instrumentation du code, comme indiqué au-dessus. D'autres utilisent les librairies elles-mêmes ou utilisent des systèmes d'instrumentation automatiques comme ADAPTOR (pour l'instrumentation de sources FORTRAN), ou encore DynaProf (injection de code par DynInst).</para>
<para>&oprofile; est un outil de profilage au niveau système pour Linux utilisant l'échantillonnage.</para>
<para>Dans beaucoup d'aspects, une manière agréable de profiler est d'utiliser Cachegrind ou Callgrind, qui sont des simulateurs utilisant l'environnement d'instrumentation d'exécution &valgrind;. Comme il n'y a pas besoin d'accéder aux compteurs hardware (souvent difficile avec les installations de Linux actuelles), et comme les binaires devant être profilés n'ont pas besoin d'être modifiés, ceci est une bonne alternative à d'autres outils de profilage. L'inconvénient du ralentissement dû à la simulation peut être réduit en n'effectuant la simulation que sur les parties intéressantes du programme, et peut-être seulement sur quelques itérations d'une boucle. Sans instrumentation de la mesure/simulation, l'usage de Valgrind ne provoque qu'un ralentissement d'un facteur de 3 à 5. Et si on n'est intéressé que par l'arbre d'appels et le nombre d'appels, le simulateur du cache peut être désactivé. </para>
<para>La simulation du cache est la première étape dans l'approximation des temps réels. En effet, sur les systèmes modernes, l'exécution est très sensible à l'utilisation de ce que l'on appelle des caches (zones de mémoire petites et rapides, et qui permettent d'accélérer les accès répétés aux mêmes emplacements mémoire). &cachegrind; fait cette simulation du cache en interceptant les accès mémoires. Les données produites incluent le nombre d'accès sur la mémoire des instructions / des données, les échecs des caches de niveau L1 / L2, et elle met en relation les lignes du code source avec les fonctions du programme exécuté. En combinant ces compteurs d'échecs et en utilisant des temps de latence de processeurs connus, on peut faire une estimation du temps passé. </para>
<para>Callgrind est une extension de &cachegrind; qui construit l'arbre d'appels d'un programme à la volée, &cad; comment les fonctions s'appellent entre elles et combien d'évènements se produisent lors de l'exécution d'une fonction. De plus, les données de profilage devant être collectées peuvent être divisées en threads ou en contextes de chaînes d'appels. Il peut aussi fournir des données de profilage au niveau instruction afin de permettre l'annotation d'un code désassemblé. </para>
</sect1>
<sect1 id="introduction-visualization">
<title>Visualisation</title>
<para>Les outils de profilage produisent typiquement un nombre important de données. Le souhait de naviguer facilement dans l'arbre d'appels, ainsi que de passer rapidement d'un mode de tri des fonctions et d'affichage des différents types d'évènements, a motivé la création d'une application graphique pour accomplir cela. </para>
<para>&kappname; est un outil de visualisation de données de profilage permettant d'accomplir ces souhaits. Il a été programmé en premier lieu pour naviguer dans les données de &cachegrind; et &calltree;. Il existe toutefois des convertisseurs permettant d'afficher les données de profilage produites par d'autres outils. Une description du format des fichiers Cachegrind/Callgrind est donnée dans l'appendice. </para>
<para>En plus d'une liste de fonctions triées en fonction des métriques des coûts inclusifs ou exclusifs, et optionnellement groupées par fichier source, librairie partagée ou classe C++, &kappname; propose des vues différentes et variées pour une fonction sélectionnée, à savoir <itemizedlist>
<listitem><para>une vue de l'arbre d'appel, qui montre une section de l'arbre d'appel autour de la fonction sélectionnée,</para>
</listitem>
<listitem><para>une vue de la carte de l'arbre, qui permet de visualiser la relation entre appels imbriqués ainsi que la métrique du coût inclusif pour détecter visuellement et rapidement les fonctions à problèmes,</para>
</listitem>
<listitem><para>les vues du code source et de l'annotation assembleur, permettant de voir les détails des coûts associés aux lignes du code source et des instructions assembleur.</para>
</listitem>
</itemizedlist>
</para>
</sect1>
</chapter>
<chapter id="using-tdecachegrind">
<title>Utiliser &tdecachegrind;</title>
<sect1 id="using-profile">
<title>Générer les données à visualiser</title>
<para>Tout d'abord, il faut générer les données de performance en mesurant les aspects des caractéristiques de l'exécution d'une application. Pour cela, il faut utiliser un outil de profilage. &tdecachegrind; n'inclut pas d'outil de profilage, mais est prévu pour fonctionner avec &callgrind;. En utilisant un convertisseur, il peut aussi être utilisé pour visualiser les données produites par &oprofile;. Même si l'objectif de ce manuel n'est pas de documenter le profilage avec ces outils, la prochaine section fournit des petits tutoriels afin que vous puissiez démarrer. </para>
<sect2>
<title>&callgrind;</title>
<para>&callgrind; est disponible sur <ulink url="http://tdecachegrind.sf.net"> http://tdecachegrind.sf.net</ulink>. Notez qu'il était précédemment nommé &calltree;, mais ce nom était trompeur. </para>
<para>L'usage le plus courant est de démarrer votre application en préfixant la ligne de commande par <application>callgrind</application>, comme par exemple <blockquote><para><command>callgrind le_programme les_arguments</command></para></blockquote> À la fin du programme, le fichier <filename>callgrind.out.pid</filename> est généré. Ce fichier peut être chargé avec &tdecachegrind;. </para>
<para>Un usage plus avancé est de générer des données de profilage quand une fonction donnée de votre application est appelée. Par exemple, pour <command>konqueror</command>, pour n'avoir les données de profilage que pour le rendu d'une page web, vous pouvez décider de générer les données quand vous sélectionnez l'élément du menu Affichage/Recharger. Ceci correspond à un appel à <symbol>KonqMainWindow::slotReload</symbol>. Utilisez la commande <blockquote><para><command>callgrind --dump-before=KonqMainWindow::slotReload konqueror</command></para></blockquote> Ceci va produire plusieurs fichiers de données de profilage avec un numéro additionnel séquentiel à la fin du nom du fichier. Un fichier sans un tel nombre à la fin (se terminant seulement par le PID du processus) sera aussi produit. En chargeant ce fichier dans &tdecachegrind;, tous les autres fichiers seront aussi chargés, et peuvent être visualisés dans la synthèse des parties et dans la liste des parties. </para>
</sect2>
<sect2>
<title>&oprofile;</title>
<para>&oprofile; est disponible sur <ulink url="http://oprofile.sf.net"> http://oprofile.sf.net</ulink>. Suivez les instructions d'installation du site web. Veuillez vérifier toutefois si votre distribution ne le fournit pas déjà en tant que paquetage (comme dans Suse). </para>
<para>Le profilage au niveau système n'est autorisé que pour l'administrateur, car toutes les actions sur le système peuvent être observées. C'est pourquoi ce qui va suivre doit être fait en tant qu'administrateur. Tout d'abord, configurez le processus de profilage, en utilisant l'interface graphique <command>oprof_start</command> ou l'outil en ligne de commande <command>opcontrol</command>. Une configuration standard devrait être le mode temps (TBS, voir introduction). Pour démarrer la mesure, lancez <command>opcontrol -s</command>. Ensuite lancez l'application à profiler, et après, lancez <command>opcontrol -d</command>. Ceci va écrire les résultats de la mesure dans des fichiers sous le dossier <filename>/var/lib/oprofile/samples/</filename>. Pour pouvoir visualiser les données dans &tdecachegrind;, lancez la commande suivante dans un dossier vide : <blockquote><para><command> opreport -gdf | op2callgrind </command></para></blockquote> Ceci va produire un nombre important de fichiers, un pour chaque programme qui s'exécutait sur le système. Chacun peut être chargé indépendamment dans &tdecachegrind;. </para>
</sect2>
</sect1>
<sect1 id="using-basics">
<title>Bases de l'interface utilisateur</title>
<para>Quand vous lancez &tdecachegrind; avec un fichier de données de profilage en tant qu'argument, ou après en avoir chargé un avec Fichier/Ouvrir, vous verrez une barre sur le côté contenant la liste des fonctions à gauche et, à droite de la partie principale, une aire de visualisation pour la fonction sélectionnée. L'aire de visualisation peut être configurée pour afficher plusieurs visualisations dans une seule. </para>
<para>Au premier démarrage, cette aire peut être divisée en deux parties séparées horizontalement, chacune avec des visualisations différentes sélectionnables par des onglets. Pour bouger les vues de visualisation, utilisez le menu contextuel de chaque onglet, et ajustez les séparations entre les visualisations. Pour commuter rapidement entre les différentes dispositions d'une visualisation, utilisez le menu Affichage/Disposition des vues/Dupliquer et changez la disposition. Vous pouvez ensuite commuter les dispositions avec le menu Affichage/Disposition des vues/Aller à la disposition suivante (ou mieux, en utilisant les raccourcis clavier). </para>
<para>Le type d'évènement actif est important pour la visualisation : pour &callgrind;, c'est par exemple le nombre d'échecs du cache ou l'estimation du cycle ; pour &oprofile;, c'est le « temps » dans le plus simple cas. Vous pouvez changer le type d'évènement par une combobox dans la barre d'outils ou dans la vue du type de l'évènement. Un premier aperçu des caractéristiques de l'exécution devrait être donné quand vous sélectionnez la fonction <symbol>main</symbol> dans la liste de gauche, et regardez la visualisation de l'arbre d'appels. Là vous voyez les appels se produisant dans votre programme. Notez que la vue du graphe d'appels ne montre que les fonctions avec un nombre d'évènements élevé. En double-cliquant sur une fonction dans le graphe, celui-ci change pour afficher les fonctions appelées autour de celle sélectionnée. </para>
<para>Pour explorer plus profondément l'interface graphique, vous pouvez regarder, en plus de ce manuel, la section documentation du site web <ulink url="http://tdecachegrind.sf.net"> http://tdecachegrind.sf.net</ulink>. De plus, chaque composant de &tdecachegrind; est fourni avec l'aide <quote>Qu'est-ce que c'est ?</quote>. </para>
</sect1>
</chapter>
<chapter id="tdecachegrind-concepts">
<title>Concepts de base</title>
<para>Ce chapitre explique quelques concepts de &tdecachegrind;, et introduit les termes utilisés dans l'interface. </para>
<sect1 id="concepts-model">
<title>Le modèle de données pour les données de profilage</title>
<sect2>
<title>Entités de coût</title>
<para>Les compteurs de coût des types d'évènement (comme les échecs du cache L2) sont attribués aux entités de coût, qui sont des éléments en relation avec le code source ou des structures de données d'un programme donné. Les entités de coût ne sont pas seulement un code simple ou des positions de données, mais aussi des tuples de position. Par exemple, un appel a une source et une cible, ou bien une adresse de données peut avoir un type de données et une position dans le code où son allocation s'est effectuée. </para>
<para>Les entités de coût connues de KCachegrind sont données ci-dessous. Les positions simples : <itemizedlist><listitem><para> instruction. Une instruction assembleur à l'adresse spécifiée. </para></listitem><listitem><para>Ligne dans le source d'une fonction. Toutes les instructions que le compilateur (par l'intermédiaire des informations de débogage) associe à une ligne donnée spécifiée par le nom du fichier source et le numéro de la ligne, et qui sont exécutées dans le contexte de quelques fonctions. Le dernier est nécessaire parce qu'une ligne source à l'intérieur d'une fonction inline peut apparaître dans le contexte de fonctions multiples. Les instructions sans association avec une ligne du code source courant sont associées à la ligne numéro 0 du fichier « ??? ». </para></listitem> <listitem><para>Fonction. Toutes les lignes d'une fonction donnée constituent la fonction elle-même. Une fonction est spécifiée, s'ils sont disponibles, par son nom et sa position dans quelques objets binaires. La dernière est nécessaire parce que les objets binaires d'un seul programme peut avoir des fonctions avec le même nom (on peut y accéder par exemple avec dlopen/dlsym ; l'éditeur de lien dynamique résout les fonctions dans un ordre de recherche donné dans les objets binaires utilisés). Si un outil de profilage ne peut détecter le nom du symbole d'une fonction, par exemple parce que l'information de débogage n'est pas disponible, soit l'adresse de la première instruction exécutée est utilisée, soit « ??? ». </para></listitem><listitem><para>Objet binaire. Toutes les fonctions dont le code se situe à l'intérieur d'un objet binaire, ou bien l'exécutable principal (NdT : « main »), ou encore une librairie partagée. </para></listitem><listitem><para>Fichier source. Toutes les fonctions dont la première instruction est associée à une ligne d'un fichier source donné. </para></listitem><listitem><para>Classe. Les noms des symboles des fonctions sont généralement ordonnés hiérarchiquement dans des espaces de nommage, par exemple les espaces de nommage C++, ou les classes des langages orientés objet. Ainsi une classe peut contenir des fonctions d'une classe ou de classes embarquées. </para></listitem><listitem><para>Partie d'un profilage. Quelques sections de temps d'une exécution de profilage, avec un identifiant de thread donné, un identifiant de processus, et la ligne de commande exécutée. </para></listitem></itemizedlist> Vu en tant que liste, un ensemble d'entités de coût définit souvent une autre entité de coût. Ainsi il y a une hiérarchie d'imbrication des entités de coût qui semble évidente par rapport à la description faite au-dessus. </para>
<para>Tuples des positions : <itemizedlist><listitem><para>Appel d'une adresse d'instruction vers une fonction cible. </para></listitem><listitem><para> Appel d'une ligne du source vers une fonction cible. </para></listitem><listitem><para> Appel d'une fonction du source vers une fonction cible. </para></listitem><listitem><para>Saut (in)conditionnel d'une source vers une instruction cible. </para></listitem><listitem><para>Saut (in)conditionnel d'une source vers une ligne cible. </para></listitem></itemizedlist>Les sauts entre les fonctions ne sont pas autorisés, car cela est absurde dans un arbre d'appels. Ainsi, les constructions telles la gestion des exceptions et les sauts longs en C doivent être traduits pour se mettre dans la pile d'appels comme demandé. </para>
</sect2>
<sect2>
<title>Types d'évènement</title>
<para>Des types d'évènements arbitraires peuvent être spécifiés dans les données de profilage en leur donnant un nom. Leur coût relié à une entité de coût est un entier sur 64 bits. </para>
<para>Les types d'évènement dont les coûts sont spécifiés dans le fichier de données de profilage sont appelés évènement réels. En plus, on peut spécifier des formules pour les types d'évènement calculés à partir d'évènement réels, que l'on appelle évènements hérités. </para>
</sect2>
</sect1>
<sect1 id="concepts-state">
<title>État de la visualisation</title>
<para>L'état de la visualisation de la fenêtre de KCachegrind inclut : <itemizedlist><listitem><para>le type d'évènement primaire et secondaire choisi pour l'affichage, </para></listitem><listitem><para>le regroupement de fonction (utilisé dans la liste Profilage des fonctions et dans la coloration des entités), </para></listitem><listitem><para>les parties du profilage dont les coûts doivent être inclus dans la visualisation, </para></listitem><listitem><para>une entité active de coût (par exemple, une fonction sélectionnée de la barre latérale Profilage de la fonction), </para></listitem><listitem><para>une entité de coût sélectionnée.</para></listitem></itemizedlist> Cet état influence les visualisations. </para>
<para>Les visualisations sont toujours affichées pour une entité de coût, celle qui est active. Quand une visualisation donnée n'est pas appropriée pour une entité de coût, elle peut être désactivée (par exemple quand on sélectionne un objet ELF en double-cliquant dans la liste des groupes, l'annotation du code source pour un objet ELF ne veut rien dire). </para>
<para>Par exemple, pour une fonction active, la liste des fonctions appelées montre toutes les fonctions appelées par la fonction active. On peut sélectionner chacune de ces fonctions sans la rendre active. Si le graphe d'appels est montré à côté, il va automatiquement sélectionner la même fonction. </para>
</sect1>
<sect1 id="concepts-guiparts">
<title>Parties de l'interface graphique</title>
<sect2>
<title>Barres latérales</title>
<para>Les barres latérales sont des fenêtres de côté qui peuvent être placées à chaque bordure de la fenêtre de KCachegrind. Elles contiennent toujours une liste d'entités de coût triées d'une manière quelconque. <itemizedlist>
<listitem><para>Le profil d'une fonction. Le profil d'une fonction est une liste des fonctions avec les coûts inclusifs et exclusifs, le nombre d'appels, le nom et la position des fonctions. </para></listitem>
<listitem><para>Synthèse des parties </para></listitem>
<listitem><para>Pile d'appels </para></listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Aire de visualisation</title>
<para>L'aire de visualisation, se situant généralement dans la partie droite de la fenêtre principale de KCachegrind, est constituée d'une (par défaut) ou de plusieurs vues d'onglets, rangées horizontalement ou verticalement. Chaque vue d'onglet contient plusieurs vues différentes de visualisation pour une seule entité de coût à un instant donné. Le nom de cette entité est indiqué en haut de la vue d'onglets. S'il y a plusieurs vues d'onglets, seulement une est active. Le nom de l'entité dans la vue d'onglets active est affiché en gras et détermine l'entité de coût active de la fenêtre de KCachegrind. </para>
</sect2>
<sect2>
<title>Aires d'une vue d'onglets</title>
<para>Chaque vue d'onglets peut contenir jusqu'à quatre aires d'affichage, nommées Haut, Droite, Gauche, Bas. Chaque aire peut contenir plusieurs vues empilées de visualisation. La vue visible d'une aire est sélectionnée par la barre d'onglets. Les barres d'onglets de l'aire en haut à droite sont en haut, les barres d'onglets de l'aire en bas à gauche sont en bas. Vous pouvez spécifier quel type de visualisation doit aller dans chaque aire en utilisant les menus contextuels des onglets. </para>
</sect2>
<sect2>
<title>Visualisation synchronisée par une entité sélectionnée dans une vue des onglets</title>
<para>En plus d'une entité active, chaque vue d'onglets a une entité sélectionnée. Comme la plupart des types de visualisations montre plusieurs entités avec celle qui est active centrée, vous pouvez changer l'élément sélectionné en naviguant dans une visualisation (en cliquant avec la souris ou en utilisant le clavier). Généralement, les éléments sélectionnés sont affichés en surbrillance. En changeant l'entité sélectionnée dans une des visualisations de la vue d'onglets, toutes les autres visualisations dans la vue d'onglets mettent par conséquent la nouvelle entité sélectionnée en surbrillance. </para>
</sect2>
<sect2>
<title>Synchronisation entre les vues d'onglets</title>
<para>Si il y a plusieurs vues d'onglets, un changement de sélection dans une des vues d'onglets mène à un changement d'activation dans la vue d'onglets suivante (à droite/en bas). Cette sorte de lien doit permettre, par exemple, de naviguer rapidement dans les graphes d'appels. </para>
</sect2>
<sect2>
<title>Dispositions</title>
<para>La disposition de toutes les vues d'onglets d'une fenêtre peut être enregistrée (voir dans le menu Affichage/Disposition des vues). Après avoir dupliqué la disposition courante (Ctrl+Plus ou menu) et changé quelques tailles ou bougé une vue de visualisation vers une autre aire de la vue d'onglets, vous pouvez rapidement commuter entre la nouvelle disposition et l'ancienne par Ctrl+Gauche/Droite. L'ensemble des dispositions sera enregistré entre les sessions de KCachegrind pour une même commande profilée. Vous pouvez faire que l'ensemble courant des dispositions soit celui par défaut pour les nouvelles sessions de KCachegrind, ou bien revenir à l'ensemble des dispositions par défaut. </para>
</sect2>
</sect1>
<sect1 id="concepts-sidedocks">
<title>Barres latérales</title>
<sect2>
<title>Profilage aplati</title>
<para>Le profilage aplati contient une liste de groupes et une liste de fonctions. La liste des groupes contient tous les groupes où le coût a été enregistré, en fonction du type de groupe choisi. La liste des groupes est cachée quand le regroupement est désactivé. </para>
<para>La liste des fonctions contient les fonctions d'un regroupement sélectionné (ou toutes les fonctions si le regroupement est désactivé), triées par colonne, par exemple les coûts propres ou inclusifs enregistrés dedans. Le nombre de fonctions affichées dans la liste est limité, mais configurable par Configuration/Configurer KCachegrind. </para>
</sect2>
<sect2>
<title>Synthèse des parties</title>
<para>Dans une exécution de profilage, plusieurs fichiers de données de profilage peuvent être produits et être chargés ensemble dans KCachegrind. La barre latérale Synthèse des parties les montre, en les triant horizontalement par date de création, les tailles de rectangle étant proportionnelles au coût enregistré dans chaque partie. Vous pouvez sélectionner une ou plusieurs parties pour obliger les coûts affichés dans les autres vues de KCachegrind à s'appliquer uniquement sur ces parties. </para>
<para>Les parties sont sous-divisées autrement : il y a un mode partitionnement et un mode partage des coûts inclusifs : <itemizedlist>
<listitem><para>Partionnement : Vous voyez le partionnement dans des groupes pour une partie des données de profilage, en accord avec le type de groupe sélectionné. Par exemple, si les groupes objet ELF sont sélectionnés, vous verrez des rectangles colorés pour chaque objet ELF utilisé (bibliothèque partagée ou exécutable), qui auront une taille proportionnelle au coût enregistré dedans. </para></listitem>
<listitem><para>Partage du coût inclusif : Un rectangle montrant le coût inclusif de la fonction active dans la partie est affiché. Celui-ci est partagé pour afficher les coûts inclusifs des fonctions appelées. </para></listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Pile d'appels</title>
<para>C'est une pile d'appels purement fictive, qui est la « plus probable ». Elle est construite en mettant au début la fonction active courante, puis en ajoutant les fonctions appelantes/appelées avec les plus hauts coûts en haut et en bas. </para>
<para>Les colonnes « coût » et « appels » montrent le coût enregistré pour tous les appels de la fonction dans la ligne au-dessus. </para>
</sect2>
</sect1>
<sect1 id="concepts-visualizations">
<title>Visualisations</title>
<sect2>
<title>Types d'évènement</title>
<para>La liste montre tous les types de coût disponibles, ceux correspondant, et le coût inclusif de la fonction active courante pour ce type d'évènement. </para>
<para>En choisissant un type d'évènement dans la liste, vous changez le type des coûts montré partout dans KCachegrind par celui sélectionné. </para>
</sect2>
<sect2>
<title>Listes des appels</title>
<para>Ces listes montrent les appels et les fonctions appelées de la fonction active courante. « Toutes » les fonctions appelantes/appelées signifie toutes les fonctions pouvant être accédées dans le sens des appelantes ou des appelées, même si d'autres fonctions se trouvent entre elles. </para>
<para>Les vues de liste des appels inclut : <itemizedlist>
<listitem><para>Les fonctions directement appelantes </para></listitem>
<listitem><para>Les fonctions directement appelées </para></listitem>
<listitem><para>Toutes les fonctions appelantes </para></listitem>
<listitem><para>Toutes les fonctions appelées </para></listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Cartes</title>
<para>Une visualisation de la carte de l'arbre du type d'évènement primaire, en haut ou en bas de la hiérarchie d'appel. Chaque rectangle coloré représente une fonction, sa taille essaie d'être proportionnelle au coût enregistré à l'intérieur pendant que la fonction active s'exécutait (cependant, il y a des contraintes de dessin). </para>
<para>Pour la carte des fonctions appelantes, le graphique montre la hiérarchie de toutes les fonctions appelant la fonction active courante ; pour la carte des fonctions appelées, il montre la hiérarchie de toutes les fonctions appelées par la fonction active courante. </para>
<para>Les options d'apparence sont disponibles dans le menu contextuel. Pour avoir des proportions exactes, choisissez « Cacher les bordures incorrectes ». Comme ce mode peut être très gourmand au niveau du temps, vous voudrez peut-être limiter avant le niveau maximum de dessin. « Meilleur » détermine la direction de partage pour les enfants à partir du ratio d'aspect de leur parent. « Toujours meilleur » décide de l'espace restant pour chaque enfant du même parent. « Ignorer les proportions » prend l'espace pour dessiner le nom de la fonction avant de dessiner les enfants. Notez que les proportions peuvent être fortement fausses. </para>
<para>La navigation par le clavier est disponible avec les touches gauche/droite pour parcourir les enfants du même parent, et haut/bas pour aller au niveau au-dessus/en dessous le plus proche. La touche Entrée active l'élément courant. </para>
</sect2>
<sect2>
<title>Graphe des appels</title>
<para>Cette vue montre le graphe d'appel autour de la fonction active. Le coût montré est seulement le coût enregistré pendant que la fonction active s'exécutait ; c'est-à-dire le coût montré pour la fonction main() - si elle est visible - doit être le même que le coût de la fonction active, comme c'est la partie du coût inclusif de main() enregistré pendant que la fonction active s'exécutait. </para>
<para>Pour les cycles, les flèches d'appels bleues indiquent que c'est un appel artificiel rajouté pour un affichage correct, même s'il ne s'est jamais produit. </para>
<para>Si le graphe est plus large que l'aire du composant, un panneau d'aperçu est affiché dans un coin. Il y a des options de visualisation identiques à celles de la carte de l'arbre d'appels ; la fonction sélectionnée est mise en surbrillance. </para>
</sect2>
<sect2>
<title>Annotations</title>
<para>Les listes source/assembleur annoté montre les lignes du code source/les instructions désassemblées de la fonction active courante, ainsi que le coût (propre) enregistré lors de l'exécution du code de la ligne du source/l'instruction. S'il y a eu appel, les lignes avec les détails sur l'appel sont insérées dans le code source : le coût (inclusif) enregistré à l'intérieur de l'appel, le nombre d'appels effectués, et la destination de l'appel. </para>
<para>Sélectionnez une telle ligne d'information d'appel pour activer la destination de l'appel. </para>
</sect2>
</sect1>
</chapter>
<chapter id="commands">
<title>Les éléments de menus / barres d'outils</title>
<sect1 id="tdecachegrind-mainwindow">
<title>La fenêtre principale de &tdecachegrind;</title>
<para></para>
<sect2>
<title>Le menu <guimenu>Fichier</guimenu></title>
<para>
<variablelist>
<varlistentry>
<term><menuchoice><shortcut> <keycombo>&Ctrl;<keycap>N</keycap></keycombo> </shortcut> <guimenu>Fichier</guimenu> <guimenuitem>Nouveau</guimenuitem> </menuchoice></term>
<listitem><para><action>Ouvre une fenêtre de haut niveau vide dans laquelle vous pouvez charger des données de profilage.</action> Cette action n'est pas vraiment nécessaire, car Fichier/Ouvrir vous donnera une nouvelle fenêtre de haut niveau quand la fenêtre courante affiche déjà des données. </para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><shortcut> <keycombo>&Ctrl;<keycap>O</keycap></keycombo> </shortcut> <guimenu>Fichier</guimenu> <guimenuitem>Ouvrir</guimenuitem> </menuchoice></term>
<listitem><para><action>Affiche le dialogue d'ouverture de fichier afin que vous puissiez choisir le fichier de données de profilage à charger.</action> S'il y a déjà des données affichées dans la fenêtre courante de haut niveau, ceci va ouvrir une nouvelle fenêtre. Si vous voulez ouvrir des données additionnelles de profilage dans la fenêtre courante, utilisez Fichier/Ajouter. </para>
<para>Le nom des fichiers de données de profilage se termine habituellement par ..-. En chargeant un fichier se terminant seulement par ., les fichiers de données éventuellement présents pour cette exécution, mais avec des terminaisons additionnelles, seront aussi chargés. </para>
<para>Exemple : s'il existe des fichiers de données de profilage cachegrind.out.123 et cachegrind.out.123.1, en chargeant le premier, le second sera chargé automatiquement. </para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Fichier</guimenu> <guimenuitem>Ajouter</guimenuitem> </menuchoice></term>
<listitem><para><action>Ajoute un fichier de données de profilage dans la fenêtre courante.</action> Vous pouvez ainsi forcer le chargement de multiples fichiers de données dans la même fenêtre de haut niveau, même s'ils ne sont pas de la même exécution, comme donné par la convention de nommage des fichiers de données de profilage. Utilisez cela par exemple pour des comparaisons côte-à-côte. </para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Fichier</guimenu> <guimenuitem>Recharger</guimenuitem> </menuchoice></term>
<listitem><para><action>Recharge les données de profilage.</action> Ceci est surtout intéressant après qu'un autre fichier de données de profilage ait été généré par l'exécution d'une application déjà chargée. </para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><shortcut> <keycombo>&Ctrl;<keycap>Q</keycap></keycombo> </shortcut> <guimenu>Fichier</guimenu> <guimenuitem>Quitter</guimenuitem> </menuchoice></term>
<listitem><para><action>Quitte</action> &kappname;</para></listitem>
</varlistentry>
</variablelist>
</para>
</sect2>
<sect2>
<title>Le menu <guimenu>Affichage</guimenu></title>
<para>
<variablelist>
<varlistentry>
<term><menuchoice><guimenu>Affichage</guimenu> <guimenuitem>Type d'évènement primaire</guimenuitem> </menuchoice></term>
<listitem><para><action>(À faire)</action></para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Affichage</guimenu> <guimenuitem>Type d'évènement secondaire</guimenuitem> </menuchoice></term>
<listitem><para><action>(À faire)</action></para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Affichage</guimenu> <guimenuitem>Regroupement</guimenuitem> </menuchoice></term>
<listitem><para><action>(À faire)</action></para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Affichage</guimenu> <guimenuitem>Disposition des vues</guimenuitem> </menuchoice></term>
<listitem><para><action>(À faire)</action></para></listitem>
</varlistentry>
<varlistentry>
<term><menuchoice><guimenu>Affichage</guimenu> <guimenuitem>Scinder</guimenuitem> </menuchoice></term>
<listitem><para><action>(À faire)</action></para></listitem>
</varlistentry>
</variablelist>
</para>
</sect2>
</sect1>
</chapter>
<chapter id="faq">
<title>Questions et Réponses</title>
&reporting.bugs; &updating.documentation; <qandaset id="faqlist">
<qandaentry>
<question>
<para>À quoi sert &tdecachegrind; ? Je n'en ai aucune idée. </para>
</question>
<answer>
<para>&tdecachegrind; est utile dans le stade final du développement d'un logiciel, appelé le profilage. Si vous ne développez pas d'applications, vous n'avez pas besoin de &tdecachegrind;. </para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Quelle est la différence entre « Incl. » et « Propre » ? </para>
</question>
<answer>
<para>Ce sont des attributs de coût pour les fonctions en considérant certains types d'évènements. Comme les fonctions peuvent s'appeler entre elles, il paraît logique de distinguer le coût de la fonction elle-même (Coût propre) et le coût incluant toutes les fonctions appelées (Coût inclusif). « Propre » est aussi remplacé certaines fois par « Exclusif ». </para>
<para>Ainsi, par exemple pour main(), vous aurez toujours un coût inclusif de presque 100%, alors que le coût propre est négligeable, le travail réel s'effectuant dans une autre fonction. </para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>La barre d'outils/de menus de KCachegrind est spartiate. Est-ce normal ?</para>
</question>
<answer>
<para>Manifestement KCachegrind est mal installé sur votre système. Il est recommandé de le compiler avec comme préfixe d'installation votre dossier de base KDE, comme par exemple <command>configure --prefix=/opt/kde3; make install</command>. Si vous choisissez un autre dossier, comme $HOME/kde, vous devez positionner la variable d'environnement TDEDIR sur ce dossier avant de lancer KCachegrind. </para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Si je double-clique sur une fonction en bas de la vue de l'arbre d'appel, il affiche le même coût pour la fonction main() que pour la fonction sélectionnée. N'est-ce pas supposé rester constant à 100% ? </para>
</question>
<answer>
<para>Vous avez activé une fonction en dessous de main() avec moins de coût que main(). Pour chaque fonction, on ne montre de la partie du coût total de la fonction, que celle enregistrée alors que la fonction activée s'exécutait. C'est-à-dire que le coût affiché pour toute fonction ne peut jamais être plus élevé que le coût de la fonction activée. </para>
</answer>
</qandaentry>
</qandaset>
</chapter>
<chapter id="glossary">
<title>Glossaire</title>
<para>A la suite, vous trouverez une liste de termes divers. <itemizedlist>
<listitem><para>Profilage : C'est le processus de collecte d'informations statistiques sur les caractéristiques d'un programme qui s'exécute. </para></listitem>
<listitem><para>Traçage : C'est le processus de supervision d'une exécution de programme, et de sauvegarde des évènements triés par date dans un fichier de sortie, la trace. </para></listitem>
<listitem><para>Trace : C'est une séquence d'évènements horodatés qui se produisent lors du traçage d'un programme qui s'exécute. Sa taille est généralement proportionnelle linéairement au temps d'exécution du programme. </para></listitem>
<listitem><para>Fichier de données de profilage : C'est un fichier contenant des données mesurées dans une expérience de profilage (ou une partie), ou produite par post-traitement d'une trace. Sa taille est généralement proportionnelle linéairement à la taille du code du programme. </para></listitem>
<listitem><para>Partie de données de profilage (aussi incorrectement nommé : partie de trace) : Ce sont des données d'un fichier de données de profilage. </para></listitem>
<listitem><para>Expérience de profilage : C'est une exécution d'un programme, supervisée par un outil de profilage, qui peut produire plusieurs fichiers de données de profilage à partir de parties et/ou de threads de l'exécution. </para></listitem>
<listitem><para>Projet de profilage : C'est une configuration pour les expériences de profilage utilisée pour un programme qui doit être profilé, peut-être dans plusieurs versions. Comparer des données de profilage n'a généralement de sens qu'entre données de profilage produites dans des expériences sur un seul projet de profilage. </para></listitem>
<listitem><para>Entité de coût : C'est un élément abstrait relié au code source, auquel on peut attribuer des compteurs d'évènements. Les dimensions des entités de coût sont la localisation dans le code (par exemple, ligne source, fonction), la localisation dans les données (par exemple, type de la donnée accédée, donnée), la localisation dans l'exécution (par exemple, thread, processus), et les couples ou les triplets des positions mentionnées au-dessus (par exemple, appels, accès à un objet à partir d'une instruction, donnée expulsée du cache). </para></listitem>
<listitem><para>Type d'évènement : C'est la sorte de l'évènement dont les coûts peuvent être attribués à une entité de coût. Il existe des types d'évènements réels et des types d'évènements hérités. </para></listitem>
<listitem><para>Type d'évènement réel : C'est un type d'évènement qui peut être mesuré par un outil. Cela nécessite l'existence d'un capteur pour le type d'évènement donné. </para></listitem>
<listitem><para>Type d'évènement hérité : C'est un type d'évènement virtuel, seulement visible dans une visualisation, et qui est défini par une formule basée sur des types d'évènements réels. </para></listitem>
<listitem><para>Coûts d'évènement : C'est la somme des évènements de quelques types d'évènement se produisant pendant que l'exécution est reliée à quelques entités de coût. Le coût est attribué à l'entité. </para></listitem>
</itemizedlist>
</para>
</chapter>
<chapter id="credits">
<title>Remerciements et licence</title>
<para>&kappname; </para>
<para>Merci à Julian Seward pour son excellent outil &valgrind;, et à Nicholas Nethercote pour le module externe &cachegrind;. Sans ces programmes, <application>KCachegrind</application> n'aurait jamais existé. Ils sont par ailleurs à l'origine de beaucoup d'idées pour cette &GUI;. </para>
<para>Et merci pour tous les rapports de bogues et les suggestions des différents utilisateurs. </para>
&underFDL; </chapter>
<appendix id="installation">
<title>Installation</title>
<sect1 id="getting-tdecachegrind">
<title>Comment obtenir &tdecachegrind;</title>
<para>&tdecachegrind; fait partie du package &package; de &kde;. Pour des versions intermédiaires avec moins de support, &callgrind; et une documentation plus complète, allez voir la homepage sur <ulink url="http://tdecachegrind.sf.net"> http://tdecachegrind.sf.net</ulink>. Vous pourrez aussi y voir des instructions de compilation et d'installation plus complètes. </para>
</sect1>
<sect1 id="requirements">
<title>Pré-requis</title>
<para>Pour utiliser dans de bonnes conditions &tdecachegrind;, vous avez besoin de &kde; 3.x. Pour générer les données de profilage, vous avez besoin de &cachegrind;, ou bien de &calltree;/&callgrind;. </para>
</sect1>
<sect1 id="compilation">
<title>Compilation et Installation</title>
&install.compile.documentation; </sect1>
<sect1 id="configuration">
<title>Configuration</title>
<para>Toutes les options de configuration sont soit dans la boîte de dialogue de configuration, soit dans les menus contextuels des visualisations. </para>
</sect1>
</appendix>
&documentation.index;
</book>
<!--
Local Variables:
mode: sgml
sgml-minimize-attributes:nil
sgml-general-insert-case:lower
sgml-indent-step:0
sgml-indent-data:nil
End:
-->
|