
Il n'y a pas si longtemps, nous avons parlé du nouveau service Selectel - le
cloud computing haute performance sur les accélérateurs FPGA . Dans un nouvel article sur ce sujet, nous considérons un exemple de programmation FPGA pour construire un ensemble de Mandelbrot, un algorithme mathématique bien connu pour visualiser des images fractales. L'article utilisait du matériel du site
Euler Project .
Au lieu de l'avant-propos
Tout d'abord, quelques termes. Un système informatique avec un accélérateur FPGA - en règle générale, il s'agit d'un adaptateur PCIe avec une puce FPGA faisant partie du serveur x64. L'accélérateur prend en charge une tâche distincte gourmande en ressources dans laquelle le calcul parallèle peut être impliqué et l'exécute de plusieurs ordres de grandeur plus rapidement que le processeur x64, le déchargeant et augmentant les performances de l'ensemble du système informatique. Par exemple, un cycle de calcul avec 100 000 répétitions peut être effectué sur un FPGA en un seul passage, au lieu de s'exécuter séquentiellement 100 000 fois sur un processeur x64 classique. Les éléments logiques, les ressources matérielles, les liens de communication, les puces FPGA sont programmés par l'utilisateur directement pour la tâche elle-même, ce qui vous permet de mettre en œuvre la tâche comme une implémentation d'un algorithme en silicium - Algorithme en silicium et ainsi atteindre de hautes performances, et avec une consommation d'énergie très modeste.
Aujourd'hui, le seuil d'entrée dans la technologie FPGA est assez accessible même aux startups - un serveur avec un accélérateur FPGA et tous les logiciels nécessaires (SDK) peuvent être loués dans le cloud Selectel pour un prix raisonnable (le soi-disant «cloud FPGA»), et la prise en charge de la norme Open CL dans FPGA conduit à qu'un programmeur qui sait travailler avec C est capable de préparer et d'exécuter un programme sur FPGA.
Pour l'avenir: essayez FPGA au travail
L'exemple de programmation décrit ci-dessous pour la construction d'un ensemble Mandelbrot a déjà été implémenté sur un serveur de test
dans le Selectel Lab , où n'importe qui peut évaluer ses performances (une inscription sera nécessaire).
Le projet est fourni en code et préparé pour la compilation. Selectel offre un accès à distance à un serveur avec accélérateur Intel Arria 10 FPGA. Côté serveur, les outils SDK et BSP pour développer, déboguer et compiler OpenCL, du code Visual Studio pour préparer les applications hôtes (applications de contrôle pour le processeur central du serveur) sont déployés.
Notez que l'exemple lui-même n'a aucune valeur appliquée; il a été choisi pour des raisons de démonstration des méthodes d'accélération en utilisant les principes du parallélisme. Avec cet exemple, le lecteur se familiarise avec la voie de conception d'une application dans un système informatique hétérogène avec FPGA - plus tard, cette voie peut être utilisée pour développer vos propres applications avec le calcul parallèle.
MISE À JOUR : Au printemps 2018, Intel a présenté le processeur hybride hautes performances Xeon Gold 6138P avec une puce FPGA Arria 10 intégrée. D'ici fin 2018, des processeurs en série de ce type devraient être mis à la disposition des clients via des partenaires Intel. Chez Selectel, nous attendons cette puce avec impatience et espérons être le premier en Russie à offrir à nos clients la possibilité de tester ce nouveau produit unique.
Ă€ propos de la norme OpenCL pour la programmation FPGA
La norme OpenCL a été développée par Khronos Group, les principaux fabricants mondiaux de puces et de logiciels comprenant Intel, AMD, Apple, ARM, Nvidia, Sony Computer Entertainment, etc. Il est conçu pour écrire des applications qui utilisent l'informatique parallèle sur différents types de processeurs, y compris FPGA. La norme OpenCL comprend le langage de programmation C basé sur la version du langage C99 (la dernière version de C99 est ISO / IEC 9899: 1999 / Cor 3: 2007 du 2007-11-15) et un environnement de programmation d'application.
La popularité de l'utilisation d'OpenCL pour l'informatique hautes performances repose sur le fait qu'il s'agit d'un standard ouvert et que son utilisation ne nécessite pas de licence. De plus, OpenCL ne limite pas la gamme d'appareils pris en charge à une marque particulière, permettant l'utilisation de matériel de différents fabricants sur la même plate-forme logicielle.
En plus sur OpenCL: Introduction Ă OpenCL sur Habr .
Un peu d'histoire - la voie de conception FPGA qui existait avant la norme OpenCL était extrêmement spécifique et chronophage, tandis qu'en termes de complexité, elle était même supérieure à la conception de puces personnalisées (ASIC, circuit intégré spécifique à l'application, "circuit intégré à usage spécial"). Une compréhension approfondie de la structure matérielle du FPGA était nécessaire, dont la configuration devait être effectuée dans un langage de description matérielle de bas niveau (HDL). La possession de cette voie de conception et de vérification a été et reste un art qui, en raison de l'extrême complexité, est accessible à un cercle restreint de développeurs.
L'avènement de la boîte à outils de support OpenCL d'Intel pour les FPGA a en partie résolu le problème de l'accessibilité de la programmation FPGA pour les développeurs de logiciels. Le programmeur sélectionne indépendamment la partie de son algorithme qui convient au traitement parallèle et le décrit en C, puis le compilateur Intel OpenCL pour FPGA crée un fichier de configuration binaire pour exécuter ce fragment de l'algorithme sur l'accélérateur.
En utilisant l'environnement Visual Studio familier ou le compilateur gcc standard, une application hôte est préparée (une application du type .exe, exécutée sur le processeur x64 principal), tandis que toutes les bibliothèques de support nécessaires sont incluses dans le SDK. Lorsque l'application hôte est lancée, le micrologiciel FPGA est chargé, les données seront chargées dans le cœur de la puce et le traitement commencera conformément à l'algorithme conçu.
FPGA (FPGA) est une structure matérielle parallèle massive reprogrammable par l'utilisateur avec des millions d'éléments logiques, des milliers de blocs de signaux DSP et des dizaines de mégaoctets de cache pour les calculs embarqués, sans accéder aux modules de mémoire principaux du serveur. Les interfaces d'E / S rapides (10GE, 40GE, 100GE, PCIe Gen 3, etc.) vous permettent d'échanger efficacement des données avec le processeur principal du serveur.
Le standard OpenCL est un environnement pour exécuter des logiciels hétérogènes. L'environnement se compose de deux parties distinctes:
- Logiciel hôte - une application exécutée sur le processeur central principal du serveur, écrite en C / C ++ et utilisant l'ensemble de fonctions OpenCL API. Le serveur hôte organise l'ensemble du processus de calcul, fournit la source et reçoit les données de sortie, et interagit avec tous les systèmes de serveur avec l'accélérateur FPGA.
- Logiciel accélérateur - un programme écrit en langage OpenCL C (langage C avec un certain nombre de restrictions), compilé pour fonctionner sur la puce FPGA.
Un serveur typique pour l'informatique parallèle est un ordinateur x64 (pour exécuter des applications hôtes), qui comprend un accélérateur FPGA matériel, le plus souvent connecté via le bus PCI-Express. À propos, un tel système est présenté dans le Selectel Lab.
La séquence de programmation et de compilation de l'accélérateur FPGA comprend deux étapes. Le code de l'application hôte est compilé par un compilateur standard (Visual C ++, GCC) pour obtenir un fichier exécutable dans le système d'exploitation du serveur (par exemple, * .exe). Le code source de l'accélérateur FPGA (noyau, noyau) est préparé par le compilateur AOC dans le cadre du SDK, avec la réception d'un fichier binaire (* .aocx). Ce fichier est juste pour la programmation de l'accélérateur.

Fig. Architecture d'environnement de compilation de logiciels OpenCL
Considérons un exemple de code pour calculer un grand vecteur de deux manières
(
PS Ne tirez pas sur le pianiste - ci-après, le code du site du projet Euler est utilisé ):
void inc (float *a, float c, int N) { for (int i = 0; i<N; i++) a[i] = a[i] + c; } void main() { ... inc(a,c,N); ... }
_kernel void inc (_global float *a, float c) { int i = get_global_id(0); a[i] = a[i] + c; } void main() { ... clEnqueueNDRangeKernel(...,&N,...) ... }
Le code au début est un exemple de la façon dont une implémentation à un seul thread en C pourrait ressembler à l'utilisation de la méthode de calcul séquentiel des éléments scalaires.
La deuxième version du code est une implémentation possible de l'algorithme sur OpenCL sous la forme d'une fonction calculée sur un accélérateur FPGA. Il n'y a pas de boucle et le calcul s'effectue en une seule itération de la boucle. Le calcul d'un tableau vectoriel se produit comme l'exécution de N copies de cette fonction. Chaque copie a son propre index, substitué dans l'itérateur dans une boucle, et le nombre de tentatives est défini à partir de l'hôte lorsque le code est exécuté. L'action de l'itérateur est fournie par la fonction get_global_id (), qui fonctionne avec un index compris entre 0 ≤ index <N.
Aller droit au but: construire une fractale
L'ensemble de Mandelbrot est un tableau de points «c» sur le plan complexe pour lequel la relation de récurrence Zn + 1 = Zn² + c pour Z0 = 0 définit une séquence bornée.
Nous définissons Zn = Zn + IYn, et aussi c = p + iq.
Pour chaque point, la séquence suivante est calculée:
Xn + 1 = Xn² + Yn² + p
Yn + 1 = 2XnYn + q
Le calcul de l'appartenance d'un point à l'ensemble à chaque itération est effectué comme l'équation
Xn² + Yn² <4.
Pour afficher l'ensemble Mandelbrot à l'écran, nous définissons une règle:
- Si l'inégalité se maintient à n'importe quelle itération, alors le point entre dans l'ensemble et sera affiché en noir.
- Si l'inégalité ne tient pas, en commençant par une certaine valeur d'itération n = N, alors la couleur est déterminée par le nombre d'itérations N.
Le processus de calcul sur l'hĂ´te sera le suivant:
- Le calcul du nombre d'itérations pour chaque point à l'intérieur de la fenêtre de pixel est affecté à la fonction mandel_pixel ().
- L'énumération séquentielle des points d'image sera fournie par la fonction softwareCalculateFrame (). Les paramètres spécifient l'intervalle réel des points calculés, le pas réel de l'algorithme et un pointeur sur le tampon de couleur de la taille de l'image (theWidth * theHeight).
- La couleur du point est ajustée par le SoftColorTable.
Passons au code:
inline unsigned int mandel_pixel( double x0, double y0, unsigned int maxIterations ) { // variables for the calculation double x = 0.0; double y = 0.0; double xSqr = 0.0; double ySqr = 0.0; unsigned int iterations = 0; // perform up to the maximum number of iterations to solve // the current point in the image while ( xSqr + ySqr < 4.0 &&iterations < maxIterations ) { // perform the current iteration xSqr = x*x; ySqr = y*y; y = 2*x*y + y0; x = xSqr - ySqr + x0; // increment iteration count iterations++; } // return the iteration count return iterations; }
int softwareCalculateFrame( double aStartX, double aStartY, double aScale, unsigned int* aFrameBuffer ) { // temporary pointer and index variables unsigned int * fb_ptr = aFrameBuffer; unsigned int j, k, pixel; // window position variables double x = aStartX; double y = aStartY; double cur_x, cur_y; double cur_step_size = aScale; // for each pixel in the y dimension window for ( j = 0, cur_y = y; j < theHeight; j++, cur_y -= cur_step_size ) { // for each pixel in the x dimension of the window for ( cur_x = x, k = 0; k< theWidth; k++, cur_x += cur_step_size ) { // set the value of the pixel in the window pixel = mandel_pixel(cur_x, cur_y, theSoftColorTableSize); if ( pixel == theSoftColorTableSize ) *fb_ptr++ = 0x0; else *fb_ptr++ = theSoftColorTable[pixel]; } } return 0; }
Chaque pixel est calculé indépendamment de l'autre, et donc ce processus peut être parallélisé. Lors de la mise en œuvre de l'algorithme pour l'accélérateur FPGA, une instruction SIMD est créée pour calculer le nombre de chaque pixel d'itération (déterminer le code couleur à partir de la palette). L'implémentation de deux boucles imbriquées sur le tampon d'image est encadrée via OpenCL en exécutant l'opération (theWidth * theHeight).
Les instances du noyau dans la liste ci-dessous sont appelées l'élément de travail, et l'ensemble de toutes les instances est appelé l'espace d'index. Les caractéristiques de la fonction matérielle sont les suivantes:
- Une déclaration de fonction commence par le mot clé __kernel.
- Type de fonction matérielle - le type de la valeur de retour est toujours nul.
- Le retour des valeurs se fait via des tampons passés en paramètres.
- Les trois premiers paramètres définissent la grille matérielle dont les nœuds correspondent aux pixels de l'image de sortie.
- Le quatrième paramètre limite le nombre d'itérations, empêchant le bouclage pour les points appartenant à l'ensemble Mandelbrot.
- Le cinquième paramètre est un pointeur sur le tampon de couleur de sortie.
- Le mot-clé __global désigne le type de mémoire à travers lequel le tampon sera transmis: il s'agit de la mémoire DDR (QDR) générale sur l'accélérateur lui-même.
- Le mot clé restrict permet à l'optimiseur d'interdire l'utilisation de références de tampon indirectes.
- Dans le 6ème paramètre, un pointeur vers la palette est passé.
- Le mot clé __constant optimise les accès au tampon en générant un cache avec un attribut en lecture seule.
La description de la fonction dans la liste est proche de l'implémentation du processeur x64. Ici, la définition de l'instance actuelle du noyau se fait via la fonction get_global_id, dans laquelle le numéro de dimension (0, 1) est passé en paramètre.
Pour une meilleure optimisation, une indication explicite du début du cycle a été introduite. En l'absence d'informations sur le nombre d'itérations au moment de la compilation, le nombre d'étapes de boucle est explicitement indiqué, car leurs propres blocs matériels seront créés pour eux. Avec ce type de codage, il faut «regarder en arrière» la capacité d'une puce spécifique installée sur l'accélérateur, en raison de la consommation de ressources FPGA pour un plus grand nombre de cycles.
//////////////////////////////////////////////////////////////////// // mandelbrot_kernel.cl : Hardware implementation of the mandelbrot algorithm //////////////////////////////////////////////////////////////////// // Amount of loop unrolling. #ifndef UNROLL #define UNROLL 20 #endif // Define the color black as 0 #define BLACK 0x00000000 __kernel void hw_mandelbrot_frame ( const double x0, const double y0, const double stepSize, const unsigned int maxIterations, __global unsigned int *restrict framebuffer, __constant const unsigned int *restrict colorLUT, const unsigned int windowWidth) { // Work-item position const size_t windowPosX = get_global_id(0); const size_t windowPosY = get_global_id(1); const double stepPosX = x0 + (windowPosX * stepSize); const double stepPosY = y0 - (windowPosY * stepSize); // Variables for the calculation double x = 0.0; double y = 0.0; double xSqr = 0.0; double ySqr = 0.0;</code> <code>unsigned
Le package d'utilitaires Intel FPGA SDK pour OpenCL devra être installé sur l'hôte avant de compiler l'implémentation matérielle de l'algorithme. Parmi les logiciels préinstallés, vous devez inclure le BSP (Board Support Package) du fabricant de la carte accélératrice spécifique. Dans l'exemple, Intel Quartus Prime Pro 16.1 est installé avec la prise en charge d'OpenCL et de BSP de l'accélérateur Euler Thread (Intel Arria 10).
Ci-dessous, vous pouvez configurer les chemins et les variables d'environnement. La variable ALTERAOCLSDKROOT contient le chemin d'accès au SDK FPGA Intel, la variable AOCL_BOARD_PACKAGE_ROOT contient le chemin d'accès à l'accélérateur BSP.
set ALTERAOCLSDKROOT=C:\intelFPGA_pro\16.1\hld set AOCL_BOARD_PACKAGE_ROOT=C:\intelFPGA_pro\16.1\hld\board\euler_thread set path=%path%;C:\intelFPGA_pro\16.1\hld\bin set path=%path%;C:\intelFPGA_pro\16.1\quartus\bin64 set path=%path%;C:\intelFPGA_pro\16.1\hld\board\a10_ref\windows64\bin set path=%path%;C:\intelFPGA_pro\16.1\hld\host\windows64\bin set path=%path%;C:\intelFPGA_pro\16.1\qsys\bin set path=%path%;C:\Program Files (x86)\GnuWin32\bin\
Pour la compilation, le compilateur aoc du SDK est utilisé.
aoc mandelbrot_kernel.cl -o mandelbrot_kernel.aocx --board thread -v -v --report
Nous décryptons: mandelbrot_kernel.cl - le fichier avec le texte source, mandelbrot_kernel.aocx - le fichier objet de sortie pour la programmation FPGA, thread - le nom de l'accélérateur du package BSP. Le commutateur --report affiche un rapport d'utilisation des ressources FPGA. Le commutateur –v affiche des informations de diagnostic pendant la compilation. Le rapport de consommation de ressources pour le noyau est le suivant:
+ ------------------------------------------------- ------------------- +
; Résumé d'utilisation estimée des ressources;
+ ---------------------------------------- + -------- ------------------- +
; Ressource + utilisation;
+ ---------------------------------------- + -------- ------------------- +
; Utilisation logique; 49%
; ALUTs; 26%;
; Registres logiques dédiés; 25%;
; Blocs de mémoire; 21%
; Blocs DSP; 16%;
+ ---------------------------------------- + -------- -------------------;
Pour compiler l'application hôte, l'exemple a utilisé le package Microsoft Visual Studio 2010 Express avec Microsoft SDK 7.1 installé. Dans les paramètres du projet, la configuration pour x64 est sélectionnée. Ensuite, connectez le dossier des fichiers d'en-tête externes et spécifiez le chemin d'accès aux bibliothèques Intel FPGA SDK supplémentaires dans les paramètres de l'éditeur de liens.
Répertoires supplémentaires pour inclure les fichiers = $ (ALTERAOCLSDKROOT) \ host \ include;
Répertoires de bibliothèque supplémentaires = $ (AOCL_BOARD_PACKAGE_ROOT) \ windows64 \ lib;
$(ALTERAOCLSDKROOT)\host\windows64\lib;
Le plan d'action général pour le lancement du noyau sur l'accélérateur sera le suivant:
- Obtenez une liste des plateformes
- Obtenez une liste d'appareils
- créer le contexte;
- charger le noyau dans l'appareil;
- envoyer des tampons d'entrée à l'appareil;
- exécuter le noyau pour exécution;
- lire le tampon de sortie de l'appareil;
- contexte libre.
Considérons quelques points directement liés au lancement du noyau. Ainsi, un cœur est conçu pour traiter un pixel de l'image. Ainsi, vous devez exécuter N instances du noyau, où N est le nombre total de pixels dans l'image.
Ci-dessous, nous notons le cas où il y a plusieurs cartes accélératrices dans le serveur, alors la tâche peut être répartie entre elles. Dans chacun des accélérateurs, vous devez charger le noyau (fichier mandelbrot_kernel.aocx). Supposons que le nombre d'accélérateurs soit numDevices et que les lignes d'image soient divisées entre tous les accélérateurs:
#define MAXDEV 10 static cl_context theContext; static cl_program theProgram; static cl_kernel theKernels[MAXDEV]; //.. // Create the program object theProgram = createProgramFromBinary( theContext, "mandelbrot_kernel.aocx", theDevices, numDevices); // Create the kernels for ( unsigned i = 0; i < numDevices; ++i ) theKernels[i] = clCreateKernel( theProgram, "hw_mandelbrot_frame", &theStatus ); // Create output pixel buffers for every kernel for( unsigned i = 0; i < numDevices; ++i ) thePixelData[i] = clCreateBuffer(theContext, CL_MEM_WRITE_ONLY, thePixelDataWidth*rowsPerDevice[i]*sizeof(unsigned int), NULL, &theStatus); // Preparing and writing palette buffer to every device theHardColorTable = clCreateBuffer(theContext, CL_MEM_READ_ONLY, aColorTableSize*sizeof(unsigned int), NULL, &theStatus); for( unsigned i = 0; i < numDevices; i++ ) theStatus = clEnqueueWriteBuffer(theQueues[i], theHardColorTable, CL_TRUE, 0, aColorTableSize*sizeof(unsigned int), aColorTable, 0, NULL, NULL); // Preparing kernels and run unsigned rowOffset = 0; for ( unsigned i = 0; i < numDevices; rowOffset += rowsPerDevice[i++] ) { // Create ND range size size_t globalSize[2] = { thePixelDataWidth, rowsPerDevice[i] }; // Set the arguments unsigned argi = 0; theStatus = clSetKernelArg (theKernels[i], argi++, sizeof(cl_double), (void*) &aStartX ); const double offsetedStartY = aStartY - rowOffset * aScale; theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_double), (void*)&offsetedStartY); theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_double), (void*)&aScale); theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_uint), (void*)&theHardColorTableSize); theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_mem), (void*)&thePixelData[i]); theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_mem), (void*)&theHardColorTable); theStatus = clSetKernelArg(theKernels[i], argi++, sizeof(cl_uint), (void*)&theWidth); // Launch kernel theStatus = clEnqueueNDRangeKernel(theQueues[i], theKernels[i], 2, NULL, globalSize, NULL, 0, NULL, NULL); } rowOffset = 0; for( unsigned i = 0; i < numDevices; rowOffset += rowsPerDevice[i++] ) { // Read the output theStatus = clEnqueueReadBuffer(theQueues[i], thePixelData[i], CL_TRUE, 0, thePixelDataWidth*rowsPerDevice[i]*sizeof(unsigned int), &aFrameBuffer[rowOffset * theWidth], 0, NULL, NULL); } / / . .
- La fonction createProgramFromBinary crée un objet programme OpenCL à partir d'un fichier objet.
- Ensuite, pour chaque périphérique, un noyau est créé en fonction de l'objet programme.
- Les tampons PixelData sont créés pour recevoir la sortie de chaque cœur.
- Un tampon est créé pour stocker la palette de couleurs et chargé dans chacun des accélérateurs.
- Ensuite, pour chaque périphérique, la liaison des paramètres d'application locale et des paramètres de noyau est définie à l'aide de la fonction clSetKernelArg.
- Les paramètres sont déterminés par des numéros de série dans la déclaration de fonction du noyau, à partir de zéro.
Le prochain point important consiste à déterminer la taille de la tâche en fonction de l'espace d'indexation en fonction du tableau globalSize. Ce tableau peut être unidimensionnel, bidimensionnel ou tridimensionnel. Pour chaque dimension, une dimension est donnée sous forme d'entier. La dimension de l'espace déterminera l'ordre d'index de l'élément de travail dans le noyau.
Dans l'exemple, pour chaque cœur, un espace à deux dimensions est spécifié, où l'un des axes est les éléments de ligne de pixels, le second est l'ensemble des lignes d'image traitées sur cet appareil. Dans le code du noyau, le nombre de pixels dans la ligne est obtenu en appelant get_global_id (0), le numéro de ligne est get_global_id (1). La variable globalSize est transmise à la fonction clEnqueueNDRangeKernel pour démarrer le nombre requis d'instances de noyau à exécuter.
Une fois l'exécution des cœurs terminée, des tampons de pixels sont lus depuis le périphérique vers des tableaux locaux. Évaluons les performances par le nombre d'images par seconde - le résultat est visible sur la démonstration effectuée lors de la conférence SelectelTechDay ( voir le début de l'article ).
Conclusion
La programmation d'accélérateurs FPGA dans un langage de haut niveau a sans aucun doute abaissé le seuil d'accès à cette technologie pour les développeurs d'un ordre de grandeur. Par exemple, pour ceux qui maîtrisent simplement cette boîte à outils, il existe même une implémentation FPGA du fameux exemple «Hello World» .
Mais pas si simple. L'écriture - et surtout - le débogage d'un algorithme clairement fonctionnel d'un vrai problème appliqué nécessite toujours un professionnalisme élevé. Une autre limitation est que chaque puce FPGA ne peut effectuer qu'une seule tâche de calcul dans l'application. Pour une autre tâche, elle doit être reprogrammée à nouveau.
Soit dit en passant, le modèle d'utilisation de la plate-forme vous permet d'avoir plus d'un accélérateur FPGA sur l'hôte, bien qu'il s'agisse d'une solution assez coûteuse.
L'hôte (application hôte) gère le processus de création du contexte (structure de données pour l'accélérateur) et de la file d'attente de commandes. C'est-à -dire Une seule application hôte, dans laquelle il existe différentes sous-tâches pour le calcul parallèle sur FPGA, peut les charger sur différents accélérateurs:
KERNEL1 => ACCÉLÉRATEUR A
KERNEL2 => ACCÉLÉRATEUR B
Néanmoins, les efforts pour maîtriser les accélérateurs FPGA en valent la peine - dans de nombreux domaines d'application, cette technologie devient indispensable: télécommunications, biotechnologie, traitement des mégadonnées, reconnaissance des formes, traitement du signal et de l'image, en mathématiques computationnelles et modélisation du champ physique.
Informations supplémentaires pour l'article:
www.altera.com est la principale ressource Intel FPGA.
www.eulerproject.com est le site officiel du projet Euler.
Altera + OpenCL: nous programmons sous FPGA sans connaissance de VHDL / Verilog - un article sur Habr.