Manuel de suivi dynamique Solaris

Structs

Le mot-clé struct en langage D (raccourci de structure) est utilisé pour introduire un nouveau type composé d'un groupe d'autres types. Vous pouvez utiliser le nouveau type de struct comme type de tableaux et de variables en langage D dans le but de définir des groupes de variables connexes sous un seul nom. Les structs en langage D sont identiques aux constructions correspondantes en C et C++. En cas de programmation en langage java, imaginez une struct en langage D comme une classe qui ne contient que des membres de données et aucune méthode.

Imaginez que vous souhaitez créer, en langage D, un programme plus sophistiqué de suivi des appels système qui enregistre plusieurs données concernant chaque appel système read(2) et write(2) exécuté par votre shell (temps écoulé, nombre d'appels et plus grand comptage d'octets sous forme d'argument). Vous pouvez écrire une clause en langage D pour enregistrer ces propriétés dans trois tableaux associatifs distincts, comme illustré dans l'exemple suivant :

syscall::read:entry, syscall::write:entry
/pid == 12345/
{
	ts[probefunc] = timestamp;
	calls[probefunc]++;
	maxbytes[probefunc] = arg2 > maxbytes[probefunc] ?
	    arg2 : maxbytes[probefunc];
}

Cette clause est toutefois inefficace car DTrace doit créer trois tableaux associatifs distincts et enregistrer les copies distinctes des valeurs de tuple identiques correspondant à probefunc pour chacune d'entre elles. Une struct vous permet d'économiser de l'espace et de simplifier la lecture et la préservation de votre programme. Pour ce faire, commencez par déclarer un nouveau type de struct au sommet du fichier source du programme :

struct callinfo {
	uint64_t ts;      /* timestamp of last syscall entry */
	uint64_t elapsed; /* total elapsed time in nanoseconds */
	uint64_t calls;   /* number of calls made */
	size_t maxbytes;  /* maximum byte count argument */
};

Le mot clé struct est suivi d'un identifiant en option qui sert de renvoi à notre nouveau type, appelé struct callinfo. Les membres de la struct sont ensuite placés entre crochets { }, puis la déclaration toute entière se termine par un point-virgule (; ). Chaque membre de la struct est défini à l'aide de la même syntaxe que celle d'une déclaration de variable en langage D, le type du membre étant indiqué en premier, puis suivi d'un identifiant permettant de nommer le membre et d'un autre point-virgule (;).

La déclaration de la struct en elle-même se contente de définir le nouveau type. Elle ne crée aucune variable ni n'alloue aucun stockage dans DTrace. La déclaration terminée, vous pouvez utiliser le type struct callinfo tout au long du reste de votre programme en D et chaque variable de type struct callinfo enregistre une copie des quatre variables décrites par notre modèle de structure. Les membres sont classés en mémoire conformément à l'ordre de la liste des membres, un espace de remplissage étant introduit entre chaque membre afin d'aligner les objets de données.

Vous pouvez utiliser les noms d'identifiant des membres pour accéder à la valeur de chaque membre à l'aide de l'opérateur “.” en écrivant une expression se présentant comme suit :

variable-name.member-name

L'exemple suivant représente un programme amélioré qui utilise le nouveau type de structure. Ouvrez votre éditeur et entrez le programme en langage D suivant, puis enregistrez-le dans le fichier rwinfo.d:


Exemple 7–1 rwinfo.d : collecte des statistiques read(2) et write(2)

struct callinfo {
	uint64_t ts;      /* timestamp of last syscall entry */
	uint64_t elapsed; /* total elapsed time in nanoseconds */
	uint64_t calls;   /* number of calls made */
	size_t maxbytes;  /* maximum byte count argument */
};

struct callinfo i[string];	/* declare i as an associative array */

syscall::read:entry, syscall::write:entry
/pid == $1/
{
	i[probefunc].ts = timestamp;
	i[probefunc].calls++;
	i[probefunc].maxbytes = arg2 > i[probefunc].maxbytes ?
		arg2 : i[probefunc].maxbytes;
}

syscall::read:return, syscall::write:return
/i[probefunc].ts != 0 && pid == $1/
{
	i[probefunc].elapsed += timestamp - i[probefunc].ts;
}

END
{
	printf("        calls  max bytes  elapsed nsecs\n");
	printf("------  -----  ---------  -------------\n");
	printf("  read  %5d  %9d  %d\n",
	    i["read"].calls, i["read"].maxbytes, i["read"].elapsed);
	printf(" write  %5d  %9d  %d\n",
	    i["write"].calls, i["write"].maxbytes, i["write"].elapsed);
}

Une fois le programme saisi, exécutez la commande dtrace -q -s rwinfo.d en spécifiant l'un de vos processus de shell. Entrez ensuite quelques commandes dans votre shell et, ceci terminé, tapez Control-C dans le terminal dtrace pour déclencher la sonde END et imprimer les résultats :


# dtrace -q -s rwinfo.d `pgrep -n ksh`
^C
        calls  max bytes  elapsed nsecs
------  -----  ---------  -------------
  read     36       1024  3588283144
 write     35         59  14945541
#