• Aucun résultat trouvé

Création de deux brins par la bibliothèque de multitraitement de L INUX 2.4

avec COSMOPEN, ne retenir que la sémantique de haut niveau contenue dans les traces d’observation comportementale d’un programme. Nous revenons ici sur cet exemple pour illustrer pas-à-pas comment s’opère cette extraction sémantique. La figure B.4 (qui reprend la figure 5.16 page 101) résulte de l’observation du petit programme qui suit, lorsque celui- ci s’exécute sur le noyau LINUX2.4 (seul le déroulement des appels àpthread_ reateest représenté).pipe,write,read, lonecorrespondent à des appels système LINUX, et sont in- voqués en interne pas la bibliothèque de multitraitement suite aux appels àpthread_ reate par le programme.

int main () {

pthread_t threadN1, threadN2 ;

pthread_ reate(&threadN1, NULL, StartOfThreadN1, NULL) ; pthread_ reate(&threadN2, NULL, StartOfThreadN2, NULL) ; pthread_join(threadN1, NULL) ;

pthread_join(threadN2, NULL) ; }

B.3.2

Causalités cachées et « sauts » temporels

Notre objectif est de transformer le graphe de la figure B.4 pour ne plus faire ressortir que la logique applicative du petit programme précédent, c’est-à-dire la création de deux brins par le brin principal. Mais nous nous heurtons à une difficulté : un graphe compor- temental ne fait ressortir que les flux de contrôle d’un programme, et ne capture pas les

interactions entre brins réalisées par échange de données au travers de structures partagées (flux de données). Sur le graphe B.4, les demandes de création par le brin principal t1 de deux nouveaux brins (appels (1) et (14)) se traduisent par l’écriture d’une requête de création sur un tube de communication (pipe) entre le brin t1 et le gestionnaire de brins (thread manager) t2, qui est interne à libpthread.so(appels(7) et (15) à write). Les informations écrites sur le pipe sont lues lors des appels correspondants (9) et (16) àread. Le lien de causalité qui existe entre un appel à writeet un appel à read n’est, sur la figure, pas visible. Comment alors relier la création du brin t3 par t2 (appels (11) et (12)) à la première invocation de pthread_ reate par t1 (appel (1)) ? et celle de t4 (appels (18) et (19)) à la seconde invocation de pthread_ reate (appel (14)) ? Nous avons choisi pour cela de mettre à profit les informations temporelles capturées par un graphe comportemental. Si nous considérons en effet l’appel (11) t2 : lone, c’est le premier appel à lone (en dehors de la création du brin gestionnaire t2) à se produire après l’appel(1) t1 : pthread_ reate. Ces deux appels sont donc nécessairement reliés. De la même façon, si nous considérons qu’à chaque invocation à pthread_ reate ne peut correspondre qu’une seule invocation à lone (en dehors, toujours, de la création du brin gestionnaire t2), nous relions immédiatement l’appel (18) t2 : lone à l’appel (14) t1 : pthread_ reate. Le seul cas où ce type d’inférence basée sur les estampilles temporelles ne fonctionne pas est lorsque les séquences <pthread_ reate

i lone

i> s’entrelacent (par exemple[pthread_ reate

1 ;pthread_ reate 2 ; lone 1 ; lone 2 ]). Il est cependant possible de détecter ce type d’entrelacements (très rares en pratique) de façon automatique, et de s’interdire ainsi toute conclusion erronée.

Pour réaliser cette inférence basée sur les estampilles temporelles de façon automatique, nous avons développé dans OPSBROWSERun opérateur de « saut » (leap en anglais) appelé leapOver.leapOverutilisent trois opérandes, de la forme

leapOver <motifDeDépart> <motifDeSaut> <graphe>.

<graphe> est la variable de graphe à laquelle s’applique l’opérateur.

<motifDeDépart>est un motif sur les noms de nœuds pour sélectionner les premiers éléments des paires <appelCause

i

appelEffet

i>. Dans notre exemple, nous vou- lons sélectionner les appels à pthread_ reate. Notre motif de départ sera donc «::pthread_ reate'*»

5.

<motifDeSaut> est un motif sur les noms de nœuds pour sélectionner les seconds éléments des paires <appelCause

i

appelEffet

i>. Dans notre exemple, ce second motif sera «:: lone'*».

Munis de ces trois opérandes,leapOverfonctionne alors de la manière suivante : pour chacune des invocations appelEffet

i sélectionnées par le motif de saut (pour nous cha- cune des invocations à lone),leapOverrecherche la plus récente invocationappelCause

i

5Les «

::» en début de motif indiquent quepthread_ reateest un symbole global, qui ne fait notamment partie

d’aucune classe. Le «'*» est une syntaxe particulière à OPSBROWSER qui permet de sélectionner toutes les

invocations àpthread_ reate, quel que soit le brin qui les effectue. Il serait aussi possible, par une autre syntaxe,

main pthread_create (1,14) t1 pthread_start_thread (12) t1:new Thread 3 (19) t1:new Thread 4 write (7,15) t1 __pthread_manager (6) t1:new Thread 2 __pthread_initialize_manager (2) t1 read StartOfThreadN1 (13) t3 StartOfThreadN2 (20) t4 pipe clone (8,9,16) t2 (3) t1 (5) t1 (4) t1 pthread_handle_create (10,17) t2 (11,18) t2

FIG. B.5 :Graphe B.4 après une opération de saut «leapOver»

correspondant au motif d’arrivée qui se soit produite avantappelEffet

i(pour nous la plus récente invocation àpthread_ reateprécédent le loneconsidéré). Ainsi à(11) t2 : lone, leapOver fera correspondre (1) t1 : pthread_ reate, et à (18) t2 : lone, (14) t1 : pthread_ reate.

Ensuite, pour chaque paire <appelCause i

appelEffet

i> ainsi formée,

leapOver opère un « saut » depuis appelCause

i« par-dessus »

appelEffet

i, en déplaçant toutes les arêtes qui sortent de appelEffet

i vers

appelCause

i (pour nous, donc, les arêtes sortant de lone, c’est-à-dire les arêtes de création de brin). Si par exemple une arête existe dans le graphe original entre appelEffet

i et l’invocation

unAutreAppel, alors cette arête est supprimée et remplacée par une arête équivalente deappelCause

ivers

unAutreAppel. L’exécution de

leapOver ::pthread_ reate'* :: lone'* GrapheGlobal

sur le graphe B.4 page 133 produit le nouveau graphe représenté sur la figure B.5. On notera sur ce nouveau graphe comment les arêtes de création de brin (en pointillés) ne partent plus de lonemais depthread_ reate.

B.3.3

S ’abstraire des détails tout en gardant leur trace

Il nous reste maintenant à éliminer du graphe toutes les invocations des brins t1 et t2 qui correspondent au fonctionnement interne de la bibliothèquelibpthread.so. Pour cela nous sélectionnons ces invocations en utilisant la suite d’opérateurs suivants :

main pthread_create (1,14) t1 pthread_start_thread (12) t1:new Thread 3 (19) t1:new Thread 4 write (7,15) t1 __pthread_manager (6) t1:new Thread 2 __pthread_initialize_manager (2) t1 read StartOfThreadN1 (13) t3 StartOfThreadN2 (20) t4 pipe clone (4,5,8) t2 (1) t1 (3) t1 (2) t1 pthread_handle_create (6,9) t2 (7,10) t2