• Aucun résultat trouvé

9.2 Temps d’extraction d’une clé

9.2.3 Parallélisation des extractions

Les programmes informatiques ont longtemps été conçus de façon linéaire : il n’existe alors qu’un fil d’exécution, et les instructions s’enchaînent de façon séquen- tielle, de sorte que l’instruction n ne peut être réalisée que si l’instruction n1 est

terminée. Ce type de programmation a l’avantage d’être relativement facile à conce- voir pour le programmeur, puisque le programme suit les instructions ligne par ligne. Il n’est en revanche pas optimal : par exemple, lors d’un accès mémoire, le proces- seur reste inactif pendant plusieurs dizaines de cycles, qui pourraient être utilisés pour exécuter une instruction indépendante.

Depuis assez longtemps, une alternative à cette programmation linéaire a été mise en place dans les langages courants, appelée programmation multi-fils. Plusieurs fils d’exécution sont créés, et les instructions de chaque fil se déroulent de façon indépen- dante. Ainsi, pendant que l’un des fils doit mettre en mémoire une quantité importante de données, le processeur peut continuer l’exécution de l’autre fil. Ce type de program- mation permet de réduire le nombre de cycles perdus par le programme.

Dans les dernières années, une nouvelle architecture de processeurs a été déve- loppée, appelée multi-cœurs, dans laquelle le processeur est constitué de plusieurs sous-processeurs pouvant travailler en parallèle. Nous avons intégré l’un de ces pro- cesseurs dans notre système : il s’agit d’un processeur Intel de type Core 2 Quad, qui contient 4 cœurs indépendants. Ces processeurs sont donc particulièrement adaptés à la programmation multi-fils, puisqu’un fil n’a pas besoin d’attendre que les autres fils aient terminé leurs instructions pour reprendre son exécution. À l’inverse, si un programme linéaire est exécuté sur un processeur multi-cœur, un seul des cœurs est mis à contribution, et les autres sont inactifs : une partie de la puissance est perdue. Mise en place de la structure multi-fils

Pour que les étapes les plus chronophages puissent être exécutées en parallèle, notre programme global a été divisé en plusieurs fils. La figure 9.3 résume cette parallélisa- tion. Le fil principal est celui lancé par l’utilisateur, c’est-à-dire le fil de gestion des communications et de l’extraction (Node et CSKDP). Dans un premier temps, un fil secondaire est créé au démarrage du programme, à travers la librairie libqkd : il s’agit du sous-programme de gestion de la transmission quantique. Par la suite, n1 fils

d’extraction de clé sont ouverts par CSKDP, de façon à ce que le programme effectue n réconciliations en parallèle. A un moment donné, nous pouvons donc avoir jusque n 1 fils fonctionnant en parallèle.

La programmation multi-cœur est donc très puissante mais délicate à réaliser pro- prement. En effet, les fils ne sont jamais complètement indépendants, et partagent un certain nombre de variables. Il faut alors s’assurer que deux fils ne puissent pas modi- fier une variable partagée en même temps, pour éviter les conflits. L’exemple le plus caractéristique dans notre système est celui des blocs de données. D’un côté, le pro- gramme de gestion de la transmission génère des blocs de données régulièrement, qu’il

9.2. Temps d’extraction d’une clé 151

Fil principal

et extraction 3 Extraction 1 Extraction 2 Hardware

Démarrer hardware Interrompre hardware

Fils d'exécution

Démarrer extrac. 1 Démarrer extrac. 2 Ex tr ac tion 3 Ex tr ac tion 1 Ex tr ac tion 2 Clé 1 Clé 2 Clé 3 (Boucle)

Figure 9.3 :Schéma de la structure multi-fils, pour 3 extractions de clé. Après avoir démarré

le fil hardware, le fil principal appelle un fil d’extraction de clé, puis un deuxième ; la troisième extraction est réalisée par le fil principal. Ainsi, trois clés sont produites en parallèle. Le fil principal a un contrôle total sur les autres fils.

traite tout d’abord en interne, puis place dans une « banque de blocs ». De l’autre, le programme principal récupère ces blocs dans la banque quand il en a besoin, de façon à démarrer une extraction de clé. Or, la banque ne peut pas être modifiée en même temps par les deux parties, ce qui résulterait de façon à peu près certaine en une erreur de segmentation.

Il est donc nécessaire d’établir un protocole d’accès aux données partagées, qui utilise des structures d’exclusion mutuelle (ou mutex). Ces structures, quand elles sont déclenchées par un fil d’exécution, empêchent tous les autres fils d’accéder à la variable concernée. Ceux-ci doivent alors attendre que la variable soit libérée pour y accéder de nouveau. Qui plus est, les mutex doivent être placés de façon pertinente, pour qu’un fil n’empêche pas le fonctionnement des autres ; en particulier, quand le fil principal accède aux données, il ne doit absolument pas bloquer le fonctionnement du fil de gestion de la transmission, car ce dernier doit envoyer des données aux cartes toutes les 100 millisecondes. Des structures de buffer ont donc été mises en place pour éviter de bloquer les fils, afin de nous assurer que le système fonctionne correctement. Conséquences sur la vitesse

La mise en parallèle des extractions de clé a permis d’accélérer la vitesse de traite- ment des données de façon significative. Le tableau ci-dessous donne les temps totaux

152 Chapitre 9 : Performances de l’extraction

d’exécution de n réconciliations de clé (pour des paramètres typiques) lorsque n fils d’extraction fonctionnent en parallèle. Ces temps d’exécution sont calculés grâce aux structures clock et time(), qui sont un standard C++.

Nombre de fils d’extraction Temps d’exécution Temps d’exécution par clé

1 24 secondes 24 secondes 2 30 secondes 15 secondes 3 34 secondes 11,3 secondes 4 40 secondes 10 secondes 5 49 secondes 9,7 secondes 10 94 secondes 9,4 secondes

Puisque notre processeur ne comporte que 4 cœurs, il ne peut exécuter plus de 4 fils de façon complètement autonome. Au delà, deux fils seront exécutés sur le même cœur. Assez logiquement, ce résultat se retrouve dans le temps d’exécution du pro- gramme : jusque 3 fils d’exécution (plus le fil hardware), le temps d’extraction par clé diminue beaucoup, c’est-à-dire que la parallélisation est efficace. Au delà, non seule- ment le temps devient presque linéaire du nombre de fils, mais le fait que certains fils d’exécution soient effectués sur le même cœur que le fil hardware rend ce dernier très instable. Il n’est en pratique pas possible de faire fonctionner plus de trois extractions parallèles.

9.3 Résultats expérimentaux

9.3.1

Distance limite de transmission et taux de clé