Optimiser les applications de test automatisé pour les processeurs multicœurs avec LabVIEW
Introduction
LabVIEW offre un environnement de programmation graphique unique et simple d’emploi pour les applications de test automatisé. Toutefois, c’est sa capacité à allouer du code de façon dynamique aux cœurs de plusieurs unités centrales qui améliore les vitesses d’exécution sur des processeurs multicœurs. Apprenez à optimiser des applications LabVIEW pour profiter de techniques de programmation parallèle.
Table des matières
Le défi de la programmation multithread
Récemment, les innovations en technologies des processeurs ont abouti à des ordinateurs dont les unités centrales (UC) fonctionnent à des vitesses d'horloge très élevées. Toutefois, au fur et à mesure que les vitesses d'horloge se rapprochent de leurs limites physiques théoriques, de nouveaux processeurs voient le jour avec plusieurs cœurs de traitement, au lieu d’un seul uniquement. Avec de nouveaux processeurs multicœurs, les applications de test automatisé obtiennent de meilleures performances et un débit plus élevé, en utilisant des techniques de programmation parallèle. Dr Edward Lee, éminent professeur de génie informatique et électrique à l'Université de Californie à Berkeley, décrit ainsi les avantages du traitement parallèle :
“Un grand nombre de technocrates prédisent que la fin de la loi de Moore sera obtenue avec des architectures à ordinateurs de plus en plus parallèles". Si nous souhaitons continuer à obtenir de bonnes performances de calcul, les programmes doivent être capables d’exploiter ce parallélisme".
De surcroît, il est communément reconnu que programmer des applications pour profiter des multiprocesseurs est un défi important en matière de programmation. Bill Gates, fondateur de Microsoft, Inc. explique ce défi avec les mots suivants :
Pour exploiter pleinement la puissance de processeurs fonctionnant en parallèle,... les logiciels doivent traiter le problème de la concurrence. "Mais comme n’importe quel développeur qui a déjà écrit du code multithread pourrait vous le dire, c’est l’une des tâches les plus ardues en programmation."
Heureusement, LabVIEW offre un environnement de programmation idéal pour les processeurs multicoeurs parce qu’il propose un environnement intuitif capable de créer des algorithmes parallèles ; et aussi parce qu’il permet d’allouer de façon dynamique plusieurs threads à une application donnée. En fait, les applications de test automatisé qui utilisent des processeurs multicœurs peuvent être facilement optimisées pour obtenir les meilleures performances possibles. En outre, les instruments modulaires PXI Express profitent de cet avantage grâce aux taux de transfert de données élevés, rendus possibles avec le bus PCI Express. Deux applications spécifiques qui profitent des processeurs multicœurs et des instruments PXI Express sont : l'analyse de signaux multivoies et le traitement en ligne (Hardware-In-the-Loop, HIL). Dans ce tutorial, nous allons évaluer plusieurs techniques de programmation parallèle et caractériser les avantages en termes de performances que chaque technique produit.
Mise en œuvre d’algorithmes de tests parallèles
Une application de test automatisé (ATE) courante qui profite du traitement parallèle est l’analyse de signaux multivoies. Vu que l’analyse de fréquence est une opération qui sollicite beaucoup le processeur, on pourra améliorer la vitesse d’exécution en rendant le code de test parallèle, de sorte que le traitement de signaux de chaque voie peut être distribué vers plusieurs cœurs de processeur. Côté programmeur, le seul changement requis pour en profiter est de simplement restructurer l’algorithme de test.
Pour illustrer ce principe, nous allons comparer les temps d’exécution de deux algorithmes pour une analyse de fréquence multivoies (transformée de Fourier ou FFT) sur deux voies d'un numériseur haute vitesse. Dans notre test, deux voies du numériseur PXIe-5122 haute vitesse 14 bits servent à acquérir des signaux à une vitesse d’échantillonnage maximale (100 Méch./s). D’abord, nous présentons le modèle de programmation séquentielle traditionnel pour cette opération dans LabVIEW.

Figure n°1. Code LabVIEW utilisant l’exécution séquentielle
Dans le diagramme ci-dessus, l’analyse de fréquence de deux voies s’effectue dans un VI Express FFT qui analyse chaque voie en série. Tandis que l’algorithme présenté ci-dessus peut toujours s’effectuer de façon efficace dans des processeurs multicœurs, il est possible d'améliorer ses performances en traitant chaque voie en parallèle.
Si nous devions décrire l’algorithme ci-dessus, nous noterions que la FFT prend bien plus de temps à se terminer que l’acquisition d’un numériseur haute vitesse. En relevant chaque voie l’une après l’autre et en effectuant deux FFT en parallèle, nous sommes en mesure de réduire, de façon conséquente, le temps de traitement. Un nouveau diagramme LabVIEW utilisant la notion parallèle est illustré ci-dessous :

Figure n°2. Code LabVIEW utilisant l’exécution parallèle
Comme l’illustre le code ci-dessus, chaque voie du numériseur sera relevée de façon séquentielle. Notez que ces opérations peuvent se faire complètement en parallèle si les deux relevés proviennent d'instruments uniques. Toutefois, étant donné qu'une transformée de Fourier sollicite beaucoup le processeur, nous sommes toujours capables d'améliorer les performances simplement en rendant le traitement de signaux parallèle. En conséquence, le temps d’exécution total s’en trouve réduit. Le temps d’exécution des deux implémentations figure ci-dessous.

Figure n°3. Temps d’exécution des algorithmes séquentiels ou parallèles (temps)
Comme l’illustre la figure ci-dessus, à mesure que la taille des blocs – échantillons par relevé) augmente, le temps de traitement enregistré via l’exécution parallèle devient bien plus évidente. En fait, l’algorithme parallèle multiplie les performances par deux pour des blocs de taille plus importante. Le graphe ci-dessous illustre l’augmentation exacte des performances en pourcentage en fonction de taille d'acquisition (dans les échantillons).
Figure n°4. Augmentation des performances des algorithmes parallèles (pourcentage)
La Figure n°4 prouve que pour les tailles de blocs supérieures à 1 million d’échantillons (résolution de bande passante de 100 Hz), l’approche parallèle génère une augmentation des performances de 80 % ou plus.
Configurer des algorithmes de test parallèle personnalisés
L’intérêt de rendre des algorithmes de traitement de signaux parallèles est de permettre à LabVIEW de diviser l'utilisation de l'unité centrale entre plusieurs cœurs. Dans la figure ci-dessous, nous illustrons l'ordre dans lequel l'unité centrale traite chaque partie de l'algorithme.

Figure n°5. Exécution du processus par l’unité centrale
Comme l’illustre le graphe, LabVIEW est capable de traiter l’essentiel des données acquises en parallèle, ce qui fait gagner du temps d'exécution. Il s’agit pour LabVIEW de faire une copie (un clône) de chaque sous-routine de traitement de signaux. Par défaut, bon nombre des algorithmes de traitement de signaux LabVIEW sont configurés pour une "exécution réentrante". Cela signifie que LabVIEW va allouer de façon dynamique une seule et unique instance de chaque sous-routine, incluant des threads séparés et l'espace mémoire. En conséquence, les sous-routines personnalisées doivent être configurées pour fonctionner en mode réentrant. Cela peut se faire avec une simple étape de configuration dans LabVIEW. Pour fixer cette propriété, sélectionnez Fichier >> Propriétés du VI et sélectionnez la catégorie "Exécution". Ensuite, cochez la case Exécution réentrante comme ci-dessous.

Figure n°6. Configurer l’exécution réentrante dans LabVIEW
Optimiser les applications HIL
Une autre application qui profite des techniques de traitement de signaux parallèle est l’utilisation de plusieurs instruments pour une entrée et une sortie simultanées. En général, on parle d’applications HIL ou de traitement en ligne. Dans ce scénario, un numériseur haute vitesse ou un module d'E/S numériques haute vitesse sert à acquérir un signal. Dans le logiciel, un algorithme de traitement de signaux numériques s'effectue. Finalement, le résultat est généré par un autre instrument modulaire. Un diagramme type est illustré ci-dessous.

Figure n°7. Diagramme de traitement de signaux en ligne (HIL)
Les applications HIL courantes incluent : un traitement de signaux numériques en ligne (filtrage, interpolation, etc.), une simulation de capteurs et une émulation de composants personnalisés. Dans ce tutorial, nous allons découvrir les techniques susceptibles d’offrir le meilleur débit dans des applications de traitement de signaux numériques en ligne.
En général, deux structures de programmation élémentaires peuvent servir : la structure monoboucle, et la structure multiboucle en mode pipeline avec files d’attente. La structure monoboucle est simple à mettre en œuvre et présentera une faible latence pour de petites tailles de blocs. Sinon, les architectures multiboucles sont capables d’un débit nettement supérieur parce qu’elles sont en mesure de mieux exploiter les unités centrales multicœurs.
En utilisant l’approche monoboucle traditionnelle, une fonction de lecture de numériseur haute vitesse, un algorithme de traitement de signaux et une écriture des E/S numériques haute vitesse sont placés dans un ordre séquentiel. Comme l’illustre le diagramme ci-dessous, chacune de ces sous-routines doit s’exécuter en série, selon le modèle de programmation par flux de données de LabVIEW.

Figure n°8. Approche monoboucle du traitement dans la boucle
La structure monoboucle est sujette à plusieurs restrictions. Étant donné que chaque étape s’effectue en série, le processeur a du mal à réaliser les E/S d'instrument tout en traitant les données. Avec cette approche, une unité centrale multicœur ne peut pas être utilisée de façon efficace parce que le processeur ne peut exécuter qu’une seule fonction à la fois. Ainsi, un seul cœur d’une unité centrale multicœur sera utilisé pour l’application. Alors que la structure monoboucle suffit aux vitesses d’acquisition plus basses, une approche multiboucle est nécessaire pour un débit de données plus élevé.
L’architecture multiboucle utilise des structures en files d'attente pour acheminer les données entre chaque boucle While. Ci-dessous, nous présentons le concept de programmation par flux de données entre les boucles While avec une structure en file d’attente.

Figure n°9. Les structures de files d’attente permettent à plusieurs boucles de partager les données
Comme le montre la figure, les files d’attente permettent de partager les données entre plusieurs boucles. La figure ci-dessus représente ce qu’on appelle communément une structure de boucle Producteur/Consommateur. Dans ce cas-là, un numériseur haute vitesse acquiert des données dans une boucle et transmet un nouvel ensemble de données à chaque itération de la FIFO. La boucle consommateur contrôle simplement le statut de la file d’attente et écrit chaque ensemble de données sur disque dès qu’elles sont disponibles. L’intérêt d’utiliser des files d’attente est que les deux boucles sont capables de s’exécuter séparément l’une de l’autre. Dans l’exemple ci-dessus, le numériseur haute vitesse peut continuer à acquérir les données même s’il y a un retard dans leur écriture sur disque. Les autres échantillons sont simplement stockés dans la FIFO entre temps. Généralement, l'approche en mode pipeline Producteur/Consommateur permet un débit de données plus élevé en permettant une utilisation du processeur plus efficace. Cet avantage est encore plus net dans les processeurs multicœurs parce que LabVIEW peut allouer dynamiquement des threads d’unité centrale à chaque cœur.
Pour une application de traitement de signaux en ligne, nous pouvons utiliser trois boucles While indépendantes et deux structures de files d’attente pour acheminer les données entre elles. Dans ce scénario, une boucle va acquérir les données d’un instrument, une autre va effectuer un traitement de signaux dédié, et la troisième va écrire les données sur un second instrument. Un diagramme LabVIEW illustrant ce principe est présenté ci-dessous :

Figure n°10. Traitement de signaux en mode pipeline avec plusieurs boucles et des structures de files d’attente
Dans la figure ci-dessus, la boucle du haut est une boucle Producteur qui acquiert les données d’un numériseur haute vitesse et les transmet à la première structure de file d’attente (FIFO). La boucle du milieu fonctionne à la fois comme producteur et comme consommateur. à chaque itération, elle décharge (consomme) plusieurs ensembles de données en provenance de la structure de file d'attente et les traite séparément en mode pipeline. Le principe du pipeline améliore les performances du traitement dans les processeurs multicœurs en permettant jusqu'à quatre ensembles de données d’être traités séparément. Notez que la boucle du milieu fonctionne aussi comme producteur, en transmettant les données traitées dans la seconde structure de file d'attente. Finalement, la boucle du bas écrit les données traitées vers le module d'E/S numériques haute vitesse.
Les algorithmes de traitement parallèle améliorent l’utilisation des processeurs sur les unités centrales multicœurs. En fait, le débit total dépend de deux facteurs : de l’utilisation du processeur et des vitesses de transfert du bus. En général, l'unité centrale et le bus de données fonctionnent mieux en traitant des blocs de données volumineux. En outre, nous pouvons réduire encore davantage les durées de transfert de données en utilisant des instruments PXI Express, qui présentent des vitesses de transfert plus élevées. En conséquence, nous illustrons le débit maximal en termes de fréquence d'échantillonnage selon la taille de l'acquisition en échantillons. Voir ci-dessous :

Figure n°11. Débit des structures mono et multiboucles
Remarque: ne pas confondre les trois boucles (cf. Figure n°10) avec les "2-stage pipeline" (correspondant à un empilement-dépilement) et le "4-stage pipeline" (correspondant à un empilement-dépilement-empilement-dépilement).
Tous les tests de performances illustrés dans ce graphe ont été effectués sur des échantillons 16 bits. De surcroît, l’algorithme de traitement de signaux utilisé était un filtre passe bas de Butterworth de 7ème ordre avec une fréquence de coupure de 0,45 x fréquence d’échantillonnage. Comme le montrent les données, l’approche en mode pipeline à 4 étapes (multiboucles) permet le débit de données le plus élevé. Notez qu’une approche de traitement de signaux à 2 étapes atteint de meilleures performances que la méthode monoboucle (séquentielle), mais qu’elle n'utilise pas l’unité centrale aussi efficacement que la méthode à 4 étapes. Les fréquences d’échantillonnage listées ci-dessus sont le taux d'échantillonnage maximal des entrées et sorties d’un numériseur haute vitesse PXIe-5122 et d’un module d'E/S numériques haute vitesse PXIe-6537. Notez aussi qu'à 20 Méch./s, le bus de l’application transfère les données à des vitesses de 40 Mo/s en entrée et 40 Mb/s en sortie pour une largeur de bande de bus totale de 80 Mo/s.
Conclusion
L’instrumentation sur PC, comme les instruments modulaires PXI et PXI Express, profite largement des avancées des technologies de processeurs multicœurs et des vitesses de bus de données améliorées. Au fur et à mesure que les performances des nouvelles unités centrales s’améliorent en ajoutant plusieurs cœurs de traitement, des structures de traitement parallèles ou en mode pipeline sont nécessaires pour optimiser l’efficacité de l’unité centrale. Heureusement, LabVIEW offre une excellente solution à ce problème de programmation en allouant de façon dynamique des tâches de traitement aux cœurs de traitement séparés. Comme l’illustrent les données ci-dessus, on peut obtenir des améliorations importantes en termes de performances en structurant les algorithmes LabVIEW pour profiter du traitement parallèle.
LabVIEW 8.5 intègre le multicoeur
Les principes fondamentaux de la programmation multicoeur
Ressources de programmation multicoeur
Législation
Ce tutorial a été développé par National Instruments. Bien qu'un support technique puisse être fourni pour ce tutorial, il n'a pas été complètement testé ni vérifié, et NI ne garantit pas sa qualité, ni qu'il continuera à être supporté pour les nouvelles versions des produits et drivers qui y sont rattachés. CE TUTORIAL EST FOURNI "EN L'ÉTAT" SANS GARANTIE D'AUCUNE SORTE, ET EST SUJET À CERTAINES RESTRICTIONS COMME PLUS SPÉCIFIQUEMENT DÉTERMINÉES DANS LES CONDITIONS D'UTILISATION DE NI.COM (http://ni.com/legal/termsofuse/unitedstates/us/).

