Userland Statically Defined Tracing (USDT)
Dans ce chapitre, nous sommes partis des tracepoints exposés volontairement
par le noyau Linux, et nous avons vu comment perf probe
nous permettait
d’instrumenter du code noyau arbitraire (kprobe) ou du code utilisateur
arbitraire (uprobe).
Les personnes attentives à la combinatoire auront remarqué qu’il y a une configuration que nous n’avons pas encore explorée, c’est celle d’une instrumentation exposée volontairement par les binaires utilisateurs. C’est le propos de l’instrumentation USDT que nous allons explorer maintenant.
Recherche d’instrumentation USDT
perf
n’est malheureusement pas capable de découvrir toute l’instrumentation
USDT disponible sur le système par lui-même, car cela impliquerait de rechercher
et ouvrir tous les binaires du système de fichier à chaque appel à perf list
,
ce qui aurait un coût inacceptable.
A la place, perf
conserve un cache de l’instrumentation observée dans les
binaires qu’on l’a amené à ouvrir, par exemple en faisant l’analyse de piles
d’appel acquises via --call-graph=dwarf
.
Il est aussi possible d’ajouter manuellement des binaires à ce cache avec la
commande perf buildid-cache
, ce que nous allons faire maintenant pour toutes
les bibliothèques de bases mentionnées à la fin de la section sur les uprobes,
plus le chargeur de binaires ld
:
perf buildid-cache -a /lib64/libc.so.6 \
&& perf buildid-cache -a /lib64/libm.so.6 \
&& perf buildid-cache -a /lib64/libpthread.so.0 \
&& perf buildid-cache -a /usr/lib64/libstdc++.so.6 \
&& perf buildid-cache -a /lib64/ld-linux-x86-64.so.2
(Vous noterez que chacune de ces commandes affiche un pager vide qui doit être quitté avec la touche “q”. Si vous trouvez un moyen de désactiver temporairement ce pager, je suis preneur.)
Ceci étant fait, l’instrumentation USDT exposée par ces binaires apparaîtra dans
perf list
:
perf list sdt
Sortie de perf list sdt
On voit que les bibliothèques GNU exposent pas mal d’instrumentation de ce type
autour de la gestion mémoire, de la gestion d’exceptions (via throw
/catch
ou
setjmp
/longjmp
), de pièges de performance liés à la libm
, ou de la
manipulation et synchronisation de threads via pthread
.
Activation de l’instrumentation
Si vous regardez la liste ci-dessus, vous constaterez que certains de ces “points d’instrumentation” sont sujets à être fréquemment empruntés, notamment ceux ayant trait à la synchronisation de threads. Il ne serait pas acceptable d’y payer en permanence le coût en performance d’une instrumentation quand celle-ci n’est pas utilisée.
L’instrumentation USDT est donc désactivée par défaut et doit être activée explicitement. Et comme l’implémentation actuelle utilise des uprobes, cette instrumentation doit être effectuée par l’administrateur du système, via les opérations suivantes :
- Remplir le buildid-cache de
root
en relançant les commandes ci-dessus pour cet utilisateur (typiquement viasudo
). - Activer l’instrumentation USDT souhaitée avec la commande
perf probe
, avec la syntaxe utilisée parperf list
.
Comme nous pouvons parfois être amené à activer un grand nombre de points
d’instrumentation à fins exploratoires, c’est le bon moment pour mentionner
qu’on peut passer à perf probe
des motifs shell du style sdt_libpthread:*
.
Invitez maintenant l’administrateur à activer l’instrumentation de la
libpthread
avec le jeu de commandes suivantes :
# Nécessite des privilèges administrateur !
sudo perf buildid-cache -a /lib64/libpthread.so.0 \
&& sudo perf probe sdt_libpthread:* \
&& sudo chown -R root:perf /sys/kernel/tracing/events/sdt_libpthread/
Exercice : Commencez par évaluer la fréquence des différents événements
exposés par libpthread
avec perf stat
, puis prenez un événement suffisamment
peu fréquent et suivez ses occurences avec perf trace
.