Manuel de suivi dynamique Solaris

Tableaux

D vous permet de définir des variables qui sont des nombres entiers ainsi que d'autres types pour représenter des chaînes et des types composites appelés structs et unions. Si vous connaissez la programmation en C, vous serez ravi d'apprendre que tout ce que vous pouvez saisir en C peut l'être en D. Si vous n'êtes pas un expert en C, ne vous en faites pas : les différents types de données sont tous décrits dans le Chapitre2Types, opérateurs et expressions D prend également en charge un type de variable appelé tableau associatif. Un tableau associatif ressemble à un tableau normal, dans la mesure où il associe un jeu de clés à un jeu de valeurs, mais dans un tableau associatif, les clés ne sont pas limitées aux nombres entiers d'une plage fixe.

Les tableaux associatifs D peuvent être indexés par une liste comportant au moins une valeur, de n'importe quel type. Ensemble, les valeurs des clés individuelles forment un tuple utilisé pour l'indexage dans le tableau et l'accès ou la modification de la valeur correspondant à cette clé. Chaque tuple utilisé avec un tableau associatif donné doit correspondre à la signature du même type, c'est-à-dire que toutes les clés de tuple doivent avoir la même longueur et leurs types doivent être identiques et dans le même ordre. La valeur associée à chaque élément d'un tableau associatif donné est également un type fixe unique pour l'ensemble du tableau. Par exemple, l'instruction D suivante définit un nouveau tableau associatif a, dont la valeur est de type int avec la signature de tuple [ string, int ] et stocke la valeur de nombre entier 456 dans le tableau.

a["hello", 123] = 456;

Dès qu'un tableau est défini, il est possible d'accéder à ces éléments comme n'importe quelle autre variable D. Par exemple, l'instruction D suivante modifie l'élément de tableau précédemment stocké dans a en incrémentant la valeur de 456 à 457 :

a["hello", 123]++;

Les valeurs de tous les éléments de tableau qui n'ont pas encore été attribués sont définies sur zéro. Utilisons maintenant un tableau associatif dans un programme D. Tapez le programme suivant et enregistrez-le dans le fichier rwtime.d :


Exemple 1–3 rwtime.d : heure read(2) et write(2) appels

syscall::read:entry,
syscall::write:entry
/pid == $1/
{
	ts[probefunc] = timestamp;
}

syscall::read:return,
syscall::write:return
/pid == $1 && ts[probefunc] != 0/
{
	printf("%d nsecs", timestamp - ts[probefunc]);
}

Comme dans le cas de trussrw.d, spécifiez l'ID de processus shell lorsque vous exécutez rwtime.d. Si vous tapez quelques commandes shell, le temps écoulé pendant chaque appel système s'affiche. Tapez la commande suivante puis appuyez sur Entrée plusieurs fois dans votre autre shell :


# dtrace -s rwtime.d `pgrep -n ksh`
dtrace: script 'rwtime.d' matched 4 probes
CPU     ID                    FUNCTION:NAME
  0     33                      read:return 22644 nsecs
  0     33                      read:return 3382 nsecs
  0     35                     write:return 25952 nsecs
  0     33                      read:return 916875239 nsecs
  0     35                     write:return 27320 nsecs
  0     33                      read:return 9022 nsecs
  0     33                      read:return 3776 nsecs
  0     35                     write:return 17164 nsecs
...
^C
#

Pour suivre le temps écoulé pour chaque appel système, vous devez instrumenter à la fois l'entrée et le retour de read(2) et write(2) et tester le temps écoulé à chaque point. Puis, lors du retour d'un appel système donné, vous devez calculer la différence entre notre premier et notre second horodatage. Il est possible d'utiliser des variables séparées pour chaque appel système, mais il peut s'avérer gênant pour le programme de s'étendre vers des appels système supplémentaires. À la place, il est plus facile d'utiliser un tableau associatif indexé par le nom de la fonction de sonde. Voici la première clause de sonde :

syscall::read:entry,
syscall::write:entry
/pid == $1/
{
	ts[probefunc] = timestamp;
}

Cette clause définit un tableau appelé ts et assigne au membre approprié la valeur de la variable DTrace timestamp. Cette variable renvoie la valeur d'un compteur à incrémentation constante en nanosecondes, comme la routine de bibliothèque Solaris gethrtime(3C). Dès que l'horodatage d'entrée est enregistré, les sondes de retour correspondantes timestamp sont à nouveau testées et les différences entre l'heure actuelle et la valeur enregistrée sont consignées dans un rapport.

syscall::read:return,
syscall::write:return
/pid == $1 && ts[probefunc] != 0/
{
	printf("%d nsecs", timestamp - ts[probefunc]);
}

Le prédicat de la sonde de retour nécessite que DTrace effectue le suivi du processus approprié et que la sonde entry correspondante se soit déjà déclenchée et ait déjà assigné une valeur ts[probefunc] différente de zéro. Cette opération permet d'éliminer les résultats non valides lors du démarrage de DTrace. Si votre shell est déjà en attente d'un appel système read(2) pour la saisie lors de l'exécution de dtrace, la sonde read:return se déclenchera même si elle n'est pas précédée de read:entry, car ce premier read(2) et ts[probefunc] renverront une valeur égale à zéro car elle n'a pas encore été assignée.