Globalement, ça ne dépend pas beaucoup des applications. Ce sont les services systèmes qui sont plus lents dans un système multi-serveurs à base de micro-noyau. Je prends un exemple : lorsqu'on réalise une lecture de fichier, classiquement les données passeront par ces intermédiaires :
* le programme réalise un appel read() ; la GLibc contacte le translator chargé
du fichier et lui envoie une requête ;
* le système de fichier fait un appel à l'abstraction qui s'occupe de gérer son "backing store" (il y a généralement ce type d'abstraction, pour que le FS se lance de façon transparente sur une image, une partition, une image compressée/chiffrée, ...) ;
* cette abstraction va traduire la requête en une autre, selon le type de source ; disons qu'il s'agit d'une partition sur un disque IDE ;
* GNU Mach est donc appelé pour faire la lecture (les pilotes sont dans GNU Mach).
Dans l'autre sens, les données seront trimbalées dans toute la chaîne. On rajoute avec L4 une étape : le pilote IDE en espace utilisateur, qui fera lui-même vraisemblablement un appel système (à moins d'I/O port déjà mappé ou de DMA). Les IPCs dans GNU Mach sont asynchrones. Cela signifie que lorsqu'un thread fait un envoi de message à un autre thread, le noyau lui rend la main dès qu'il a enregistré la requête dans la queue des messages correspondant à ce thread (en fait, un thread n'est pas associé à une queue, mais passons). Bien sûr, il fait une copie logique, et même plus précisémen du copy-on-write, comme dit dans la news : mais comme les messages sont asynchrones, l'application continue à faire autre chose pendant le même temps, et si elle écrit là où les données étaient stockées, il faudra copier physiquement la mémoire dans la queue (dans le noyau! on sait comme les copies user space -> kernel sont extrêmement lourdes) en attendant que le destinataire vienne le chercher. Le temps que le message de retour soit passé dans toute la chaîne, il est bien probable qu'une application au moins ait modifié l'emplacement mémoire où elle avait stocké les données lues (disons, le pilote IDE). Du coup, au moins une copie physique lourde, si ce n'est deux. N'autoriser que des IPCs synchrones (et gérer le passage de mémoire intelligemment avec des containers comme le fait physmem) résout en grande partie le problème : c'est ce que fait L4.
L'autre problème est lié au simple fait que l'appel implique plusieurs services : outre le passage de message, le fait de passer d'une tâche à l'autre (changement de contexte) a lui aussi un coût associé. Une partie des coûts sont liés au TLB (Translation Lookaside Buffer). Ce TLB est un buffer où l'on met en cache les correspondances adresses virtuelles <-> adresses physiques. En effet, le fait de retrouver l'adresse physique à partir de l'adresse virtuelle est une opération assez pénible qui nécessite des parcours dans les pagetables de toutes façons assez longs (évidemment, les VM essayent de le rendre le moins long possible). Or, les adresses virtuelles sont dépendantes de l'espace d'adressage, donc a priori de la tâche en cours d'exécution. Comme on n'a pas moyen de préciser dans le TLB "cette association correspond à tel espace d'adressage" (tagger le TLB) sauf sur quelques architectures, il faut le vider à chaque changement de contexte. Et donc multiplier les parcours. Plus on multiplie les changements de tâche, plus on multiplie les parcours, plus on perd du temps. L4 se propose justement de résoudre ça (au moins en partie sur x86) sur au moins trois architectures (x86, PowerPC, Sparc), en utilisant des possibilités de chaque architecture. Du coup, on évite 4 fois sur 5 au moins les "vidages" de TLB.
Si vous voulez plus de détails sur les mécanismes, réferez vous aux publications de L4Ka ou aux anciens commentaires de Kilobug ou de moi. :-)
[^] # Re: Avancement futur? + perfs ?
Posté par Manuel Menal . En réponse à la dépêche Nouvelle avancée du port du Hurd sur L4. Évalué à 8.
* le programme réalise un appel read() ; la GLibc contacte le translator chargé
du fichier et lui envoie une requête ;
* le système de fichier fait un appel à l'abstraction qui s'occupe de gérer son "backing store" (il y a généralement ce type d'abstraction, pour que le FS se lance de façon transparente sur une image, une partition, une image compressée/chiffrée, ...) ;
* cette abstraction va traduire la requête en une autre, selon le type de source ; disons qu'il s'agit d'une partition sur un disque IDE ;
* GNU Mach est donc appelé pour faire la lecture (les pilotes sont dans GNU Mach).
Dans l'autre sens, les données seront trimbalées dans toute la chaîne. On rajoute avec L4 une étape : le pilote IDE en espace utilisateur, qui fera lui-même vraisemblablement un appel système (à moins d'I/O port déjà mappé ou de DMA). Les IPCs dans GNU Mach sont asynchrones. Cela signifie que lorsqu'un thread fait un envoi de message à un autre thread, le noyau lui rend la main dès qu'il a enregistré la requête dans la queue des messages correspondant à ce thread (en fait, un thread n'est pas associé à une queue, mais passons). Bien sûr, il fait une copie logique, et même plus précisémen du copy-on-write, comme dit dans la news : mais comme les messages sont asynchrones, l'application continue à faire autre chose pendant le même temps, et si elle écrit là où les données étaient stockées, il faudra copier physiquement la mémoire dans la queue (dans le noyau! on sait comme les copies user space -> kernel sont extrêmement lourdes) en attendant que le destinataire vienne le chercher. Le temps que le message de retour soit passé dans toute la chaîne, il est bien probable qu'une application au moins ait modifié l'emplacement mémoire où elle avait stocké les données lues (disons, le pilote IDE). Du coup, au moins une copie physique lourde, si ce n'est deux. N'autoriser que des IPCs synchrones (et gérer le passage de mémoire intelligemment avec des containers comme le fait physmem) résout en grande partie le problème : c'est ce que fait L4.
L'autre problème est lié au simple fait que l'appel implique plusieurs services : outre le passage de message, le fait de passer d'une tâche à l'autre (changement de contexte) a lui aussi un coût associé. Une partie des coûts sont liés au TLB (Translation Lookaside Buffer). Ce TLB est un buffer où l'on met en cache les correspondances adresses virtuelles <-> adresses physiques. En effet, le fait de retrouver l'adresse physique à partir de l'adresse virtuelle est une opération assez pénible qui nécessite des parcours dans les pagetables de toutes façons assez longs (évidemment, les VM essayent de le rendre le moins long possible). Or, les adresses virtuelles sont dépendantes de l'espace d'adressage, donc a priori de la tâche en cours d'exécution. Comme on n'a pas moyen de préciser dans le TLB "cette association correspond à tel espace d'adressage" (tagger le TLB) sauf sur quelques architectures, il faut le vider à chaque changement de contexte. Et donc multiplier les parcours. Plus on multiplie les changements de tâche, plus on multiplie les parcours, plus on perd du temps. L4 se propose justement de résoudre ça (au moins en partie sur x86) sur au moins trois architectures (x86, PowerPC, Sparc), en utilisant des possibilités de chaque architecture. Du coup, on évite 4 fois sur 5 au moins les "vidages" de TLB.
Si vous voulez plus de détails sur les mécanismes, réferez vous aux publications de L4Ka ou aux anciens commentaires de Kilobug ou de moi. :-)