Generative and Meta-Programming - Modern C++ Design for Parallel Computing
Boost.SIMD
1. Le SIMD en pratique avec Boost.SIMD
Unlocked software performance
Mathias Gaunard, Joel Falcou
NumScale - Université Paris Sud
23 mai 2014
2. Unlocked software performance
NumScale en quelques mots
La Société
■ Start-up implantée sur le campus de l’Université Paris-Sud, sur le plateau de
Saclay
■ Expertise en optimisation des logiciels et en calcul parallèle
Solutions
■ Proler sous Linux non-intrusif (langages compilés et JIT)
■ Bibliothèques C++ pour le calcul optimisé
■ Compilateurs (Python, MATLAB)
■ Optimisation de logiciels
■ Portage et passage à l’échelle
1 of 35
3. Unlocked software performance
NumScale en quelques mots
■ Permettre aux développeurs d’accéder à la pleine puissance des processeurs
modernes
■ Optimisation des calculs en prenant en compte algorithmes, matériel et
techniques de programmation
Algorithme
Analyse numérique
Algèbre linéaire
Traitement du signal
Traitement d’image
Vision
Simulation
Statistiques
...
Matériel
SIMD
Multi-cœurs
Distribué
GPU
Smartphones
Embarqué, DSPs
Logiciel
C, C++
FORTRAN
MATLAB
Python
Java, C#
2 of 35
4. Unlocked software performance
NumScale et le C++
Pourquoi le C++
■ Le C++ a l’accès bas niveau nécessaire pour exploiter au mieux la
mémoire, le système, les processeurs et le parallélisme
■ Le C++ a les capacités d’abstraction nécessaires pour pouvoir
construire des composants portables et ré-utilisables
NumScale s’implique
■ Implication auprès du comité de normalisation ISO
■ Participation à la communauté open-source, en particulier via les
bibliothèques Boost
3 of 35
5. Unlocked software performance
NumScale et le SIMD
■ Parallélisation à l’intérieur même des cœurs, peu utilisé en pratique
■ Gains de l’ordre de x2 à x16 cumulable avec le multi-cœurs
■ Réduire les temps de calcul sans toucher à l’infrastructure
■ Marche particulièrement bien pour tout le calcul numérique type HPC
4 of 35
7. Unlocked software performance
Un parallélisme toujours plus présent
Le parallélisme évident
■ Architecture Multi-cœurs
■ Architecture Many-cœurs
■ Systèmes Distribués
Le parallélisme moins évident
■ Pipeline intra-processeurs
■ Exécutions super-scalaire et/ou out of order
■ les extensions SIMD
6 of 35
8. Unlocked software performance
Un parallélisme toujours plus présent
Le parallélisme évident
■ Architecture Multi-cœurs
■ Architecture Many-cœurs
■ Systèmes Distribués
Le parallélisme moins évident
■ Pipeline intra-processeurs
■ Exécutions super-scalaire et/ou out of order
■ les extensions SIMD
6 of 35
9. Unlocked software performance
Qu’est-ce que le SIMD ?
Instructions
Data
Results
SISD SIMD
Principes
■ Single Instruction, Multiple Data
■ Chaque operation est appliquée sur
N valeurs dans un seul registre (si
registres 128 bits, 4 valeurs de 32
bits ou 2 valeurs de 64 bits)
■ Théoriquement N fois plus rapide
que l’ALU/FPU en mode normal
7 of 35
14. Unlocked software performance
Le SIMD en mode manuel, int32 * int32 -> int32
// Altivec
// reinterpret as u16
short0 = (__vector unsigned short)a0 ;
short1 = (__vector unsigned short)a1 ;
// shifting constant
shift = vec_splat_u32 (-16) ;
sf = vec_rl(a1, shift_) ;
// Compute high part of the product
high = vec_msum( short0 , (__vector unsigned short)sf
, vec_splat_u32 (0)
) ;
// Complete by adding low part of the 16 bits product
return vec_add( vec_sl(high , shift_)
, vec_mulo(short0 , short1)
) ;
9 of 35
15. Unlocked software performance
Et les compilateurs alors ?
Limitations de l’auto-vectorisation
■ L’auto-vectorisation ne se déclenche que si :
□ la mémoire est bien agencée
□ le code est intrinséquement vectorisable
■ Les fonctions compilées à l’extérieur ne sont pas vectorisées
■ Le compilateur peut manquer d’informations pour effectuer la vectorisation
Conclusion
■ Le SIMD explicite permet de garantir la vectorisation
■ Challenge : Maintenir un code SIMD sur de multiples plate-formes
10 of 35
16. Unlocked software performance
Notre approche
Une abstraction de haut-niveau
■ Utilisation d’un Domain-Specic Embedded Language (DSEL)
■ Abstraction des registres SIMD comme un bloc de données
■ Applications d’optimisations au niveau des expressions
Integration au langage
■ Permettre l’écriture de code générique
■ Intégration au sein de la STL
■ Reposer sur des concepts issus du C++ moderne
11 of 35
18. Unlocked software performance
L’abstraction pack
La notion simd::pack<T,N>
pack<T, N> registre SIMD contenant N élements de type T
pack<T> idem avec le N optimal pour l’architecture courante
Se comporte comme une valeur de type T mais en effectuant les opérations sur les N
valeurs de son contenu en une seul fois.
Contraintes
■ T est soit un type fondamental soit un tuple Fusion
■ logical<T> permet de gérer les valeurs booléennes.
■ N doit être une puissance de 2.
13 of 35
19. Unlocked software performance
Opérations sur les pack
Opérateurs du langage
■ Tous les opérateurs classiques sont applicables : pack<T> ⊕ pack<T> , pack<T> ⊕ T ,
T ⊕ pack<T>
■ Pas de conversion ni de promotion entière :
uint8_t(255) + uint8_t(1) = uint8_t(0)
Comparaisons
■ ==, !=, <, <=,> et >= effectue des comparaisons vectorielles.
■ compare_equal, compare_less, etc. retournent le résultat booléen de la
comparaison lexicographique de leurs paramètres.
Autres propriétés
■ Modélise à la fois une RandomAccessFusionSequence et RandomAccessRange
■ p[i] retourne un proxy pour l’accès aux éléments du registre
14 of 35
20. Unlocked software performance
Gestion des chargements
Chargement
■ Mode aligné (aligned_load/store) et non-aligné (load/store)
■ Gestion des chargements statiquement désalignés
■ Gestion des chargements/stockages conditionnels et/ou dispersés
15 of 35
21. Unlocked software performance
Gestion des chargements
Chargement
■ Mode aligné (aligned_load/store) et non-aligné (load/store)
■ Gestion des chargements statiquement désalignés
■ Gestion des chargements/stockages conditionnels et/ou dispersés
Exemples
aligned_load< pack<T, N> >(p, i) charge un pack depuis l’adresse alignée p + i.
0D 0E 0F 10 11 12 13 14 15 16 17 18
aligned_load<pack<float>>(0x10,0)
Main Memory
... ...
10 11 12 13
15 of 35
22. Unlocked software performance
Gestion des chargements
Chargement
■ Mode aligné (aligned_load/store) et non-aligné (load/store)
■ Gestion des chargements statiquement désalignés
■ Gestion des chargements/stockages conditionnels et/ou dispersés
Exemples
aligned_load< pack<T, N>, Offset>(p, i) charge un pack depuis l’adresse alignée
p + i + Offset.
0D 0E 0F 10 11 12 13 14 15 16 17 18
aligned_load<pack<float>,2>(0x10,2)
Main Memory
... ...
12 13 14 15
15 of 35
23. Unlocked software performance
Réordonnancement de registre
Principe et Intérêt
■ Les éléments d’un registre SIMD sont permutables par le hardware
■ Remplace des chargements mémoires dans certains algorithmes
■ Encapsulé par boost::simd::shuffle
Exemples :
// a = [ 1 2 3 4 ]
pack <float > a = enumerate < pack <float > >(1) ;
// b = [ 10 11 12 13 ]
pack <float > b = enumerate < pack <float > >(10) ;
// res = [4 12 0 10]
pack <float > res = shuffle <3,6,-1,4>(a,b) ;
16 of 35
24. Unlocked software performance
Réordonnancement de registre
Principe et Intérêt
■ Les éléments d’un registre SIMD sont permutables par le hardware
■ Remplace des chargements mémoires dans certains algorithmes
■ Encapsulé par boost::simd::shuffle
Exemples :
struct reverse_
{
template <class I, class C>
struct apply : mpl : :int_ <C : :value - I : :value - 1> {} ;
} ;
// res = [n n-1 ... 2 1]
pack <float > res = shuffle <reverse_ >(a) ;
16 of 35
25. Unlocked software performance
Intégration avec la STL
■ Algorithmes :
□ boost::simd::transform
□ boost::simd::fold
□ Foncteur polymorphe pour support scalaire/SIMD
17 of 35
26. Unlocked software performance
Intégration avec la STL
■ Algorithmes :
□ boost::simd::transform
□ boost::simd::fold
□ Foncteur polymorphe pour support scalaire/SIMD
■ Iterateurs :
□ Encapsule des stratégies de parcours SIMD :
□ boost::simd::(aligned_)(input/output_)iterator
□ boost::simd::direct_output_iterator
□ boost::simd::shifted_iterator
17 of 35
27. Unlocked software performance
Intégration avec la STL
■ Algorithmes :
□ boost::simd::transform
□ boost::simd::fold
□ Foncteur polymorphe pour support scalaire/SIMD
■ Iterateurs :
□ Encapsule des stratégies de parcours SIMD :
□ boost::simd::(aligned_)(input/output_)iterator
□ boost::simd::direct_output_iterator
□ boost::simd::shifted_iterator
■ Allocateur :
□ Fournit de la mémoire correctement alignée
□ Possibilité d’adapter un allocateur existant
17 of 35
28. Unlocked software performance
Intégration avec la STL
std : :vector <float , simd : :allocator <float > > v(N) ;
simd : :transform( v.begin(), v.end()
, []( auto const& p)
{
return p * 2.f ;
}
) ;
18 of 35
30. Unlocked software performance
Optimisations architecturales
Problématique
■ La plupart des extensions SIMD proposent des opérateurs fusionnés type fma.
■ Ces optimisations doivent rester transparentes
■ Via une implantation à base d’Expression Templates, B.SIMD auto-optimise
ces motifs.
Exemple :
■ a * b + c s’évalue comme fma(a, b, c)
■ a + b * c s’évalue comme fma(b, c, a)
■ !(a < b) s’évalue comme is_nle(a, b)
19 of 35
31. Unlocked software performance
Architectures Supportées
Version Open Source
■ Intel SSE2-4, AVX
■ PowerPC VMX
Version Propriétaire
■ ARM Neon
■ Intel AVX2, XOP, FMA3, FMA4
■ Intel MIC
20 of 35
32. Unlocked software performance
Autres fonctions ...
Arithmetic
■ arithmetique saturée
■ multiplication longue
■ conversion oat/int
■ round, oor, ceil, trunc
■ sqrt, cbrt
■ hypot
■ average
■ random
■ min/max
■ division et reste arrondi
Bitwise
■ select
■ andnot, ornot
■ popcnt
■ ffs
■ ror, rol
■ rshr, rshl
■ twopower
IEEE
■ ilogb, frexp
■ ldexp
■ next/prev
■ ulpdist
Predicates
■ comparaison à zero
■ négation de
comparaison
■ is_unord, is_nan,
is_invalid
■ is_odd, is_even
■ majority
21 of 35
33. Unlocked software performance
Réduction et Opérations intra-registre
Reduction
■ any, all
■ nbtrue
■ minimum/maximum,
posmin/posmax
■ sum
■ product, dot product
SWAR
■ group/split
■ reduction splattée
■ cumsum
■ sort
22 of 35
35. Unlocked software performance
Fonctions de base
Fonctions trigonométriques simple précision
Architecture : Core i7 SandyBridge, AVX en cycles/valeurs
Fonction Intervalle std Scalaire SIMD
exp [−10, 10] 46 38 7
log [−10, −10] 42 37 5
asin [−1, 1] 40 35 13
cos [−20π, 20π] 66 47 6
fast_cos [−π/4, π/4] 32 9 1.3
24 of 35
36. Unlocked software performance
Générateur de fractale
■ Génére une image fractale via l’évalutaion d’un fonction complexe
■ Application compute-bound
■ Challenge : Quantité de travail dépendante du pixel
25 of 35
37. Unlocked software performance
Générateur de fractale
template <class T> typename meta : :as_integer <T> : :type
julia(T const& a, T const& b)
{
typename meta : :as_integer <T> : :type iter ;
std : :size_t i = 0 ;
T x, y ;
do {
T x2 = x * x ;
T y2 = y * y ;
T xy = s_t(2) * x * y ;
x = x2 - y2 + a ;
y = xy + b ;
iter = selinc(x2 + y2 < T(4), iter) ;
} while(any(mask) && i++ < 256) ;
return iter ;
}
26 of 35
39. Unlocked software performance
Détection de Mouvements
■ Algorithme Sigma-Delta par Manzanera et al.
■ Approche mono-modale basé sur l’extraction du fond
■ Modélise la variation d’intensité par une gaussienne en chaque pixel
■ Challenge : Intensité arithmétique très faible
28 of 35
40. Unlocked software performance
Détection de Mouvements
template <typename T>
T sigma_delta(T& bkg , T const& frm , T& var)
{
bkg = selinc(bkg < frm , seldec(bkg > fr, bkg)) ;
T dif = dist(bkg , frm) ;
T mul = muls(dif ,3) ;
var = if_else( dif != T(0)
, selinc(var < mul , seldec(var > mul , var))
, var
) ;
return if_zero_else_one( dif < var ) ;
}
29 of 35
42. Unlocked software performance
Solveur de Système Tridiagonal Creux
■ Résout Ax = b avec A sparse
■ Application : mécanique des
uides
■ Challenge : vectoriser malgré
l’aspect sparse
■ Solution : Mélanges arbitraires
pour recompactication
31 of 35
45. Unlocked software performance
Conclusion
Boost.SIMD
■ C++ permet d’allier abstraction et performance
■ Une accélération garantie sur un large panel d’architectures
■ Retrouvez nous sur https://github.com/MetaScale/nt2
■ Tests, commentaires et retours bienvenus
À venir
■ Intégration de la version Open Source dans Boost
■ Support pour nouvelles architectures : QPX, C6x, etc...
34 of 35