Télécharger le fichier pdf d’un mémoire de fin d’études
Architectures embarquées pour les ADAS
Les fonctions ADAS citées précédemment nécessitent de la puissance de calcul pour pouvoir traiter les données issues des différents capteurs, prendre des décisions et agir en conséquence (pilotage d’actionneur, alarme, etc.), dans le milieu automobile on parle alors d’Electronic Control Units (ECUs). Les conditions et normes automobiles imposent que ces systèmes de traitement soient de faible coût, peu consommateurs et sûrs d’un point de vue fonctionnel (normeISO 26262). Ainsi il existe sur le marché un grand nombre d’architectures utilisées pour embarquer des applications automobiles, on parle également de Systems-on-Chip (SoCs) qui intègrent, sur une même puce, l’ensemble des éléments nécessaires à l’ECU (processeurs, mémoire, périphériques d’interface, etc.).
Architecture type
De manière générale, une architecture de calcul embarquée est composée de différents éléments que l’on peut classer suivant deux catégories : les unités d’exécution et les unités de mémoire.
Unités d’exécution
Une unité d’exécution permet d’exécuter un fil d’instructions (calculs et/ou accès mémoire) également appelé thread. Elle est composée de plusieurs unités élémentaires qui sont activées d’une manière sélective suite au décodage de différents types d’instructions.
On distingue ainsi les unités élémentaires suivantes :
— Unité arithmétique et logique délivrant les opérations d’additions, ou/et logique, etc. (nombre entier et virgule fixe).
— Unité de multiplication se chargeant d’appliquer les multiplications ou les multiplications – accumulations.
— Unité de calcul en virgule flottante permettant d’effectuer des opérations sur les variables à virgule flottante (additions et multiplications).
— Unités de calcul spécifique : unités optionnelles qui encapsulent une implémentation hardware spécifique d’une ou plusieurs instructions (par exemple cos, sin, etc.).
— Unité de branchement gérant les instructions du type condition (comme if ) ou boucle (comme for). Elles sont souvent liées à des unités de prédictions qui peuvent mettre en place une exécution spéculative du fil d’instruction.
— Unité d’adresse permettant le calcul d’adresses, par exemple accès à la ne valeur d’un vecteur par l’opérateur [n].
— Unité Load&Store se chargeant de faire l’interface entre les registres du processeur et la mémoire du système, en utilisant les unités d’adresses.
Unités de mémoire
Les unités de mémoire permettent de stocker de l’information. Généralement, on caractérise la mémoire par sa capacité de stockage (quantité d’information), sa bande passante (vitesse d’échange de l’information) et sa latence (délai pour obtenir une information).
Il existe plusieurs niveaux de mémoires, allant du voisinage le plus proche des unités d’exécution (mémoires très rapides mais de très petite taille) au stockage de masse, beaucoup plus lents (comme les mémoires non-volatiles).
Registre Les registres constituent la mémoire la plus rapide d’un processeur. Les résultats des instructions sont généralement stockés sur des registres avant d’être sauvegardés en mémoire (par le biais d’instruction Load & Store). Le nombre et la taille des registres (souvent 32 ou 64 bits) varient d’un processeur à l’autre.
Mémoire cache La mémoire cache correspond à la mémoire tampon entre le processeur et la RAM. Pour des raisons d’efficacité, elle est structurée en plusieurs niveaux de caches : L1, L2 et parfois L3, qui peuvent être uniques ou partagées entre plusieurs unités d’exécution ou coeurs d’un même processeur. Il s’agit de mémoires ayant de faibles latences d’accès mais de faibles capacités de stockage (en général pas plus de quelques Mo). Le cache agit comme une mémoire temporaire permettant de stocker des données préalablement utilisées, pour diminuer le temps d’un accès ultérieur. Ainsi, lorsque l’unité d’exécution cherche à accéder à une donnée qui se trouve déjà dans le cache, on parle alors de cachehit, l’accès sera très rapide.Dans le cas contraire, on parle de cache-miss, la latence d’accès sera beaucoup plus lente. Remarquons qu’il existe plusieurs politiques et stratégies pour gérer la mémoire cache. Dans le cas de l’écriture, on distingue deux politiques :
— l’écriture immédiate (writhe-through) qui fait en sorte que les données sont écrites à la fois dans le cache et dans la mémoire centrale pour garantir une cohérence entre les différents niveaux de mémoire,
— l’écriture différée (write-back) qui évite des écritures répétées dans la mémoire centrale en se permettant de garder une différence entres les données dans le cache et celles présentes dans la mémoire. Les lignes du cache non cohérentes avec la mémoire centrale sont marquées d’un dirty bit, dont nous expliquons le fonctionnent en figure 1.3.
Remarquons que la majorité des processeurs actuels proposent par défaut une politique write-back, ce qui permet d’avoir des délais en écriture beaucoup plus rapides.
RAMoumémoire vive Il s’agit de la mémoire principale du système, elle permet de stocker de grande quantité de données (quelques Go). Cependant accéder de manière répéter à la RAM est souvent coûteux en termes de temps d’exécution à cause de sa forte latence.
Notons que la majorité des mémoires RAMd’aujourd’hui sont qualifiées de double data rate (DDR). Ainsi, elles sont capables de transférer des données à la fois sur le front montant et le front descendant de l’horloge de la mémoire, soit deux transactions par coup d’horloge.
Mémoire non-volatile Cette mémoire conserve les données en l’absence d’alimentation électrique (utilisée notamment pour le stockage de l’OS), elle a souvent plusieurs centaines de Go de mémoire. On peut citer les disques durs, mémoires flashs (clés USB, cartes SD, etc.). Elle est cependant assez peu utilisée lors de l’exécution d’un programme temps-réel à cause de ses performances catastrophiques (sauf dans le cas d’applications spécifiques comme la gestion de base de données).
Processeurs
Le terme de processeur désigne un système électronique capable d’effectuer des opérations et ne se limite pas uniquement au Central Processing Unit (CPU). Un processeur est composé d’une ou plusieurs unités d’exécution et de certaines unités mémoire comme les mémoires cache. Un processeur peut intégrer plusieurs coeurs (on parle alors de multicoeur), il est alors capable d’exécuter plusieurs threads simultanément et donc dispose de plusieurs unités d’exécution. Remarquons que le nombre de coeurs n’est pas toujours égal au nombre d’unités d’exécution, par exemple les processeurs Intel sont capables d’exécuter simultanément 2 threads par coeur (soit 2 unités d’exécution par coeur) grâce à l’Hyper-Threading.
SoCs
Finalement, un SoC consiste à intégrer l’ensemble (ou une partie) de ces composants sur une même puce. Remarquons que plusieurs processeurs peuvent être intégrés sur une même puce et qu’un SoC peut également intégrer une mémoire non-volatile. Ainsi, nous illustrons en figure 1.4 l’exemple d’un SoC composé de deux processeurs partageant une même mémoire RAM. La figure décrit également le découpage en unités d’exécution (dans l’exemple une unité d’exécution est équivalent à un coeur du processeur) et en unités élémentaires.
Le calcul parallèle
Certaines architectures ont la particularité d’être conçues pour procéder aux différents calculs demanière parallèle. Au vu des différents types de parallélisme, il est possible de définir plusieurs classes auxquelles peuvent se rattacher les différentes architectures de calcul. Ainsi, la taxonomie de FLYNN [1972] définit quatre classes :
— SISD (Single Instruction Single Data) : le calcul s’effectue de manière séquentielle, il n’y a aucune forme de parallélisme. Cela concerne les architectures n’étant pas capables d’effectuer plusieurs calculs de manière simultanée, effectuant les opérations les unes à la suite des autres (au maximum une instruction par cycle d’horloge).
Par exemple un CPU mono coeur, mono scalaire pipeliné appartient à cette classe.
— MISD (Multiple Instruction Single Data) : plusieurs opérations sont appliquées en même temps à une donnée unique. Très peu d’architectures se rattachent à cette classe.
— MIMD (Multiple Instruction Multiple Data) : capable d’effectuer plusieurs opérations sur différentes données de manière simultanée. Cela concerne les systèmes présentant plusieurs unités d’exécution, ces architectures sont donc capable d’effectuer des calculs concurrentiels sur plusieurs données.
— SIMD (Single Instruction Multiple Data) : une opération est appliquée à plusieurs données en même temps. Il s’agit de ce que l’on appelle des opérations ou architectures vectorielles.
Parallélisme au niveau architecture
Du point de vue fonctionnel, il existe plusieurs stratégies pour procéder à du calcul parallèle sur une architecture. Nous présentons ici une définition des différents niveaux de parallélisme, en allant du niveau registre au sein d’une même unité d’exécution, jusqu’au niveau multiprocesseur hétérogène.
Parallélisme de registre Le parallélisme de registre consiste à appliquer une même opération à des zones régulières d’un même registre. Cela consiste souvent à un registre de grande taille (128 ou 256 bits), qui est divisé en un vecteur de plusieurs variables (c’est le cas des technologies NEON, SSE, AVX, etc.). De cette manière il est possible d’appliquer une même opération à plusieurs variables en simultanée .On parle alors d’opérateurs vectoriels, ou SIMD.
Parallélisme fonctionnel Pour exécuter une instruction, plusieurs étapes sont nécessaires.
Les étapes dépendent bien évidemment de l’architecture, cependant de manière générale chaque étape fait appel à une unité différente. Ainsi, il est possible de séquencer un traitement périodique en plusieurs étapes spécifiques qui seront exécutées en parallèle par des unités différentes. C’est ce que l’on appelle le pipeline fonctionnel, un exemple est donné dans la figure 1.5. Avec une répétition suffisamment grande, le temps d’exécution du traitement tend alors vers 1 cycle d’horloge. De plus, sur les architectures actuelles plusieurs unités élémentaires sont présentes (comme présenté dans la partie 1.3.1), chacune permettant d’exécuter un type d’instruction. Ainsi il devient possible d’exécuter plusieurs instructions en même temps si elles utilisent des unités élémentaires différentes, par exemple des opérations faisant intervenir une unité arithmétique et logique en même temps que des opérations faisant intervenir l’unité de calcul en virgule flottante. Une telle approche nécessite des stations de réservations et des buffers de réordonnancent. On qualifie de superscalaire les architectures capables d’utiliser cette technique.
FIGURE 1.5 – Séquençage d’opérations dans un processeur doté d’un pipeline à 5 étages. Les 5 étages sont Fetch, Decode, Execute, Memory et WriteBack. Il faut 9 cycles pour exécuter 5 opérations et 1004 cycles pour exécuter 1000 opérations. Dans cet exemple, à partir de t = 5, tous les étages du pipeline sont sollicités, et les 5 opérations ont lieu en même temps.
Parallélisme multicoeur Certaines architectures présentent plusieurs unités d’exécution parfois appelées coeurs, c’est le cas de la majorité des CPUs modernes qui peuvent avoir 4 voire 8 coeurs. Il est donc possible de profiter des différents coeurs pour effectuer plusieurs calculs simultanément. Certaines APIs permettent d’ailleurs de faciliter le portage d’algorithme sur ce type de cible, c’est notamment le cas de l’API d’OpenMP qui utilise des directives du compilateur pour la parallélisation.
Parallélisme hybride Le parallélisme hybride (ou à hardware mixte) consiste à répartir l’exécution d’un algorithme sur différents processeurs de natures différentes et présents sur un même SoC. Ainsi, sur un calculateur embarqué comportant un CPU multicoeur et un GPU, il est possible d’effectuer une partie des calculs sur un des processeurs, tout en effectuant une autre partie sur l’autre processeur. Chaque processeur ayant ses propres avantages et inconvénients, l’efficacité dépendra fortement de l’adéquation entre le processeur et la partie de l’algorithme à exécuter. Il existe deux modèles pour les calculateurs hybrides :
— Chaque processeur dispose de sa propre mémoire, ils communiquent alors par le biais d’un bus de données avec un mécanisme plus ou moins explicite de transfert de données.
— Les processeurs sont organisés autour d’une même mémoire globale, les données sont donc directement partagées et sont protégées contre les lectures et écritures concurrentes par un mécanisme hardware ou software. Le système de cache local permet d’accélérer les différents accès.
|
Table des matières
1 Contexte et problématiques
1.1 Introduction
1.2 Systèmes d’aide à la conduite
1.3 Architectures embarquées pour les ADAS
1.4 Analyse de l’embarquabilité
1.5 Démarche proposée
1.6 Références
2 Traitement d’images et architectures hétérogènes
2.1 Introduction
2.2 Traitement d’images pour les ADAS
2.3 Architectures hétérogènes pour les ADAS
2.4 Limitations et évolutions
2.5 Références
3 Méthodologie d’analyse d’embarquabilité
3.1 Introduction
3.2 Algorithmes et contraintes temps-réel
3.3 Optimisation du mapping
3.4 Méthodologie globale
3.5 Références
4 Caractérisation d’architectures de calcul
4.1 Introduction
4.2 État de l’art
4.3 Configuration et compilation
4.4 Vecteurs de test low-level
4.5 Vecteurs de test mid-level
4.6 Vecteurs de test high-level
4.7 Vers la prédiction de performances
4.8 Références
5 Prédiction de performances
5.1 Introduction
5.2 Travaux existant sur la prédictions de performances
5.3 Méthodologie de prédiction de performances
5.4 Résultats
5.5 Mapping et pipeline d’exécution
5.6 Références
6 Résultats et applications
6.1 Introduction
6.2 Odométrie visuelle
6.3 Détection de piétons
6.4 Références
7 Conclusion et perspectives
7.1 Synthèse
7.2 Perspectives et applications
7.3 Références
A Odométrie visuelle I
A.1 Calcul des dérivées partielles
A.2 Résultats de l’algorithme
B Liste des acronymes VII
C Glossaire IX
D Liste des symboles XI
E Publications et communications XIII
Télécharger le rapport complet