Manuel de suivi dynamique Solaris

Prédicats

L'une des grandes différences entre D et d'autres langages de programmation comme C, C++ et Java réside dans l'absence de constructions de flux de contrôle comme les instructions Si et les boucles. Les clauses du programme D sont écrites en tant que listes d'instructions simples sur une seule ligne qui procèdent au suivi d'une quantité de données fixe, facultative. D fournit la possibilité de suivre et modifier le flux de contrôle sous certaines conditions à l'aide d'expressions logiques appelées prédicats pouvant être utilisées pour placer en préfixe des clauses du programme. Une expression de prédicat est évaluée lors du déclenchement de la sonde avant l'exécution de l'une des instructions associées à la clause correspondante. Si le prédicat renvoie True, représenté par une valeur différente de zéro, la liste d'instructions est exécutée. Si le prédicat renvoie False, représenté par une valeur égale à zéro, aucune des instructions n'est exécutée et le déclenchement de la sonde est ignoré.

Tapez le code source suivant pour le prochain exemple et enregistrez-le dans un fichier appelé countdown.d :

dtrace:::BEGIN
{
	i = 10;
}

profile:::tick-1sec
/i > 0/
{
	trace(i--);
}

profile:::tick-1sec
/i == 0/
{
	trace("blastoff!");
	exit(0);
}

Ce programme D implémente un compte à rebours de 10 secondes avec des prédicats. Lorsqu'il est exécuté, le fichier countdown.d effectue un compte à rebours à partir de 10, affiche un message et se ferme :

# dtrace -s countdown.d
dtrace: script 'countdown.d' matched 3 probes
CPU     ID                    FUNCTION:NAME
	0  25499                       :tick-1sec        10
	0  25499                       :tick-1sec         9
	0  25499                       :tick-1sec         8
	0  25499                       :tick-1sec         7
	0  25499                       :tick-1sec         6
	0  25499                       :tick-1sec         5
	0  25499                       :tick-1sec         4
	0  25499                       :tick-1sec         3
	0  25499                       :tick-1sec         2
	0  25499                       :tick-1sec         1
	0  25499                       :tick-1sec   blastoff!
# 

Cet exemple utilise la sondeBEGIN pour initialiser un nombre entier i sur 10 pour commencer le compte à rebours. Ensuite, comme dans l'exemple précédent, le programme utilise la sonde tick-1sec pour implémenter une horloge qui se déclenche une fois par seconde. Vous remarquerez que dans countdown.d, la description de la sonde tick-1sec est utilisée dans deux clauses différentes, chacune avec un prédicat et une liste d'actions différents. Le prédicat est une expression logique entre barres obliques / / qui suit le nom de la sonde et précède les accolades { } entourant la liste d'instructions.

Le premier prédicat teste si i est supérieur à zéro, indiquant que l'horloge est toujours en cours d'exécution :

profile:::tick-1sec
/i > 0/
{
	trace(i--);
}

L'opérateur relationnel > signifie supérieur à et renvoie un nombre entier d'une valeur égale à zéro pour False et égale à un pour True. Tous les opérateurs arithmétiques relationnels de C sont pris en charge en D ; la liste complète figure dans le Chapitre2Types, opérateurs et expressions Si i n'est pas encore égal à zéro, le script effectue le suivi de i, puis le décrémente en utilisant l'opérateur --.

Le second prédicat utilise l'opérateur == pour renvoyer True lorsque i est égal à zéro, indiquant que le compte à rebours est terminé :

profile:::tick-1sec
/i == 0/
{
	trace("blastoff!");
	exit(0);
}

Comme dans le premier exemple, hello.d countdown.d utilise une séquence de caractères entre guillemets appelée constante de chaîne, pour afficher un message final lorsque le compte à rebours est terminé. La fonction exit() est utilisée pour quitter dtrace et revenir à l'invite de shell.

Si vous regardez la structure de countdown.d, vous constaterez qu'en créant deux clauses avec la même description de sonde mais avec différents prédicats et actions, nous avons effectivement créé le flux logique :

i = 10
once per second,
	if i is greater than zero
		trace(i--);
	otherwise if i is equal to zero
		trace("blastoff!");
		exit(0);

Lorsque vous souhaitez écrire des programmes complexes avec des prédicats, essayez d'abord de visualiser votre algorithme de cette façon, puis transformez chaque chemin de vos constructions conditionnelles en une clause et un prédicat séparés.

Vous pouvez maintenant combiner des prédicats avec un nouveau fournisseur, le fournisseur syscall et créer votre premier vrai programme de suivi D. Le fournisseur syscall vous permet d'activer des sondes lors de l'entrée ou du renvoi de n'importe quel appel système Solaris. Le prochain exemple utilise DTrace pour observer à chaque fois que votre shell effectue un appel système read(2) ou write(2). Ouvrez d'abord deux fenêtres de terminal, l'une pour utiliser DTrace et l'autre contenant le processus de shell que vous allez observer. Dans la seconde fenêtre, tapez la commande suivante pour obtenir l'ID de processus de ce shell :


# echo $$
12345

Revenez maintenant à votre première fenêtre de terminal, tapez le programme D suivant et enregistrez-le dans un fichier appelé rw.d. En tapant le programme, remplacez 12345 par l'ID de processus du shell affiché en réponse à votre commande echo.

syscall::read:entry,
syscall::write:entry
/pid == 12345/
{

}

Vous remarquerez que la clause de sonde rw.d reste vide car le programme est uniquement destiné à suivre les notifications de déclenchement de sondes et non à suivre des données supplémentaires. Lorsque vous avez terminé la saisie dans rw.d, utilisez dtrace pour commencer votre expérience puis accédez à la seconde fenêtre de shell et tapez quelques commandes, en appuyant sur Entrée après chacune. Lors de la saisie, vous devez voir les déclenchements de sonde dtrace consignés dans un rapport dans votre première fenêtre, comme dans l'exemple qui suit :


# dtrace -s rw.d
dtrace: script 'rw.d' matched 2 probes
CPU     ID                    FUNCTION:NAME
	0     34                      write:entry
	0     32                       read:entry
	0     34                      write:entry
	0     32                       read:entry
	0     34                      write:entry
	0     32                       read:entry
	0     34                      write:entry
	0     32                       read:entry
...

Vous observez à présent votre shell exécuter des appels système read(2) et write(2) pour lire un caractère à partir de votre fenêtre de terminal et renvoyer le résultat. Cet exemple comprend un grand nombre des concepts décrits jusqu'à présent et quelques nouveaux concepts également. Tout d'abord, pour instrumenter read(2) et write(2) de la même façon, le script utilise une seule clause de sonde avec plusieurs descriptions de sonde en les séparant par des virgules, comme suit :

syscall::read:entry,
syscall::write:entry

Pour une meilleure lisibilité, chaque description de sonde apparaît sur sa propre ligne. Cette disposition n'est pas strictement requise mais elle contribue à une meilleure lisibilité du script. Le script définit ensuite un prédicat correspondant uniquement aux appels système exécutés par votre processus de shell :

/pid == 12345/

Le prédicat utilise la variable DTrace prédéfinie pid, qui évalue toujours l'ID de processus associé au thread ayant déclenché la sonde correspondante. DTrace fournit de nombreuses définitions de variables intégrées pour obtenir des informations utiles comme l'ID de processus. Voici une liste de quelques variables DTrace pouvant être utilisées pour écrire vos premiers programmes D :

Nom de variable 

Type de données 

Signification 

errno

int

Valeur errno actuelle pour les appels système

execname

string

Nom du fichier exécutable du processus actuel 

pid

pid_t

ID de processus du processus actuel 

tid

id_t

ID de thread du thread actuel 

probeprov

string

Champ du fournisseur de la description de sonde actuelle 

probemod

string

Champ du module de la description de sonde actuelle 

probefunc

string

Champ de la fonction de la description de sonde actuelle 

probename

string

Champ du nom de la description de sonde actuelle 

Maintenant que vous avez écrit un vrai programme d'instrumentation, essayez de l'expérimenter sur différents processus s'exécutant sur votre système en modifiant l'ID de processus et les sondes d'appels système instrumentées. Vous pouvez ensuite effectuer une modification supplémentaire et changer rw.d en une version très simple d'un outil de suivi des appels système comme truss(1). Utiliser un champ de description de sonde vide revient à utiliser un caractère générique, correspondant à n'importe quelle sonde. Vous devez donc modifier votre programme selon le nouveau code source suivant pour suivre n'importe quel appel système exécuté par votre shell :

syscall:::entry
/pid == 12345/
{

}

Essayez de taper quelques commandes dans le shell comme cd, ls et date et examinez le rapport créé par votre programme DTrace.