Upload
ochafik
View
5.632
Download
2
Tags:
Embed Size (px)
Citation preview
4
Mettons les GPUs au travail !
• Concepts de base d’OpenCL
• JavaCL en quelques lignes de code
• Pour les paresseux et les pressés : ScalaCL
5
Speaker
Olivier Chafik (@ochafik)
•Développeur C++ / Java (3D, finance)
•Hobby = interopérabilité
• JNAerator, BridJ : des bindings en 1 minute-chrono
• JavaCL, ScalaCL
8
Pourquoi OpenCL ?
• Puissance gratuite (x10 à x100)
• Standard multi-vendeur, CPU + GPU
• Close-to-metal : parallélisme boucles + SIMDPousse les multi-coeurs à bout !
• Interaction DirectX / OpenGL
10
Orienté événement
• Opérations asynchrones & enchaînables
• Renvoient events, en attendre d’autres
Écriture buffer Exec 1 Exec 2 Lecture buffer
• Files d’exécutions attachées à un device
Exemple de boucle C
Calcul de sinus & cosinus en boucle
void scos( const double* params, double* out, int length) { for (int i = 0; i < length; i++) { double param = params[i]; out[2 * i] = sin(param); out[2 * i + 1] = cos(param); }}
11
Kernel OpenCL équivalent
Calcul de sinus & cosinus parallèle (simplifié)
#pragma OpenCL EXTENSION cl_khr_fp64 : enablekernel void scos( global const double* params, global double2* out, int length) { int i = get_global_id(0); // indice parallèle if (i >= length) return; // dépassements possibles { double param = params[i]; double c, s = sincos(param, &c); // calcul sin & cos rapide out[i] = (double2)(s, c); }}
12
13
Kernels
• Dialecte du C
• Fonctions math vectorielles (SIMD sur float4, int8…)
• Code connait sa position d’exécution
• Lecture / écriture buffers / images
• Synchronisation avec voisins (working group)
14
Code hôte
• Choix devices + création contexte
• Création file d’exécution
• Compilation kernels
• Allocation buffers / images
• Scheduling des exécutions
• Lecture / écriture buffers
JavaCL (BSD)
15
• 1ers bindings OpenCL
• API orientée-objet
• Maven Central (jar unique)
• Communauté active
Plus que des bindings
• Gestion mémoire débrayable
• Cache automatique des binaires
• Inclusion depuis URLs
• Générateur de wrappers typés
• Parallel Reduction (min, max, sum, product)
18
Plus que des bindings (2)
• FFT complexe d'un tableau de primitives :
DoubleFFTPow2 fft = new DoubleFFTPow2();double[] transformed = fft.transform(data);
• Chargement (+ conversion) d'une image :
CLImage2D img = context.createImage2D(Usage.Input, ImageIO.read(file));
• Multiplication de matrices UJMP :
Matrix a = new CLDenseFloatMatrix2D(n, m), Matrix b = new CLDenseFloatMatrix2D(m, q);Matrix c = a.times(b);
19
Les pièges d’OpenCL
• Coût des transferts RAM / GPU
• Contextes mixtes CPU / GPU : seulement sur APU AMD
• Branchements conditionnels lents sur GPU
• Besoin de tests d’arrêt
21
Encore des pièges
• Peu de formats d’image garantis
• Endianness parfois différente entre hôte & device
• Apple ne supporte qu’OpenCL 1.0
22
Chasse à la performance sur GPU
• Groupes d’exécution : memoire locale, barrières…
• Répartition de charge multi-GPU
• Exécutions pyramidales pour réductions associatives
23
JavaCL 1.0.0-RC2
• 32 & 64 bits / Windows, Linux, MacOS X
• NVIDIA, AMD, Intel & Apple
• OpenCL 1.0 / 1.1 (1.2 peu répandu)
24
Rendre OpenCL plus facile ?
• Éviter d’écrire les kernels en C
• Cacher l’asynchronicité
• Accepter performance sub-optimale (> 10x plus rapide que Java)
25
OpenCL “traduit”
• Apapapi (AMD)
• Java
• Cache beaucoup (trop ?) de détails
• ScalaCL (votre serviteur)
26
ScalaCL
• Collections Scala asynchrones
• Stockage + Opérations OpenCL (map, filter, sum…)
• Traduction Scala / OpenCL
27
Qu'est-ce que Scala ?
• Saint-Graal des langages (impératif, fonctionnel, objet…)
• Tuples + Collections mutables / immutables
• Syntaxe familière
• JVM
28
Quelques lignes de Scala…
val intervalle = (0 until 100000)
val cosSinCol = intervalle.map(i => { val f = 0.2 (cos(i * f), sin(i * f))})
val sum = cosSinCol.map({ case (c, s) => c * s }).sum
29
Les mêmes lignes sur GPUimport scalacl._implicit val context = Context.best(DoubleSupport)val intervalle = (0 until 100000).cl
val cosSinCol = intervalle.map(i => { val f = 0.2 (cos(i * f), sin(i * f))})
val sum = cosSinCol.map({ case (c, s) => c * s }).sum
30
Comment ça marche
• Conversion fonctions Scala => code OpenCL
• 3 collections
• CLRange : intervalle
• CLArray : tableau de tuploïdes
• CLFilteredArray : tableau filtré, compactable en parallèle
32
Des collections asynchrones
• Contrainte : les collections Scala ont l’air synchrones
• Principe : single writer, multiple reader
33
Des collections asynchrones
val tab = Array(1, 2, 3, 4).cl
val resultat = tab.map(x => x * 2).map(x – 5)
// resultat pas encore calculé
resultat(i) = 10 // attente avant écriture
34
Traduire Scala en OpenCL ?
• Limitations (pas de classes)
• Élimination des tuples
• Élimination du code “objet”
36
Aller plus vite : flot d’opérations
col.map(f).filter(g).map(h).reduceLeft(i)
•Collections intermédiaires + lambdas
•f, g, h sans effet de bord ?
40
ScalaCL : encore un prototype
• Scalaxy : spin-off généraliste plutôt stable
• Fonctionalités expérimentales :captures, random, reduce
•Macros Scala 2.10
41
OpenCL
•Votre GPU se tourne les pouces
•Write once, run (almost) everywhere
http://javacl.googlecode.comhttp://scalacl.googlecode.com
42
CLFilteredArray[T]
• Tableau de valeurs + Bitmap de présence
• Compactage :
• Somme préfixée
• Recopie aux incréments
• Exemple : filtrage pairsf: x => ((x % 2) == 0)
45
JavaCL : hôte minimaliste
• Choix d'un contexte + file d'exécution :CLContext context = JavaCL.createBestContext(DoubleSupport);CLQueue queue = context.createDefaultQueue();
• Création de tableaux :DoubleBuffer values = ...;CLDoubleBuffer params = context.createDoubleBuffer(Usage.Input, values);
• Compilation du programme :CLKernel scos = context.createProgram(src).createKernel("scos");
• Exécution parallèle :scos.setArgs(params, out, length);CLEvent evt = scos.enqueueNDRange(queue, new int[] { length });
47