SystemTap : Profilez et utilisez rapidement des fonctionnalités du kernel
Contents
1 Introduction
SystemTap est un logiciel pour simplifier la récupération d'informations sur un système Linux. Il permet d'analyser et diagnostiquer un problème de performance ou de fonctionnalité. Il permet de s'affranchir de tous les besoins de recompilation de kernel, de reboot et d’événements indispensable pour une collecte de donnée bas niveau.
SystemTap fournit une interface à la ligne de commande type awk et un language de scripting proche du C qui permet d'écrire des outils directement sur un live kernel. Au delà du tracing/probing, il est utile pour des taches complexes nécessitant une analyse temps réel, programmable avec réponses aux évenements...
SystemTap peut profiler tous les appels system qui utilisent kprobes. A l'inverse d'OProfile, SystemTap capture 100% des évennements.
Un des gros avantage de SystemTap, c'est qu'il a été conçu de manière à être exécuté sur des environnements de production. On a donc :
- Une machine de développement : Sur laquelle on va compiler et tester les modules kernel SystemTap avec tous les outils et librairies nécessaire au bon développement de celui ci.
- Des machines de Production : Avoir le minimum de packages installés, avec juste le module compilé désiré, récupéré de la machine de développement.
2 Installation
2.1 Red Hat
2.1.1 Développement
Assurez vous d'avoir le repository debuginfo. Si ce n'est pas le cas, créez ce fichier avec ce contenu (à adapter) :
Puis installez ces packages :
yum |
yum install systemtap kernel-debuginfo kernel-devel gcc |
2.1.2 Production
Comme expliqué dans l'introduction, l'avantage de SystemTap, c'est que sur une machine de production, il n'y a qu'un seul package à installer :
yum |
yum install systemtap-runtime |
Lorsque vous utiliserez un module, vérifiez la compatibilité entre l'environnement de développement et de production grâce à cette commande :
modinfo |
modinfo modulename | grep vermagic |
Si vous voulez connaitre d'un coup tous les modules avec leur version de kernel associée :
3 Créer un script systemtap
Vous pouvez trouver beaucoup d'exemple sur le site de SystemTap : http://sourceware.org/systemtap/examples/
Les scripts doivent utiliser un notation avec des points et supportent les wilcards. Pour donner une idée de ce qui donnerait un hello world en systemtap :
hello_world.stp |
#! /usr/bin/env stap probe begin { println("hello world") exit () } |
3.1 Les fonctions
Un bon nombre de fonctions existent déjà et sont utilisable dans /usr/share/systemtap/tapset/*.
Pour appeler une fonction, on va utiliser probe. Voici un exemple :
my_systemtap_script.stp |
#! /usr/bin/env stap probe kernel.function("foo") probe kernel.function("*").return |
Voici quelques infos que l'on peut trouver dans ces scripts histoire de comprendre un peu mieux ce qui s'y passe :
- ioscheduler.elv_next_request : Détecte lorsqu'une requête (de type disque lecture/écriture) est récupérée de la queue
- ioscheduler.elv_next_request.return : Sort (fonction return de n'importe quel langage) lorsqu'une requête est retournée
- process.exec : Le process va exécuter un nouveau programme
- process.release : Lorsque le process souhaité va être libéré de la mémoire (en état non Zombie)
- netdev.receive : Voir l'arrivée de n'importe quelle donnée réseaux sur toutes les cartes
- tcp.sendmsg : Lorsque le kernel envoie une trame tcp
- vm.pagefault : Voir les pagesfault (lorsque la mémoire est physiquement allouée/lorsque les données sont prise depuis la swap...)
Si vous souhaitez obtenir la liste complète de toutes les fonctions disponibles par le kernel :
stap |
stap -p2 -e 'probe kernel.function("*") {}' | sort -u |
4 Exécution
4.1 Stap
Vous l'aurez certainement compris, c'est la commande stap qui est utilisée pour lancer le scripts. Cette commande est donc à utiliser sur une machine de développement et est découpée en 5 niveaux/étapes :
- Parsing du script (vérification de la syntaxe du script systemtap)
- Comparaison et vérification des symboles/fonctions avec celles du kernel-debuginfo
- Conversion du code SystemTap en C
- Création d'un module Kernel
- Chargement du module et lancement de celui ci (également déchargement, tout ceci requiert les privilèges root)
Il est possible de ne pas créer de script et de lancer directement la commande stap dans un shell. Vous pouvez également lui définir un niveau d'exécution de cette commande (par exemple 2 grâce à l'option -p). Si vous n'en spécifiez pas, les 5 niveaux seront exécutés et le module restera chargé jusqu'à sa fermeture (via Ctrl+C).
Voyons un exemple de ligne de commande qui va permettre de placer un traceur sur la fonction sys_open() du kernel et qui affichera tous les appels avec leurs arguments :
stap |
stap -e 'probe syscall.open {printf("%s: %s\n", execname(), argstr)}' |
Note : vous pouvez utiliser l'option -k pour garder une trace de votre compilation dans /tmp pour vérifier s'il y a eu un problème lors d'une étape
5 FAQ
5.1 systemtap ERROR: Build-id mismatch
Si vous observez ce genre de comportements lors d'une compilation d'un module SystemTap, c'est surement que la version du kernel-dev est différente de la version du kernel qui tourne actuellement sur votre machine. Pour le vérifier, il va falloir comparer le Build-id du kernel en cours d'exécution :
eu-readelf |
> eu-readelf -n /boot/vmlinuz-`uname -r` | grep "Build ID" Build ID: efbb1bd2e40f890370b8f2fc536c991a2d4abda7 |
Avec celle du module kernel-dev :
eu-readelf |
> eu-readelf -n /usr/lib/debug/lib/modules/ma_version_du_noyau/vmlinux | grep "Build ID" Build ID: adcf5270333d375aa5a034523b006373e8f54e48 |
Et là nous pouvons voir qu'il y a un problème de version, ce qui aura pour effet d'avoir ce type de message :
Passe 5 : lancement de l'exécution ERROR: Build-id mismatch: "kernel" vs. "vmlinux" byte 0 (0xad vs 0xef) address 0xffffffff814f7380 rc 0 Warning: /usr/bin/staprun exited with status: 1 Pass 5: run completed in 10usr/10sys/232real ms. Passe 5 : échec de l'exécution.Essayez encore avec une option '--vp 00001' supplémentaire.
Pour résoudre votre problème, il suffira donc de prendre la bonne version de chaque packages requis.