• Aucun résultat trouvé

Adaptation du calcul de la Transformée de Fourier Rapide sur une architecture mixte CPU/GPU intégrée

N/A
N/A
Protected

Academic year: 2021

Partager "Adaptation du calcul de la Transformée de Fourier Rapide sur une architecture mixte CPU/GPU intégrée"

Copied!
114
0
0

Texte intégral

(1)

HAL Id: tel-01245958

https://hal.inria.fr/tel-01245958v2

Submitted on 13 Jan 2016

HAL is a multi-disciplinary open access

archive for the deposit and dissemination of sci-entific research documents, whether they are pub-lished or not. The documents may come from teaching and research institutions in France or abroad, or from public or private research centers.

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des établissements d’enseignement et de recherche français ou étrangers, des laboratoires publics ou privés.

Rapide sur une architecture mixte CPU/GPU intégrée

Mohamed Amine Bergach

To cite this version:

Mohamed Amine Bergach. Adaptation du calcul de la Transformée de Fourier Rapide sur une archi-tecture mixte CPU/GPU intégrée. Autre [cs.OH]. Université Nice Sophia Antipolis, 2015. Français. �NNT : 2015NICE4060�. �tel-01245958v2�

(2)

ECOLE DOCTORALE STIC

SCIENCES ET TECHNOLOGIES DE L’INFORMATION ET DE LA COMMUNICATION

THESE

pour l’obtention du grade de

Docteur en Sciences

de l’Université Nice-Sophia Antipolis

Mention : Informatique

présentée et soutenue par

Mohamed Amine BERGACH

Adaptation du calcul de la Transformée de Fourier Rapide sur une

architecture mixte CPU/GPU intégrée

Thèse dirigée par Robert DE SIMONE soutenue le 2 Octobre 2015

Jury :

M. Olivier SENTIEYS Examinateur M. Jean-François MÉHAUT Rapporteur

M. Albert COHEN Rapporteur

M. RobertDESIMONE Directeur de thèse

M. Serge TISSOT Encadrant de thèse entreprise M. Michel SYSKA co-Encadrant de thèse

(3)
(4)
(5)
(6)
(7)
(8)

Je tiens à remercier en premier lieu Robert de Simone d’avoir accepté d’être le direc-teur de cette thèse.

Mes remerciements vont conjointement et tout particulièrement à Serge Tissot et Michel Syska pour leur encadrement, leur soutien et leur confiance qui m’ont permis de mener à bien ce projet.

Je remercie également les rapporteurs de cette thèse Albert Cohen et Jean-François Méhaut de s’être portés volontaires à la lecture de mon mémoire. Merci également aux autres membres du jury.

Je tiens à remercier une dernière fois Robert de Simone, Michel Syska et Serge Tissot pour leur relecture de mes travaux et de m’avoir soumis leurs corrections tant sur la forme que sur mon français parfois approximatif.

Enfin, je tiens à montrer ma gratitude à tout le soutien apporté par mes proches, ma famille, plus particulièrement mes parents pour leurs encouragements ; sans ou-blier mes amis qui ont su me motiver en s’informant régulièrement de l’avancement de mon travail.

Cette thèse n’aurait sûrement pas abouti sans cet entourage qui a su apporter, chacun à leur manière, une aide réconfortante et précieuse.

Merci.

(9)

Les architectures multi-cœurs Intel Core (IvyBridge, Haswell,...) contiennent à la fois des cœurs CPU généralistes (4), mais aussi des cœurs dédiés GPU embarqués sur cette même puce (16 et 40 respectivement). Dans le cadre de l’activité de la société Kontron (qui participe à ce financement de nature CIFRE) un objectif important est de calculer efficacement sur cette architecture des tableaux et séquences de trans-formées de Fourier rapides (FFT), comme par exemple on en trouve dans des appli-cations radar. Alors que des bibliothèques natives (mais propriétaires) existent chez Intel pour les CPU, rien de tel n’est actuellement disponible pour la partie GPU.

L’objectif de la thèse était donc de définir le placement efficace de modules FFT, en étudiant au niveau théorique la forme optimale permettant de regrouper des étages de calcul d’une telle FFT en fonction de la localité des données sur un cœur de calcul unique. Ce choix a priori permet d’espérer une efficacité des traitements, en ajustant la taille de la mémoire disponible à celles des données nécessaires.

Ensuite la multiplicité des cœurs reste exploitable pour disposer plusieurs FFT calculées en parallèle, sans interférence (sauf contention du bus entre CPU et GPU). Nous avons obtenu des résultats significatifs, tant au niveau de l’implantation d’une FFT (1024 points) sur un cœur CPU SIMD, exprimée en langage C, que pour l’implan-tation d’une FFT de même taille sur un cœur GPU SIMT, exprimée alors en OpenCL. De plus nos résultats permettent de définir des règles pour synthétiser automatique-ment de telles solutions, en fonction uniqueautomatique-ment de la taille de la FFT son nombre d’étages plus précisément), et de la taille de la mémoire locale pour un cœur de calcul donné. Les performances obtenues sont supérieures à celles de la bibliothèque na-tive Intel pour CPU), et démontrent un gain important de consommation sur GPU. Tous ces points sont détaillés dans le document de thèse. Ces résultats devraient don-ner lieu à exploitation au sein de la société Kontron.

(10)

Multicore architectures Intel Core (IvyBridge, Haswell...) contain both general pur-pose CPU cores (4) and dedicated GPU cores embedded on the same chip (16 and 40 respectively). As part of the activity of Kontron (the company partially funding this CIFRE scholarship), an important objective is to efficiently compute arrays and se-quences of fast Fourier transforms (FFT) such as one finds in radar applications, on this architecture. While native (but proprietary) libraries exist for Intel CPU, nothing is currently available for the GPU part.

The aim of the thesis was to define the efficient placement of FFT modules, and to study theoretically the optimal form for grouping computing stages of such FFT according to data locality on a single computing core. This choice should allow pro-cessing efficiency, by adjusting the memory size available to the required application data size. Then the multiplicity of cores is exploitable to compute several FFT in pa-rallel, without interference (except for possible bus contention between the CPU and the GPU). We have achieved significant results, both in the implementation of an FFT (1024 points) on a SIMD CPU core, expressed in C, and in the implementation of a FFT of the same size on a GPU SIMT core, then expressed in OpenCL.

In addition, our results allow to define rules to automatically synthesize such solu-tions, based solely on the size of the FFT (more specifically its number of stages), and the size of the local memory for a given computing core. The performances obtained are better than the native Intel library for CPU, and demonstrate a significant gain in consumption on GPU. All these points are detailed in the thesis document. These results should lead to exploitation of the code as library by the Kontron company.

(11)

Résumé i Abstract ii Abréviations x 1 Introduction 1 1.1 Contexte et objectifs . . . 1 1.2 Contributions . . . 2 1.3 Organisation . . . 3

2 Applications visées et modélisation 4 Motivations . . . 4

2.1 Transformée de Fourier discrète et algorithme FFT de base . . . 4

2.1.1 Transformée de Fourier discrète . . . 4

2.1.2 Version de base FFT de Cooley-Tukey . . . 6

2.1.3 Calcul optimisé du bloc de base « papillon » . . . 8

2.1.4 Opération bit reverse . . . 12

2.2 Variantes algorithmiques de la FFT . . . 13 2.2.1 Cooley-Tukey . . . 14 2.2.2 Radix-2 DIF . . . 14 2.2.3 Mixed radix . . . 15 2.2.4 Split-Radix FFT . . . 16 2.2.5 Stockham . . . 16 2.2.6 Autres versions . . . 18

2.2.7 Analyse et comparaison entre les versions . . . 18

2.3 Applications basées sur la FFT : exemple de détection Radar . . . 18

Bilan et discussion . . . . 21

3 Les architectures de calcul intensif 22 Motivations . . . 22

3.1 Parallélisme "on-chip" (généralités) . . . 22

3.1.1 Parallélisme d’instructions . . . 22

3.1.1.1 FMA fused multiply-add . . . . 23

3.1.1.2 SMT simultaneous multithreading . . . . 23

3.1.2 Le multicœur . . . 25

3.2 Modèle SIMD pour CPU . . . 26

(12)

3.2.1 Principes et modèle de programmation . . . 26

3.2.2 Mise en œuvre (intrinsics) . . . 27

3.2.3 Permutations de valeurs . . . 29

3.3 Modèle SIMT pour GPU . . . 30

3.3.1 Évolution des GPU . . . 30

3.3.2 Principes et modèle de programmation . . . 31

3.3.3 Lien entre GPU et CPU, et transferts de données . . . 32

3.3.4 Mise en œuvre (OpenCL) . . . 34

3.4 Architecture Intel Core considérée chez Kontron . . . . 36

3.4.1 GPU Intel . . . 36

3.4.2 Unité d’exécution . . . 38

3.4.3 Hiérarchie mémoire . . . 40

3.4.4 Interconnexion . . . 41

3.5 Mesures expérimentales sur les architectures Intel Core . . . . 42

3.5.1 Débit de calcul maximum . . . 42

3.5.2 Taille des work-groups . . . . 44

3.5.2.1 Débit de transfert mémoire et work-groups . . . . 45

3.5.2.2 Calcul et taille du work-group . . . . 46

Bilan et discussion . . . . 47

4 Adaptation de la FFT sur l’architecture 49 Motivations . . . 49

4.1 Adaptation SIMD puis SIMT sur un bloc élémentaire GPU . . . 50

4.1.1 Démarche d’adaptation sur GPU . . . 50

4.1.2 Cœur de calcul . . . 51

4.1.3 Approche locale (« in-register » ) . . . . 52

4.1.3.1 Taille maximale de la FFT . . . 53

4.1.3.2 Optimisation de l’espace registres . . . 54

4.1.3.3 SIMD sur GPU en OpenCL . . . 55

4.1.4 Approche SIMT . . . 57

4.1.4.1 Adaptation au registres . . . 57

4.1.4.2 Adaptation à la mémoire partagée . . . 59

4.1.4.3 Organisation des calculs FFT . . . 62

4.1.4.4 Approche adaptative FFT . . . 65

4.1.5 Synthèse de code . . . 68

4.1.6 Expérimentation et résultats pratiques . . . 68

4.2 Adaptation SIMD sur un cœur CPU . . . 70

4.2.1 Cœur de calcul . . . 71

4.2.2 Première implémentation SIMD . . . 72

4.2.3 Deuxième implémentation SIMD : Adaptation des permutations 76 4.2.4 Expérimentation et résultats pratiques . . . 79

Bilan et discussion . . . . 81

5 Performances système et distribution de l’application globale 82 Motivations . . . 82

(13)

5.1.1 Sur multicœur CPU . . . 83

5.1.1.1 Performances CPU . . . 83

5.1.1.2 Dissipation thermique et consommation . . . 84

5.1.2 Sur GPU . . . 85

5.1.3 Conséquences . . . 88

5.2 Dimensionnement pour application radar . . . 88

5.2.1 Besoins en calculs FFTs . . . 88

5.2.2 Adaptation de la charge de calcul aux contraintes . . . 89

Bilan et discussion . . . . 91

6 Conclusion et Travaux Futurs 92 6.1 Related Works . . . 92

(14)

2.1 Décomposition d’un signal . . . 5

2.2 Évolution des twiddle factors dans le temps . . . . 6

2.3 Signal flow graph FFT basique . . . . 9

2.4 Bloc de base papillon FFT . . . 9

2.5 Opérations papillon standard . . . 9

2.6 Opérations papillon optimisé . . . 11

2.7 Précision de calcul FFT . . . 12

2.8 Bit reverse 8 points . . . 13

2.9 Convolution et Bit reverse . . . 13

2.10 SFG FFT DIT 8 . . . 14

2.11 SFG FFT DIF 8 . . . 15

2.12 Mixed radix FFT 8 points . . . 15

2.13 Split-radix FFT . . . 17

2.14 Signal flow graph Algorithme de Stockham . . . 17

2.15 Choix matériels pour un système Radar . . . 19

2.16 Schéma bloc RDA SAR . . . 20

3.1 Flux d’instruction classique . . . 24

3.2 Avec hyperthreading . . . 24

3.3 Impact de l’hyperthreading sur la FFT . . . 25

3.4 Schéma CPU multicœur . . . 26

3.5 Addition vectorielle SIMD de deux vecteurs . . . 27

3.6 Évolution des unités SIMD . . . 28

3.7 Benchmark FFT sur SIMD CPU . . . 28

3.8 Instruction de permutation SIMD . . . 30

3.9 Architecture d’un Execution unit GPU . . . 31

3.10 Organisation des unités d’exécution du GPU d’AMD E6760 . . . 31

3.11 Exécution SIMT en mode cohérent . . . 32

3.12 Exécution SIMT en mode divergent . . . 32

3.13 SIMT Taxonomie . . . 32

3.14 interconnexion CPU-GPU . . . 33

3.15 débits PCIe . . . 33

3.16 Architecture CPU Intel IvyBridge . . . 33

3.17 Exemple kernel OpenCL qui additionne deux vecteurs d’entiers . . . . 34

3.18 Type vectoriel OpenCL . . . 35

3.19 Compilation OpenCL . . . 36

3.20 Architecture GPU Intel IvyBridge . . . 37

(15)

3.21 Mapping sur EU GPU intel . . . 38

3.22 Architecture Mémoire GPU Intel . . . 40

3.23 Interconnexion CPU GPU intégrés Intel . . . 41

3.24 Benchmark Kernel OpenCL GFlops maximum . . . 43

3.25 performances crête . . . 44

3.26 Passage à l’échelle des performances . . . 44

3.27 Benchmark kernel OpenCL qui transfère les données de la mémoire DRAM vers les registres . . . 45

3.28 Mise à l’échelle des débit Registres DRAM Work-group size =1 . . . 46

3.29 Mise à l’échelle des débit Registres DRAM Work-group size =2 . . . 46

3.30 Mise à l’échelle des débit Registres DRAM Work-group size =4 . . . 46

3.31 Mise à l’échelle des débit Registres DRAM Work-group size =8 . . . 46

3.32 Mise à l’échelle des débit Registres DRAM Work-group size =16 . . . . 47

3.33 Mise à l’échelle des débit Registres DRAM Work-group size =32 . . . . 47

3.34 Taille du work-group . . . 47

4.1 Paramètres d’adaptation FFT . . . 51

4.2 Adaptation FFT sur GPU niveau registres . . . 54

4.3 Scalairisation . . . 56

4.4 Mapping Radix-2 sur 1 work-item . . . . 57

4.5 Mapping FFT radix-4 sur 1 thread logique ou work-item . . . . 59

4.6 Mapping FFT radix-8 sur 1 thread logique ou work-item . . . . 59

4.7 Utilisation de la mémoire partagée SLM pour échanger 8KB de don-nées FFT 1024 points complexes . . . 60

4.8 Échange de données implémentation FFT 1K (radix-2) . . . 61

4.9 Organisation des calculs FFT sur un work-item . . . . 63

4.10 Mouvement des données pour une FFT 1K points sur GPU . . . 63

4.11 Organisation de l’implémentation FFT 1K sur un work-item . . . . 64

4.12 Organisation de l’implémentation FFT 1K . . . 64

4.13 Design Space FFT . . . 66

4.14 Radix-2 . . . 66

4.15 Radix-4 . . . 66

4.16 Radix-8 . . . 66

4.17 Performances FFT 1024 sur GPU IvyBridge et Haswell . . . 69

4.18 Efficacité de notre implémentation FFT 1024 sur GPU IvyBridge et Has-well . . . 70

4.19 Optimisation papillon FFT entrelacé . . . 72

4.20 Simdization FFT AVX . . . 73

4.21 Vectorisation AVX de la FFT . . . 73

4.22 Comparaison performances FFT CPU sur Haswell . . . 74

4.23 Performances par passes FFT sur CPU . . . 75

4.24 Architecture d’un cœur CPU Haswell d’Intel . . . 76

4.25 Organisation FFT vue globale . . . 77

4.26 Quatre dernières passes FFT . . . 78

4.27 Quatre dernières passes FFT choix 1 . . . 78

(16)

4.29 Performances par passes FFT sur CPU version 1 . . . 80

4.30 Performances par passes FFT sur CPU version 2 . . . 80

4.31 Performances FFT sur CPU Comparatif . . . 81

5.1 Passage à l’échelle FFT sur CPU . . . 83

5.2 Effet d’emballement thermique . . . 84

5.3 Expérience de placement des charges de calcul selon la localité du cœurs 85 5.4 Résultats thermiques sur le CPU IvyBridge d’Intel : 5°C de gain entre les cas favorables (C0,C3 et C4) et les cas défavorables (C1,C2 et C5) . . 85

5.5 Courbe des performances IVB . . . 86

5.6 Courbe des performances HSW . . . 86

5.7 analyse structure de notre kernel FFT . . . 87

5.8 Tableau de correspondance débit mémoire et performances FFT . . . . 87

5.9 Distribution des calculs FFT sur CPU et GPU (sur Intel IvyBridge) . . . 89

5.10 Besoin de l’application en puissance de calcul afin d’avoir du temps réel (1555 fois /seconde) . . . 90

5.11 Architecture de système de calcul radar à base de cartes CPU Intel Has-well . . . . 91

(17)

2.1 Classification transformées de Fourier . . . 5

3.1 Comparaison terminologie CUDA , OpenCL et OpenCL Intel . . . 35

4.1 Taille du design space pour la FFT . . . 67

4.2 Intel Ivy Bridge GPU benchmarks subset . . . 67

4.3 Intel Haswell GPU benchmarks subset . . . 67

(18)

Terme Description

APU Accelerated Processing Unit (AMD) ARF Architecture Register File AVX Advanced Vector Extensions

CS commande streamer

ECC Error Correction Code

EU Execution Unit

FMA Fused Multiply-Add

FPU Floating-point unit GRF General purpose Register File

GTI Graphics Technology Interface

HSW Haswell (Intel)

ISA Instruction Set Architecture IVB IvyBridge (Intel)

LLC Last Level Cache

MIMD Multiple instruction multiple data MMU Memory Management Unit SIMD Single instruction multiple data SIMT Single instruction multiple threads

SLM Shared local memory SMT Simultaneous Multi-Threading SPMD Single program multiple data

SMT Simultaneous Multi-Threading SWaP Size Weight and Power

TDP Thermal Design Power VLIW Very long instruction word

(19)

Introduction

La prolifération du parallélisme au sein des calculateurs est une tendance de fond maintenant bien établie. Les supercalculateurs des années 80s sont complémentés par les grappes/clusters de calcul, les data centers du cloud computing et autres

network processors ; les ordinateurs individuels sont désormais multi-cœurs et

uti-lisent des co-processeurs graphiques dédiés (GPU) ; les téléphones mobiles et autres processeurs embarqués contiennent de multiples accélérateurs graphiques de trai-tement du signal (DSP)... Désormais, nous assistons même au mélange et aux in-teractions entre ces formes multiples de parallélisme au niveau physique : les GPU apparaissent tant dans des supercalculateurs du top 500 que dans des plates-formes embarquées, la concurrence entre architectures MPPAs, FPGA ou GPU fait l’objet de discussions et débats au sein de la communauté...

La recherche de l’efficacité (en performance ou en consommation) atteint son pa-roxysme. Néanmoins, elle se traduit trop souvent par une perte de l’automatisation lors des phases de compilation, quand le parallélisme (concurrency) inhérent poten-tiel des applications doit être projeté et ajusté au parallélisme (parallelism) réel des architectures et infrastructures matérielles sous-jacentes. Des armées d’ingénieurs réimplantent et portent souvent des programmes applicatifs manuellement d’une machine à sa remplaçante, ce qui induit des pertes en productivité et en sûreté du de-sign à la compilation qui viennent souvent compenser les gains en efficacité à l’exé-cution.

1.1

Contexte et objectifs

Dans le cadre concret de cette thèse, financée par un contrat CIFRE entre Inria et la société Kontron, nous nous intéressons spécifiquement à l’architecture Intel Core (processeurs grand public IvyBridge, Haswell puis Broadwell), qui allie sur une même puce une architecture quadri-cœur CPU (x86) avec des ALU vectorielles SIMD, et des cœurs de calcul GPU avec une programmation de nature SIMT (Single Instruction

Multiple Threads). La société Kontron assemble des sous-systèmes sur cartes-mères

à partir de tels composants, pour des applications de nature professionnelle qui ré-clament à la fois efficacité et robustesse. Dans l’exemple dont nous traiterons (de manière simplifiée) au cours de cette thèse, une application radar nécessite suffisam-ment de puissance de calcul afin de calculer des opérations de traitesuffisam-ment de signal

(20)

(transformée de Fourier rapide principalement) en parallèle, en nombre important et en temps-réel. Notre approche du problème (telle qu’elle nous est progressive-ment apparue au cours de nos travaux) consistera à optimiser le traiteprogressive-ment d’une FFT (unique) sur un cœur (unique) de calcul, qu’il soit CPU ou GPU. Cette approche a comme avantage de garantir la localité des données lors de ce module de calcul, alors que les transferts de données (avec les problèmes de caches et de débit des bus internes d’interconnexion) peuvent se révéler un aspect excessivement pénalisant de la parallélisation. Ensuite, on devra dimensionner, entre les (4) cœurs CPU du proces-seur et les (16 pour Ivybridge puis 40 pour Haswell) cœurs GPU d’une même carte, afin de répartir au mieux les nombreuses occurrences de calcul FFT élémentaires, et au-delà dimensionner le système afin d’avoir la capacité de calcul désirée en utilisant plusieurs processeurs Intel Core sur une même carte.

1.2

Contributions

Le placement optimisé d’une FFT est donc un point central de notre approche. Il doit être effectué (une bonne fois pour toute, sur un cœur CPU et sur un cœur GPU) de manière spécifique, du fait que la définition récursive de cet algorithme ne suit pas les schémas de base pour l’automatisation générique de la compilation pa-rallèle (par les méthodes polyédriques notamment). Ensuite, la répartition des FFT entres les différentes ressources et cœurs de calcul ressemblera (de manière carica-turale) à une sorte de gigantesque « règle de 3 » pour équilibrer les charges de calcul. D’un point de vue pratique (et sensible pour la société Kontron), cette phase a aussi l’avantage de produire un code source natif, compréhensif et modifiable, alors que dans la situation actuelle les bibliothèque natives Intel pour le calcul FFT sur CPU ne fournissent qu’un code cible moyennement optimisé, et qu’il n’en existe simplement pas pour la compilation GPU. Nous avons également considéré les initiatives com-munautaires qui proposent des études et solutions optimisées (FFTW, Spiral,...)[1], mais elles ne répondent pas complètement à nos besoins en terme de « fine tuning » sur notre architecture, ou de disponibilité de code source pour exploitation commer-ciale. L’objectif ultime de nos travaux sera donc, non seulement de produire un code source efficace optimisé et dimensionné pour nos architectures cibles, mais encore d’étudier comment synthétiser ce code de manière modulaire à partir de certains pa-ramètre dimensionnants simples. On pourra alors espérer produire de manière au-tomatique les versions correspondant aux versions ultérieures des processeurs Intel

Core, qui semblent devoir garder des architectures similaires tout en augmentant les

tailles des paramètres et en multipliant les nombres de cœurs.

Les paramètres qui entrerons en ligne de compte dans nos calculs seront princi-palement le nombre de points requis pour la taille de FFT : 1014 généralement, ce qui correspond à 10 étages successifs de calculs de papillons élémentaires (1014 = 210) ;

ce nombre d’étages est en fait le paramètre direct qui nous concerne. Le second para-mètre d’importance sera le nombre de registres internes (ou mémoire L0) disponible dans chaque cœur (ou dans chaque bloc élémentaire de calcul) ; avec ces nombres on peut déterminer combien d’étages peuvent être exécutés sans de mouvements de données externes (juste dans les registres), ce qui fournit une information essentielle sur la granularité du découpage de la FFT, dont la réécriture à partir de blocs

(21)

amal-gamés comportant le bon nombre d’étages permet d’obtenir le code final. Tous ces points forment l’essentiel des contributions techniques de ce document.

1.3

Organisation

Le document est structuré en 6 parties, comme suit : après cette introduction, le chapitre 2 introduit la problématique du calcul de la Transformée de Fourier Discrète, avec toutes ses variantes et optimisation connues ; le chapitre décrit également la modélisation abstraite d’une application radar qui utilise intensivement cette trans-formée. Le chapitre 3 décrit les éléments majeurs d’architecture et de micro archi-tecture parallèle, jusqu’à les spécialiser pour notre archiarchi-tecture Intel Core (qui al-lie cœurs CPU SIMD X86 et cœurs GPU SIMT embarqués sur une même puce). Le chapitre 4 contient l’essentiel de nos expérimentations et résultats ayant donné lieu à la solution de placement (une FFT sur un cœur) que nous avons définie et mise en œuvre. Il contient des résultats expérimentaux validant cette approche. À noter que certains de nos résultats ou définitions « ajustées » pour préparer ces résultats se trouvaient déjà présentées dans les chapitres précédents. Le chapitre 5 décrit le pla-cement plus général des calculs de l’application radar sur l’intégralité des ressources d’une carte à base de processeurs Intel Core. Pour des raisons de temps nous n’avons pas encore pu explorer ici toutes les pistes d’optimisation et d’automatisation, mais nous savons décrire assez précisément les travaux effectués, et ceux envisagés. Enfin le chapitre 6 apporte une conclusion au travail en traçant la piste de développements futurs, ainsi que les enseignements qu’on peut en tirer dès maintenant.

(22)

Applications visées et modélisation

Motivations

Les applications RADAR et SONAR sont deux domaines exigeants en puissance de calcul. Plus particulièrement, pour les traitements RADAR les latences de calcul doivent être réduites au minimum sous peine de ne pas pouvoir détecter en temps réel les cibles en mouvement. Ces applications font appel à des bibliothèques ma-thématiques contenant une liste exhaustive de fonctions élémentaires telles que les transformées, les filtres et les opérations matricielles. Ce sont des algorithmes de type flot de données opérant sur de larges tableaux d’une ou plusieurs dimensions. Parmi les différents algorithmes qui composent ces bibliothèques, il en est un qui revêt une importance capitale dans la plupart des cas d’utilisation. Il s’agit de la transformée de Fourier rapide.

L’optimisation de la transformée de Fourier sur des architectures parallèles est donc primordiale pour atteindre des performances temps réels dans les systèmes Ra-dar : l’effort d’optimisation sur cette brique de base se traduit immédiatement par un gain majeur de performance sur tout le système.

Le but de ce chapitre est de présenter les fondamentaux de cette transformée et de son application, en portant un éclairage particulier sur les aspects qui nous intéres-serons spécialement par la suite, comme les subtiles variations algorithmiques qui permettront un ajustement à une architecture spécifique donnée. Nous conclurons le chapitre par une contribution technique, qui nous semble nouvelle, réorganisant le calcul à partir des coefficients, et qui en pratique améliore la précision du résultat.

2.1

Transformée de Fourier discrète et algorithme FFT de base

2.1.1 Transformée de Fourier discrète

Les processus physiques peuvent être décrits dans le domaine temporel à l’aide de la valeur d’une quantité h en fonction du temps t, ou bien dans le domaine fré-quentiel à l’aide de son amplitude H en fonction de sa fréquence f . On peut alors considérer que h(t) et H(f ) sont deux représentations de la même fonction modulo une transformation. La transformée de Fourier permet le passage d’une représenta-tion à une autre.

Selon le type des signaux à transformer, différents types de transformées de

(23)

rier sont définis :

Non périodique Périodique

Continue Transformée de Fourier Série de Fourier Discret DTFT (discrete time Fourier

transform)1

DFT (Discrete Fourier transform)

TABLE2.1 – Classification transformées de Fourier

Pour un signal discret et périodique la transformée correspondante porte le nom de transformée de Fourier discrète (on utilise habituellement l’abréviation anglaise DFT pour "Discrete Fourier Transform"). Nous nous focaliserons exclusivement sur ce type de transformée dans ce document.

FIGURE2.1 – Décomposition d’un signal en plusieurs signaux sinusoïdaux

Soit une séquence d’entrée x(n), la DFT de N points est définie comme suit :

X(k) =

N −1

X

n=0

x(n) · WNnk avec : k = 0, 1, . . . , N − 1 (2.1) Où l’entier n est l’index de temps, l’entier k est l’index de fréquence et le nombre complexe Wnk

N qui correspond à la racine n-ième de l’unité, communément appelé

twiddle factor, est définie comme suit :

WNnk = exp −2iπnk N  = cos 2πnk N  − i · sin 2πnk N  . (2.2)

La DFT inverse (IDFT) est exprimé comme ceci :

x(n) = 1 N · N −1 X n=0 X(n) · WN−nk avec : k = 0, 1, . . . , N − 1 (2.3) Nous observons que N multiplications complexes et N − 1 additions complexes

1. Ces signaux sont définis que dans un espace temporel discret, cette transformée est discrète dans l’espace temporel et continue dans l’espace fréquentiel.

(24)

sont nécessaires pour calculer un point, donc il nous faut N2 multiplications

com-plexes et N2−N additions complexes pour calculer une DFT/IDFT de N échantillons.

Le calcul direct de la DFT est inefficace avec l’augmentation de la taille du signal à transformer.

2.1.2 Version de base FFT de Cooley-Tukey

La transformée de Fourier rapide a été « décrétée » l’un des 10 algorithmes majeurs du 20esiècle [2]. C’est aussi l’un des plus utilisés et en 1990 il a été estimé [3] que sur une base installée de supercalculateurs Cray de 200 machines (à 25 millions de dollar US l’unité), 40% des cycles CPU sont dédiés aux calculs de la FFT.

L’algorithme de la transformée de Fourier rapide a été initialement découvert par Gauss en 1805, mais il n’a eu de succès qu’en 1965 après la publication [4] de celui-ci par J. W. Cooley et J. W. Tukey. C’est pour cette raison que l’algorithme de base porte habituellement leurs noms.

L’algorithme de la FFT est un algorithme de type « Diviser pour régner », il factorise la DFT pour réduire le nombre d’opérations de O(N2)à O(N · logN ).

Nous pouvons visualiser la structure récursive de la FFT à travers la figure 2.2 qui montre comment les racines de l’unité sont distribuées tout au long de l’algorithme de la FFT.

FIGURE2.2 – Évolution de l’utilisation des twiddle factors à travers les passes (FFT 8 points)

Nous verrons plus bas que la structure récursive est néanmoins généralement al-térée par le besoin de réordonner les données entre deux passes élémentaires de cal-cul, l’opération intermédiaire est appelée bit reverse.

On verra ultérieurement des variantes optimisant plus encore la version de base, proposant de nouveaux schémas récursifs préservant la complexité globale des cal-culs.

(25)

alors comme ceci : Soit la DFT de x(n) : X(k) = N −1 X n=0 x(n).WNnk avec : W = e2πiN (2.4) Supposons que N s’écrit sous la forme de : N = r1× r2

Soit k et n définit par :

k = k1r1+ k0 avec : k0 = 0, 1, . . . , r1− 1 et k1 = 0, 1, . . . , r2− 1 (2.5) n = n1r2+ n0 avec : n0 = 0, 1, . . . , r2− 1 et n1 = 0, 1, . . . , r1− 1 (2.6) X(k1, k0) = r2−1 X n0=0 r1−1 X n1=0 x(n1, n0) · Wkn1r2Wkn0 (2.7) avec : Wkn1r2 = Wk0n1r2 X(k1, k0) = r2−1 X n0=0 r1−1 X n1=0 x(n1, n0) · Wk0n1r2Wkn0 (2.8) On pose : X1(k0, n0) = r1−1 X n1=0 x(n1, n0) · Wk0n1r2 (2.9) X(k1, k0) = r2−1 X n0=0 X1(k0, n0) · W(k1r1+k0)n0 (2.10)

Le tableau X1contient N éléments, chacun nécessite r1opérations, ce qui donne

un total de N · r1 opérations pour obtenir X1. Pour calculer X à partir de X1 il faut

N · r2opérations. Donc, pour cet algorithme qui décompose le calcul en deux étapes,

nous avons besoin au total de : N (r1+ r2)opérations ce qui est largement inférieur

au nombre d’opérations initial qui était de N2opérations.

Si on répète cette même décomposition successivement nous aurons un algo-rithme avec m étapes et N (r1 + r2 + ... + rm)opérations avec N = r1r2...rm. Ce qui

est toujours inférieur ou égal à N2.

Donc si r1 = r2 = . . . = rm = r alors m = logrN et le nombre total d’opérations

devient :

rN logrN (2.11)

Si r = 2 alors N = 2m

Les indices n et k s’écrivent alors sous la forme :

(26)

n = nm−12m−1+ . . . + n1.2 + n0 (2.13)

Avec nxet kxprenant comme valeurs soit 0 soit 1, ce qui représente les valeurs des

bits dans la représentation binaire de k et de n.

Alors la transformée de Fourier s’écrit en fonction de la position binaire des in-dices : X(km−1, . . . , k0) = 1 X n0=0 1 X n1=0 . . . 1 X nm−1=0 x(nm−1, . . . , n0) · Wknm−12 m−1+...+kn 0 (2.14) Avec : Wknm−1·2m−1 = Wk0nm−1·2m−1

Donc la somme interne d’indice nm−1dans l’équation ne dépend que de k0, nm−2, . . . , n0

On l’écrit alors : X1(k0, nm−2, . . . , n0) = 1 X nm−1=0 x(nm−1, . . . , n0) · Wk0nm−12 m−1 (2.15) On réitère cette même procédure aux autres sommes en utilisant :

Wknm−p·2m−p = W(kp−12p−1+...+k0)nm−p·2mp (2.16) On obtient pour p = 1, 2, . . . , m Xp(k0, . . . , kp−1, nm−p−1, . . . , n0) = 1 X nm−p=0 Xp−1(k0, . . . , kp−2, nm−p, . . . , n0)·W(kp−12 p−1+...+k 0)nm−p·2m−p (2.17)

La dernière somme donne le résultat final de la transformée de Fourier :

X(km−1, . . . , k0) = Xm(k0, . . . , km−1) (2.18)

On remarque que l’index de X doit avoir son ordre binaire inversé pour que le résultat soit correct : c’est pour cela qu’une étape de bit reversing est nécessaire pour l’algorithme initial de la FFT publié par Cooley et Tukey. Cette étape sera décrite dans la section 2.1.4.

Nous notons aussi que le graphe de dépendance de données doit rester inchangé, cependant l’ordre des index peut varier tout au long de l’algorithme. Nous introdui-rons ici le graphe de flot de données utilisé dans la suite de cette thèse pour illustrer les différents algorithmes. Dans ce graphe, les données du même étage peuvent être arrangées librement en gardant les arêtes du graphe connectées. La figure 2.3 illustre le graphe de flot de données pour l’algorithme de Cooley et Tukey.

2.1.3 Calcul optimisé du bloc de base « papillon »

Tous les algorithmes FFT sont construits autour d’un bloc de base qui porte usuel-lement le nom de papillon (figure 2.4). Ce bloc prend deux valeurs complexes en

(27)

en-FIGURE2.3 – Signal flow graph basique FFT de taille 16

trée et produit aussi deux valeurs complexes en sortie. Il nécessite la multiplication de deux nombres complexes. Cette opération est calculée à l’aide de 10 opérations flottantes (typiquement : 6 additions et 4 multiplications(figure 2.5)).

FIGURE2.4 – Bloc de base papillon FFT

FIGURE2.5 – Opérations papillon standard

Une instruction ad hoc permettant d’enchainer une multiplication et une addi-tion a = a + b × c en une seule opéraaddi-tion élémentaire, existe dans la plupart des architectures matérielles modernes (à partir des processeurs DSP). On la nomme gé-néralement MAC (multiply-accumulate) pour le calcul en précision fixe, et elle porte aussi le nom de FMA (fused multiply-add)[5] pour les calculs en nombres flottants. Dans cette thèse nous nous intéressons aux calculs flottants.

Cette instruction apparait désormais dans les jeux d’instructions des GPU qui font partie de nos architectures cibles.

Nous souhaitons alors utiliser efficacement l’instruction FMA, qui permet de faire l’addition et la multiplication dans le même temps qui serait nécessaire pour faire soit une addition soit une multiplication.

En 1993 Linzer et Feig[6] [7] sont les premiers à exploiter la FMA dans les algo-rithmes de la FFT radix-2, radix-4 et split-radix. En 1997 Goedecker[8] a proposé un

(28)

algorithme qui exploite la FMA moins complexe que les algorithmes de Linzer et Feig. Aussi dans les travaux d’une thèse antérieure à celle-ci [9], portant sur les architec-tures PowerPC à Kontron, l’utilisation de l’instruction FMA a été exploitée à travers une factorisation des calculs afin d’exprimer toutes les opérations en une suite de FMA (6 au total). Ce nombre représente l’optimal en nombre d’instructions FMA, car il n’est pas possible de calculer un papillon FFT avec moins de 6 FMA.

La factorisation effectuée pour exploiter la FMA dans les travaux antérieurs à cette thèse est de type :

ax + by → a(x + (b/a)y) (2.19)

Nous notons ar et br la partie réelle des valeurs d’entrée de notre papillon et ai

et bileurs parties imaginaires. De même ωret ωi les parties réelles et imaginaires du

twiddle factor. Les résultats de notre papillon sont notés Ar et Br pour les parties

réelles, Aiet Bipour les parties imaginaires. Le papillon standard est alors calculé en

10 opérations selon les équations suivantes (2.20),(2.21) :

Ar= ar+ (ωr· br− ωi· bi) Ai = ai+ (ωi· br+ ωr· bi) (2.20)

Br = ar− (ωr· br− ωi· bi) Bi = ai− (ωi· br+ ωr· bi) (2.21)

En appliquant la factorisation décrite plus haut, le papillon devient : Ar = ar− (bi− ωr ωi · br) · ωi Ai = ai+ ( ωr ωi · bi+ br) · ωi (2.22) Br = ar+ (bi− ωr ωi · br) · ωi Bi = ai− ( ωr ωi · bi+ br) · ωi (2.23)

Cette factorisation est correcte dans le cas où ωi 6= 0, cependant quand ωi = 0

nous devons le remplacer par une valeur très petite, à savoir ωi = 0, 0000001.

Cette méthode est très efficace mais elle présente un inconvénient du point de vue mathématique, car si nos twiddle factors sont remplacés par une valeur très petite dans le cas où ωi est égal à zéro, ceci engendre une dégradation de la précision de

calcul, cette dernière est mesurée plus tard.

Notre contribution [10] que nous décrivons ici permet de s’affranchir de cette li-mitation, et permet ainsi de bénéficier de la précision de calcul de l’instruction FMA. Nous savons que l’instruction FMA permet d’optimiser le calcul au niveau perfor-mances et aussi au niveau précision par rapport à une multiplication suivie d’une addition, car l’instruction FMA n’effectue l’arrondi qu’à la fin du calcul.

Notre factorisation s’écrit alors sous la forme suivante : Ar = ar+ (br+ −ωi ωr · bi) · ωr Ai = ai+ ( ωi ωr · br+ bi) · ωr (2.24) Br = ar+ (br+ −ωi ωr · bi) · (−ωr) Bi = ai+ ( ωi ωr · br+ bi) · (−ωr) (2.25)

Nous avons ainsi factorisé notre calcul à l’aide de la partie réelle des twiddle

(29)

re-vient au fait que tan(π

2)n’est pas défini. Nous rappelons aussi que tan(θ) = sin(θ) cos(θ) et

que cos(π 2) = 0.

Nous utiliserons cette contribution comme brique de base pour la suite de notre thèse (voir figure 2.6).

FIGURE2.6 – Opérations papillon optimisé

Nous souhaitons aussi évaluer l’impact de cette factorisation sur la précision des calculs. Donc, afin de mesurer la précision des calculs de notre optimisation, plu-sieurs procédures existent. Pour des fins de reproductibilité est aussi pour pouvoir avoir des références communes avec l’état de l’art dans le domaine du calcul FFT, nous avons fait le choix d’adopter la méthode de vérification préconisée par FFTW2[1].

FFTW calcule la précision d’une FFT en comparant la transformation d’un signal pseudo-aléatoire uniforme compris entre −0.5 et +0.5 avec le résultat d’une FFT de référence dite exacte.

Le choix de la FFT de référence influe fortement sur le résultat, surtout que nous voulons comparer la précision de calculs d’algorithmes FFT entre elles. Nous devons alors nous affranchir de ce choix qui est à un certain niveau subjectif. Pour ce faire, nous avons choisi de comparer le résultat de la FFT suivie de la FFT inverse (signal reconstruit) avec le signal d’origine (signal source).

Pour comparer les deux signaux nous utilisons la fonction suivante

compare(F F T inv(F F T (signalSource)), signalSource) qui calcule la norme euclidienne

(L2) relative définie dans l’équation 2.26.

compare(a, b) = ka − bk2/kbk2 (2.26)

Avec a, le résultat de notre FFT/FFT inverse, b le signal pseudo-aléatoire source dont les valeurs sont comprises dans l’intervalle [−0.5, 0.5], et :

kxk2 =

q X

|xi|2 (2.27)

Le graphique suivant (figure 2.7) montre le gain en précision obtenu en utilisant

(30)

la FMA sur une FFT de 1024 points complexes sur le GPU d’Intel IvyBridge HD4000 dont l’architecture sera étudiée finement dans cette thèse (chapitre 3).

Notons aussi que le taux d’erreurs accumulées entre une FFT et une FFT inverse est grandement amélioré par rapport à une implémentation qui n’utilise pas de FMA, surtout en simple précision sur GPU, en effet elle passe de 10−4à 10−7.

FIGURE2.7 – Précision de calcul FFT sur GPU Intel IvyBridge HD4000

2.1.4 Opération bit reverse

Le bit reverse se traduit par une organisation selon les bits du poids fort des don-nées d’entrée initialement ordondon-nées selon le bit du poids faible. Ceci est du à la propriété de décompositions successives de la FFT en deux sous transformées.

Sequential order : 000, 001, 010, 011, 100, 101, 110, 111

0, 1, 2, 3, 4, 5, 6, 7

Bit-reversed order : 000, 100, 010, 110, 001, 101, 011, 111

0, 4, 2, 6, 1, 5, 3, 7

Il faut bien prendre en compte cette particularité car le ré-ordonnancement des données est très coûteux, surtout avec des accès en puissances de deux.

Pour certaines applications où nous avons besoin d’enchainer une FFT suivie par une FFT inverse, nous pouvons éviter l’étape du bit reverse. C’est notamment le cas pour la convolution.

Le bit reverse se fait à l’aide de permutations. On verra en section 3.2 que les archi-tectures CPU modernes proposent dans certains cas des versions (limitées) de telles permutations.

(31)

FIGURE2.8 – Bit reverse de 8 points

La convolution : La convolution correspond à la réponse du filtre à une entrée don-née (notée e(t)). Le filtre est entièrement caractérisé par sa réponse impulsionnelle h(t). Mise en équation, la réponse du filtre est s(t) = h(t) ∗ e(t).

Une particularité de la convolution dans le cas des filtres linéaires, si on entre un signal e(t) = e2πif tle signal de sortie s(t) sera aussi de la forme e2πif t au facteur H(f )

près. Ce facteur n’est autre que la transformée de Fourier de h(t).

C’est pour cette raison que la FFT est très pratique quand on souhaite faire du filtrage sur un signal, nous effectuons le filtrage dans l’espace fréquentiel en faisant une simple multiplication ponctuelle avec le filtre puis on enchaine avec une FFT inverse pour retrouver le signal filtré.

FIGURE2.9 – Convolution FFT et Bit reversing

Pour une convolution l’étape du bit reverse n’est pas importante, on peut juste ignorer cette étape.

2.2

Variantes algorithmiques de la FFT

Au-delà de la version de base, il existe plusieurs méthodes pour regrouper et or-donner les calculs, ainsi que pour distribuer l’opération de bit-reverse. Si toutes ces

(32)

variantes conservent de fait le même graphe de dépendance pour le flot de données, elles consistent à encapsuler les calculs par des approches « divide-and-conquer » distinctes, et surtout à rapprocher les données afin d’augmenter la localité de l’appli-cation du bloc papillon, et de mieux répartir les opérations conduisant au bit reverse. Elles ont donc la même complexité générale de O(n · logn) opérations, mais elles peuvent varier en efficacité pratique avec une mesure plus fine de cette complexité.

Les futures implantations parallèles considérées au chapitre 4, et leur ajustement à une architecture parallèle donnée comme décrite au chapitre 3, devront jouer sur ces variations afin de répartir les calculs en modules de base de taille appropriée. Nous décrivons maintenant les aspects majeurs des variantes algorithmiques dans l’absolu.

Pour plus de détails, le très bon livre de Van Loan « Computational Frameworks

for the Fast Fourier Transform »[11] constitue un ouvrage de référence unificateur des

différents algorithmes.

2.2.1 Cooley-Tukey

Cet algorithme est décrit dans la section 2.1.2 [4][12], il est l’implémentation po-pulaire qui porte le nom radix-2 DIT (decimation in time) à entrelacement temporel. Pour une FFT de N points en radix-2 DIT, les données d’entrée sont ordonnées en bit-reversed order et les sorties sont ordonnées en ordre naturel. Sachant qu’une transformée de Fourier directe permet le passage de l’espace temporel à l’espace fré-quentiel, alors si l’étape de bit reverse est effectuée au début, on parle d’entrelace-ment temporel et si elle est faite à la fin, on parle d’entrelaced’entrelace-ment fréquentiel.

FIGURE2.10 – Signal flow graph FFT décimation dans le temps (DIT de taille 8)

L’algorithme FFT radix-2 DIT (figure 2.10) est une succession de log2(N ) étages,

tous composés de N/2 papillons.

2.2.2 Radix-2 DIF

L’algorithme Radix-2 DIF (decimation in frequency) diffère de son prédécesseur par l’ordre des données d’entrées, ces dernières sont fournies dans l’ordre séquentiel et les sorties sont dans l’ordre bit-reversed order.

(33)

FIGURE2.11 – Signal flow graph FFT décimation en fréquence (DIF de taille 8)

La complexité de calcul demeure inchangée.

2.2.3 Mixed radix

Une FFT peut être partitionnée en plusieurs sous transformées. Si toutes les par-titions ont la même taille r, alors cette version de l’algorithme FFT est dite de type

radix-r .

Dans le cas où les partitions ont des tailles différentes, on parle de mixed-radix FFT[13].

FIGURE2.12 – Exemple de FFT 8 points avec l’algorithme mixed-radix : la première passe est

calculée avec deux radix-4 et la dernière passe avec 4 radix-2

L’approche mixed-radix permet plus de dégrés de liberté dans l’implémentation et l’organisation des calculs. Dans cette thèse, une particulière importance est don-née à cette méthode.

(34)

2.2.4 Split-Radix FFT

L’algorithme FFT split-radix trouve son origine dans une observation très simple illustrée sur la figure 2.13 :

Le graphe d’un algorithme radix-2 à entrelacement temporel peut se transformer de manière évidente en graphe d’un algorithme radix-4 uniquement en changeant les exposants de la racine de l’unité servant de coefficients multiplicateurs (twiddle

fac-tors). Ce faisant, il apparait assez vite que, à chaque étage de l’algorithme, un radix-4

est plus intéressant pour les termes impairs, et un radix-2 pour les termes pairs de la FFT.

L’algorithme split-radix est donc basé sur la décomposition suivante :

Xk= N −1

X

k=0

xnWNnk, (2.28)

Il divise récursivement le calcul de la FFT en une FFT de taille N/2 et deux FFT de taille N/4. X(k) = N 2−1 X n=0 x(2n).e−(i.2π(2n)kN )+ N 4−1 X n=0 x(4n + 1).e−(i.2π(4n+1)kN )+ N 4−1 X n=0 x(4n + 3).e−(i.2π(4n+3)kN ) (2.29) Après identification des trois sous-transformées, il ressort l’écriture suivante :

X(k) = DF TN 2[x(2n)] + w k N.DF TN 4[x(4n + 1)] + w 3k N.DF TN 4[x(4n + 3)] (2.30) La combinaison des algorithmes radix-2 et radix-4 donne à son papillon, sa forme caractéristique en L.

Créé en 1984 par P. Duhamel et H. Hollmann [14], il représente l’algorithme possé-dant le plus faible nombre d’opérations flottantes, multiplications et additions confon-dues, sur des signaux de taille égale à une puissance de deux : pour un signal de taille n, le nombre d’opérations est 4n log2n − 6n + 8Flop (avec n = 2m).

Plus récemment, en 2007, ce nombre d’opérations arithmétiques nécessaire au calcul de l’algorithme a encore été amélioré par S.G. Johnson et M. Frigo [15]. Cet algorithme a aussi été amélioré par Bernstein [16], il a donné aussi le nom Tangente FFT à cet algorithme pour mettre en avant le rôle important que jouent les tangentes comme constantes dans cet algorithme.

2.2.5 Stockham

L’Algorithme de Stockham a pour but initial de supprimer l’étape de bit reverse en la répartissant progressivement par entrelacement avec les calculs.

Il a été référencé dans l’article de Cochrane et Cooley [12] en 1967 oú les auteurs attribuaient cet algorithme à T.G Stockham.

C’est un algorithme dit auto-sort qui permet de calculer la FFT à partir d’une sé-quence d’échantillons reçus dans l’ordre naturel, pour restituer le résultat dans le

(35)

FIGURE2.13 – Signal-flow graph split-radix FFT de taille 8

même ordre (voir figure 2.14).

L’étape de bit reverse est ainsi entrelacée avec les calculs.

FIGURE2.14 – Signal flow graph FFT selon l’algorithme de Stockham

La complexité de calcul d’un algorithme de Stockham reste strictement identique à celle d’un algorithme de type radix standard car le cœur de calcul de l’algorithme s’appuie sur le radix-2 ou 4. C’est juste l’organisation entre calculs et communica-tions / transferts de données qui est modifiée, ce qui peut être potentiellement très intéressant pour la parallélisation de ces opérations.

(36)

L’algorithme de Stockham ne peut pas se faire en place (in-place), l’utilisation d’un tableau de données supplémentaire est nécessaire. Ce tableau « tampon » per-met de changer la localité des résultats après chaque étage de calcul de la FFT. Le tableau initial et le tableau « tampon » alternent leur rôle après chaque étape. Ceci a pour conséquence de ne pouvoir garantir de retourner les résultats de la FFT sur le tableau initial pour toutes les tailles d’échantillons. Lorsque log2(N )n’est pas pair, il

est nécessaire d’avoir recours à une copie de tableaux pour restituer les résultats de la FFT.

2.2.6 Autres versions

Il existe d’autres méthodes publiées dans la littérature, que nous ne considérerons pas dans notre travail, et mentionnées ici par soucis de complétude.

L’algorithme Prime factor FFT a été introduit par Good et Thomas en 1958 et 1963 [17] [18], il ré-exprime la DFT de taille N = N1N2 en une DFT en deux dimensions

N1 × N2, pour ce faire N1 et N2 doivent être premiers entre eux. L’utilisation de cet

algorithme n’est pas compatible avec une taille N qui est une puissance de deux.

L’algorithme FFT de Winograd [19] est considéré comme une dérivation du PFA(Prime

Factor Algorithm). C’est un algorithme efficace connu pour sa faible complexité en

multiplications [20].

2.2.7 Analyse et comparaison entre les versions

La comparaison entre les différentes versions de FFT a donné lieu à de nombreux travaux, tant théoriques qu’expérimentaux. Le site FFTW (http://www.fftw.org) re-cense actuellement la plupart de ces contributions.

Néanmoins ces travaux sont en général sensibles à la nature de l’architecture vi-sée, ce qui justifie les travaux de cette thèse.

On considère en général en informatique la performance d’un processeur par le GigaFlops, défini comme le nombre d’opérations flottantes effectuées en une nano-seconde.

Dans la communauté de l’analyse de la FFT [1] on étend en général cette dé-finition, et on parle de GFlops FFT en multipliant cette valeur par 5N Log2(N ), ce

qui revient à normer les chiffres sur un algorithme abstrait (proche de la version de base Cooley-Tukey) qui comporterait exactement ce nombre 5N Log2(N )

d’opé-rations. Nous adopterons cette mesure dans nos résultats du chapitre 4.

2.3

Applications basées sur la FFT : exemple de détection Radar

La plupart des algorithmes de traitement du signal reposent sur une analyse spec-trale du signal, et dans la majorité des cas leur implémentation utilise la transformée de Fourier rapide (FFT). Ainsi, optimiser la FFT, c’est aussi optimiser toute l’applica-tion (figure 2.15).

Une application populaire qui utilise massivement la FFT est le Radar à synthèse d’ouverture plus connu sous son acronyme anglais SAR (Synthetic aperture Radar),

(37)

FIGURE2.15 – Algorithmes traitement Radar qui utilisent la FFT comme bloc de base

ce type de radar est un radar imageur qui a pour but la télédétection principalement aérienne (dans le cadre de cette thèse).

Généralement les traitements SAR temps réel sont faits en utilisant des DSP

(Di-gital Signal Processor) et/ou des FPGA (Field Programmable Gate Array). Du fait de la

difficulté de programmation et du déverminage des DSP et FPGA, d’autres solutions ont émergé, à savoir celles basées sur les CPU ou les GPU [21].

Kontron privilégie dans le cadre de cette thèse la modularité et la portabilité de la solution SAR. La puissance de calcul fournie par les derniers processeurs d’Intel, à la fois au niveau CPU et GPU (intégré à la puce), rend cette solution applicable aux cas d’applications considérées par Kontron.

Plusieurs algorithmes de traitement SAR existent dans la littérature : Extended

Exact Transform Function (EETF), Chirp Scaling, Frequency Scaling, Omega-K, SPE-CAN et Range-Doppler Algorithm (RDA). Ce dernier est l’implémentation la plus

uti-lisée.

Les principales étapes du traitement SAR via l’algorithme Range-Doppler (RDA) consistent en une succession de FFT sauf pour l’étape du RCMC (Range cell migration

correction) qui nécessite d’appliquer une interpolation sur le signal afin de corriger la

forme hyperbolique de celui-ci, cette étape peut aussi être faite à l’aide de FFT avec la méthode introduite récemment par [22]. Cet algorithme est celui retenu pour notre application radar.

Le traitement SAR (RDA figure 2.16) nécessite aussi une étape communément ap-pelée corner turn. Cette opération consiste à tourner les données bi-dimensionnelles (Range et azimut ) à 90. Mathématiquement parlant, cette opération correspond à la

(38)

FIGURE2.16 – Schéma bloc de l’algorithme Range-Roppler (RDA) pour le traitement SAR A =      a b c d e f g h i j k l      ⇒ AT =          a e i b f j c g k d h l          (2.31)

Les données traitées par notre application sont sous forme de matrices de nombres complexes simple précision de taille 1024 × 1024. L’algorithme RDA est appliqué sur un flux continu de matrices de données 1024 × 1024. Nous appliquons le même trai-tement sur des données différentes à chaque itération de l’algorithme. Nous détaille-rons cet algorithme dans le chapitre 5 de cette thèse.

Le traitement SAR nécessite une infrastructure de calcul intensif, les GPU offrent un très bon compromis par rapport aux autres alternatives. Dans notre domaine, à savoir celui de l’informatique embarquée, les critères taille, poids et énergie regrou-pés communément dans l’acronyme anglais SWaP pour (Size Weight and Power) sont des critères très importants. Un exemple simple est celui du radar SAR embarqué dans un drone : le poids influe sur l’altitude du drone, il influe aussi sur l’autonomie, donc dans un encombrement minimum il faut embarquer une puissance de calcul suffisante pour que le drone puisse voler assez vite et longtemps pour exécuter sa mission en général critique.

Trouver un algorithme optimal de la FFT pour une architecture cible n’est pas une chose triviale. L’ordonnancement des calculs et des mouvements de données afin de réduire le surcoût engendré par les mouvements de données (register spill) est un problème NP-complet[23]. Avec les architectures multi-cœurs et les niveaux supplé-mentaires de la hiérarchie mémoire, le problème est rendu encore plus complexe.

(39)

Bilan et discussion

Toutes les versions connues du calcul de la FFT s’organisent autour du bloc de base d’un papillon à deux entrées et deux sorties, dont le calcul doit s’effectuer de manière quasi-atomique avec des instructions dédiées (FMA). Nous avons proposé une amélioration incrémentale du calcul de ce bloc, qui augmente sensiblement en pratique la qualité des calculs flottants simple précision.

Pour récapituler, le calcul de la FFT procède en étages. Les (n − 1) premiers étages de l’algorithme calculent sur deux moitiés distinctes des valeurs une FFT de taille (n − 1), puis le dernier étage mélange ces résultats à nouveau par moitié, mélangeant dans un certain ordre la moitié des valeurs de la première « demi-finale » avec celles de l’autre.

Bien que l’on puisse envisager de nombreux ordres pour sélectionner les moitiés, on procède en général suivant l’ordre « naturel » qui combine d’abord les valeurs voi-sines sélectionnées deux par deux, puis élargit les distances en les doublant à chaque fois (voir figure 2.10), ou parfois suivant l’ordre inverse (combinant d’abord les va-leurs les plus distantes, puis les rapprochant (voir figure 2.11).

On peut obtenir un code uniforme pour chaque étage en pratiquant effectivement les permutations qui « réalignent » les données dans une position semblable à chaque fois. On peut aussi in-liner le code de tous les étages à la suite, pour y pratiquer di-rectement les changements d’indice (avec un code distinct alors pour chaque étage). La première solution ajoute le coût des permutations, mais la seconde fait gonfler la taille du code qui peut ne plus tenir en mémoire cache. Nous représenterons gé-néralement ces permutations par une représentation graphique, alliant le graphe de dépendance (déplacement) des données entre deux étages, avec une signification donnée à l’ordre (vertical) des index des valeurs en mémoire.

En fait, nous allons être amenés dans nos travaux à considérer une approche mé-langeant permutations explicites et in-lining du fait que nous allons trouver des li-mites au nombre d’opérations que l’on peut effectuer en n’utilisant que la mémoire très locale (registres) des processeurs SIMD sur CPU, ou des Execution Units sur GPU. Ces considérations de taille seront détaillées dans le chapitre suivant (pour le CPU et le GPU de notre architecture Intel Core), et la nature de nos solutions et ajustements des algorithmes (entre mouvements physiques de données et in-lining de code agré-geant des étages) feront l’objet principalement du chapitre 4.

On peut évidemment rappeler que le calcul de n étages de FFT (ou, de manière équivalente, d’une FFT de taille 2n) nécessite n valeurs complexes, dont 2 · n nombres

flottants dans notre approche. C’est la taille qu’il nous faut chercher à ajuster à l’es-pace des registres.

(40)

Les architectures de calcul intensif

Motivations

Nous décrivons dans ce chapitre les tendances du parallélisme architectural exis-tant au niveau élémentaire d’une puce matérielle unique (possiblement multicœur, voire multiprocesseur), différent du niveau macroscopique des grilles de machines et autres data centers.

Nous débutons par des généralités et rappels, puis nous nous concentrons sur le type de combinaison CPU-GPU que l’on trouve dans les architectures Intel Core (Ivy

Bridge et Haswell notamment) qui formaient la cible de nos travaux au sein de Kon-tron. Le problème central consiste à bien comprendre et caractériser les tailles et les

débits des différents composants de mémorisation et de transfert de données, ainsi que leur articulation, pour exploiter ces informations dans le placement optimisé des fonctions du calcul de FFT. Nous décrivons également certains aspects du lan-gage OpenCL utilisé pour la représentation de nos algorithmes, et des mécanismes particuliers de compilation de ce langage sur ces architectures.

Dans le chapitre suivant nous étudierons le placement optimisé de la FFT sur cette architecture Intel Core. Il sera important de tester l’efficacité en performance, mais également en consommation et surtout en température (le circuit peut se mettre en mode dégradé, voire hors tension, s’il devient trop chaud). Nous abordons ces as-pects en caractérisant le circuit de manière expérimentale, à l’aide des équipements disponibles au sein de la société Kontron.

3.1

Parallélisme "on-chip" (généralités)

3.1.1 Parallélisme d’instructions

Historiquement, dans les CPUs, chaque instruction est exécutée lorsque l’instruc-tion précédente est terminée. Rapidement, les concepteurs ont vu qu’il était possible d’optimiser le flux d’instructions en divisant en plusieurs étages le traitement d’une instruction, ce qui améliore considérablement les performances du processeur.

Ces étages sont, par exemple dans le cas d’une machine RISC, lecture de l’ration en mémoire, décodage de l’opél’ration en micro-opél’rations, lecture des opé-randes, exécution et écriture du résultat.

Cette technique, nommée pipeline, permet de produire le résultat d’une

(41)

tion sur la durée de traitement d’un étage, celui de l’exécution, et non plus sur la du-rée de traitement de l’instruction. Ainsi, en régime constant, la vitesse d’exécution est considérablement augmentée. De plus, le compteur de programme peut commencer à traiter l’instruction à exécuter avant même que ses opérandes soient disponibles. C’est ici qu’apparaît la première forme de parallélisme qui exploite donc le parallé-lisme entre les différents étages.

Le pipelining est une des premières optimisations qui a permis d’exploiter le pa-rallélisme d’instructions, d’autres techniques sont venues ensuite pour encore amé-liorer ce type de parallélisme à savoir :

— l’apparition des processeurs dits superscalaires qui sont capables d’exécuter plusieurs instructions simultanément parmi une suite d’instructions, ces der-niers comportent plusieurs unités de calcul, et sont capable de détecter l’ab-sence de dépendances entre instructions.

— l’exécution dans le désordre qui permet au processeur d’exécuter les instruc-tions non pas dans l’ordre des instrucinstruc-tions du programme mais de manière à optimiser l’utilisation des ressources matérielles, sans toutefois violer la dé-pendance des données.

— le renommage de registre vient comme une solution pour le problème de concur-rence sur un même registre qui survient lors de l’exécution dans le désordre. — la prédiction de branchement permet de prédire le résultat d’un branchement

et rend ainsi plus efficace l’utilisation du pipeline, une autre solution est l’exé-cution spéculative qui permet d’exécuter en même temps différents branche-ment et après la fin de l’exécution on garde le résultat du bon branchebranche-ment, au cout d’une duplication de la logique voire du pipeline.

— les accès mémoire et les entrées sorties dans le désordre. — le Prefetch ou pré-lecture des instructions et des données. 3.1.1.1 FMA fused multiply-add

Une autre amélioration architecturale, présentée dans le chapitre précédent 2.1.3, appelé FMA ou fused multiply-add. Elle a été introduite par IBM en 1990 dans leur processeur POWER1.

Cette instruction permet d’exécuter une addition et une multiplication avec un débit équivalent à la fréquence d’horloge.

Elle permet aussi d’avoir une meilleure précision de calcul flottant par rapport à l’utilisation de deux instructions indépendantes, ceci est du au fait que l’arrondi n’est fait qu’une seule fois, c’est-à-dire à la fin de l’opération a = a + b × c.

Ainsi, l’instruction FMA permet de doubler les performances du CPU. La FMA est très répandue dans les processeurs de nouvelle génération et dans tous les GPU. 3.1.1.2 SMT simultaneous multithreading

Cette présentation du parallélisme d’instruction ne sera complète qu’avec la des-cription du simultaneous multithreading (SMT) ou d’après la nomenclature d’Intel l’hyperthreading [24].

Il s’agit d’une forme de multithreading qui permet le partage d’un cœur de pro-cesseur superscalaire entre plusieurs threads.

(42)

Les processeurs non SMT (figure 3.1), dotés de 4 unités d’exécution différentes, passent alternativement d’un thread à l’autre pour l’exécution des instructions. En revanche, les processeurs SMT (figure 3.2) peuvent allouer des unités d’exécution à des threads différents simultanément (schématisés ici en vert pour le thread 1 et en bleu pour le thread 2).

FIGURE3.1 – Flux d’instruction classique FIGURE3.2 – Avec hyperthreading

Les registres utilisateur sont alors dupliqués et partagent les mêmes unités de cal-cul. Tout blocage d’un thread provoque un changement de contexte instantané (par exemple pendant un accès mémoire).

Le but du SMT est d’améliorer l’utilisation des ressources et ainsi exploiter au maximum le parallélisme d’instruction du processeur.

Le multithreading fournit en général pour un processeur, avec deux threads sur un cœur physique, 1.3 fois les performances d’un seul thread. Une autre technologie baptisée "fused core"1proposée par Freescale permet d’atteindre une performance

entre 1.7 et 1.9. Ce gain de performance est dû à l’utilisation d’unités dédiées aux

threads logiques.

Malgré les qualités de l’hyperthreading sur les applications grand public, nous déconseillons son utilisation pour les applications temps réel. Lors de nos essais, nous avons expérimenté sur l’architecture Haswell d’Intel à quatre cœur les perfor-mances d’une FFT 1D de 1024 points complexes avec l’hyperthreading inactif puis avec l’hyperthreading actif. Nous avons ainsi constaté une nette dégradation des per-formances comme le montre la figure 3.3.

La cause principale de cette dégradation est la pollution du cache L1 des cœurs par les threads concurrents sur les mêmes ressources. Il faut souligner aussi que dans notre cas l’essentiel des calculs tiennent dans le cache L1 qui est de taille 64KB.

Nous notons aussi que pour du code optimisé exploitant efficacement les unités d’exécution, par des dimensionnements convenables, l’hyperthreading n’apporte en général pas de gain de performances, il améliore surtout les situations où les calculs sont « creux » (par analogie avec les matrices creuses en mémoire).

Nous avons décidé que pour nos applications temps réel, pour des soucis de per-formances et de prédictibilité l’hyperthreading doit être désactivé. On verra au cha-pitre 4 que les différents cœurs d’un même processeurs seront par ailleurs plus tard

(43)

FIGURE 3.3 – Impact de l’hyperthreading sur la FFT : HT OFF les 4 cœur du CPU Haswell calculent un tableau de FFT de 1024 points complexes, HT ON les 8 cœur calculent le même tableau de FFT

disponibles alors pour exécuter chacune des FFTs distinctes de notre tableau de FFT de l’application Radar.

3.1.2 Le multicœur

Les processeurs actuels sont devenus des systèmes complexes capables d’effec-tuer plusieurs calculs simultanément, d’opérer sur plusieurs données à la fois, de prédire les différents branchements du programme, de changer sa fréquence dyna-miquement ou encore de décider de l’ordre d’exécution des instructions. Toutes ces innovations ont été créées dans un seul et unique but, celui d’augmenter considé-rablement les performances des processeurs, but difficile à atteindre par l’augmen-tation seule de la fréquence. En d’autres mots, la fréquence représente la rapidité du processeur tandis que ces diverses innovations caractérisent l’efficacité de l’architec-ture.

Le traitement multicœur contribue à augmenter les performances et la producti-vité dans des ordinateurs de plus petite taille capables d’exécuter simultanément plu-sieurs applications complexes et de réaliser davantage de tâches en moins de temps. Dans sa forme la plus petite, les processeurs multicœur sont constitués de deux cœurs identiques et d’une mémoire partagée pour les communications intra-cœurs. Les architectures multicœur (voir figure 3.4) sont généralement dotées de cœurs homogènes, chaque cœur peut avoir un ou plusieurs threads SMT comme présenté en 3.1.1.2.

On peut alors espérer une augmentation des performances générale de l’appli-cation sur un processeur monocœur plus rapide (en fréquence) sans rien changer à l’application. Cependant, si nous gardons la même fréquence d’horloge du proces-seur mais que nous doublons le nombre de cœurs, le gain de performance n’est pas direct.

Références

Documents relatifs

Comparez le signal à celui obtenu dans la partie précédente (il faudra sans doute légérement modifier le signal précédent pour comparer les signaux).. À partir du signal

[r]

On pensait que les transformations avec des nombres réels pouvaient être plus efficacement calculées via une transformation discrète de Hartley mais il a été prouvé par la

In this paper we present the comparison between numerical and analytical solutions in case of a linear force and usage of multi-core CPU and GPU for solv- ing Kramers-Klein

Stochastic arithmetic can estimate which digits are affected by round-off errors and possibly explain reproducibility failures. Related

∂b 2 u = 0 where u is the acoustic pressure, c is the wave velocity and t is the time is solved using a finite difference scheme with time order 2 and space order 8.. Differences in

Stochastic arithmetic can estimate which digits in the results are different from one execution to another because of round-off errors.. Estimation de la reproductibilité numérique

If the product is delivered by mail or common carrier, you agree to insure the product or assume the risk of loss or damage in transit, to prepay shipping charges