Académique Documents
Professionnel Documents
Culture Documents
Amina Guermouche
Télécom SudParis
Premiers pas Les blocks Threads Optimisations
CUDA C
2 / 75
Premiers pas Les blocks Threads Optimisations
Fonctionnement
3 / 75
Premiers pas Les blocks Threads Optimisations
Fonctionnement
3 / 75
Premiers pas Les blocks Threads Optimisations
Fonctionnement
4 / 75
Premiers pas Les blocks Threads Optimisations
Interrogation du GPU
• Quel est le nombre de GPUs disponibles
• Quelle est la taille de la mémoire disponible ?
• Quelles sont les caractéristiques des GPUs ?
cudaDeviceProp prop ;
i n t count ;
c u d a G e t D e v i c e C o u n t (& c o u n t ) ;
f o r ( i n t i = 0 ; i < c o u n t ; i ++)
{
c u d a G e t D e v i c e P r o p e r t i e s (& prop , i ) ;
p r i n t f ( ’ ’ T a i l l e t o t a l de l a memoire g l o b a l e
%l d \n ’ ’ , p r o p . t o t a l G l o b a l M e m ) ;
}
Exercice 1
6 / 75
Premiers pas Les blocks Threads Optimisations
Hello, World !
i n t main ( v o i d ) {
p r i n t f ( ’ ’ H e l l o , World ! \ n ’ ’ ) ;
return 0;
}
7 / 75
Premiers pas Les blocks Threads Optimisations
Hello, World !
i n t main ( v o i d ) {
kernel<<<1,1>>>();
p r i n t f ( ’ ’ H e l l o , World ! \ n ’ ’ ) ;
return 0;
}
7 / 75
Premiers pas Les blocks Threads Optimisations
Hello, World !
Code du device
__global__ v o i d k e r n e l ( v o i d )
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
∗ c = ∗ a + ∗b ;
}
9 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
∗ c = ∗ a + ∗b ;
}
9 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
∗ c = ∗ a + ∗b ;
}
i n t main ( v o i d ) {
int a , b, c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = sizeof ( int ) ;
10 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
∗ c = ∗ a + ∗b ;
}
i n t main ( v o i d ) {
int a , b, c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = sizeof ( int ) ;
// allocation de l’espace pour le device
cudaMalloc( (void **)&gpu_a, size) ;
cudaMalloc( (void **)&gpu_b, size) ;
cudaMalloc( (void **)&gpu_c, size) ;
a=2 ;
b=7 ;
10 / 75
Premiers pas Les blocks Threads Optimisations
return 0
}
11 / 75
Premiers pas Les blocks Threads Optimisations
return 0
}
11 / 75
Premiers pas Les blocks Threads Optimisations
return 0
}
11 / 75
Premiers pas Les blocks Threads Optimisations
return 0
}
11 / 75
Premiers pas Les blocks Threads Optimisations
12 / 75
Premiers pas Les blocks Threads Optimisations
12 / 75
Premiers pas Les blocks Threads Optimisations
+ + + + + + + +
b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] • Comment sont exprimés les indices sur
le GPU ?
c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7]
12 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
c [ blockIdx.x ] = a [ blockIdx.x ] + b [ blockIdx.x ] ;
}
13 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
c [ blockIdx.x ] = a [ blockIdx.x ] + b [ blockIdx.x ] ;
}
Block0 Block1
Block2 Block3
#d e f i n e N 512 // nombre d ’ e l e m e n t s du t a b l e a u
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
// a l l o c a t i o n de l ’ e s p a c e p o u r l e d e v i c e }
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_a , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_b , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_c , s i z e ) ;
a=( i n t ∗ ) m a l l o c ( s i z e ) ;
b=( i n t ∗ ) m a l l o c ( s i z e ) ;
r a n d o m _ i n t s ( a , N) ;
r a n d o m _ i n t s ( b , N) ;
14 / 75
Premiers pas Les blocks Threads Optimisations
// C o p i e d e s d o n n e e s v e r s l e D e v i c e
cudaMemcpy ( gpu_a , a , s i z e , cudaMemcpyHostToDevice ) ;
cudaMemcpy ( gpu_b , b , s i z e , cudaMemcpyHostToDevice ) ;
// C o p i e du r e s u l t a t
cudaMemcpy ( c , gpu_c , s i z e , cudaMemcpyDeviceToHost ) ;
15 / 75
Premiers pas Les blocks Threads Optimisations
16 / 75
Premiers pas Les blocks Threads Optimisations
Grille et blocks
gridDim.x
Block2 Block3
17 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
int x = blockIdx . x ;
int y = blockIdx . y ;
i n t i n d i c e = x + y ∗ gridDim . x ;
c [ indice ] = a[ indice ] + b[ indice ];
}
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
...
dim3 g r i d (N, N) ;
add <<<g r i d , 1 >>> ( dev_a , dev_b , dev_c ) ;
...
}
18 / 75
Premiers pas Les blocks Threads Optimisations
Exercice 2
19 / 75
Premiers pas Les blocks Threads Optimisations
Threads
20 / 75
Premiers pas Les blocks Threads Optimisations
#d e f i n e N 512 // nombre d ’ e l e m e n t s du t a b l e a u
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
// a l l o c a t i o n de l ’ e s p a c e p o u r l e d e v i c e }
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_a , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_b , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_c , s i z e ) ;
a=( i n t ∗ ) m a l l o c ( s i z e ) ;
b=( i n t ∗ ) m a l l o c ( s i z e ) ;
r a n d o m _ i n t s ( a , N) ;
r a n d o m _ i n t s ( b , N) ;
21 / 75
Premiers pas Les blocks Threads Optimisations
// C o p i e d e s d o n n e e s v e r s l e D e v i c e
cudaMemcpy ( gpu_a , a , s i z e , cudaMemcpyHostToDevice ) ;
cudaMemcpy ( gpu_b , b , s i z e , cudaMemcpyHostToDevice ) ;
// Lancement de l ’ o p e r a t i o n a v e c N t h r e a d s
add <<< 1 , N >>> ( gpu_a , gpu_b , gpu_c ) ;
// C o p i e du r e s u l t a t
cudaMemcpy ( c , gpu_c , s i z e , cudaMemcpyDeviceToHost ) ;
22 / 75
Premiers pas Les blocks Threads Optimisations
23 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
i n t i n d i c e = t h r e a d I d x . x + b l o c k I d x . x ∗ blockDim .
x;
c [ indice ] = a[ indice ] + b[ indice ];
}
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
// a l l o c a t i o n de l ’ e s p a c e p o u r l e d e v i c e }
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_a , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_b , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_c , s i z e ) ;
24 / 75
Premiers pas Les blocks Threads Optimisations
a=( i n t ∗ ) m a l l o c ( s i z e ) ;
b=( i n t ∗ ) m a l l o c ( s i z e ) ;
ra n d o m _ i n t s ( a , N) ;
ra n d o m _ i n t s ( b , N) ;
// C o p i e d e s d o n n e e s v e r s l e D e v i c e
cudaMemcpy ( gpu_a , a , s i z e , cudaMemcpyHostToDevice ) ;
cudaMemcpy ( gpu_b , b , s i z e , cudaMemcpyHostToDevice ) ;
// Lancement de l ’ o p e r a t i o n a v e c THREAD_PER_BLOCK
par block
add <<< N/THREAD_PER_BLOCK , THREAD_PER_BLOCK >>>
( gpu_a , gpu_b , gpu_c ) ;
// C o p i e du r e s u l t a t
cudaMemcpy ( c , gpu_c , s i z e , cudaMemcpyDeviceToHost ) ;
25 / 75
Premiers pas Les blocks Threads Optimisations
26 / 75
Premiers pas Les blocks Threads Optimisations
Exercice 3
27 / 75
Premiers pas Les blocks Threads Optimisations
• Au niveau du main
add <<< ( N+THREAD_PER_BLOCK-1 ) /
THREAD_PER_BLOCK, THREAD_PER_BLOCK >>> (
gpu_a , gpu_b , gpu_c , N) ;
28 / 75
Premiers pas Les blocks Threads Optimisations
29 / 75
Premiers pas Les blocks Threads Optimisations
blockIdx.x
threadIdx.x
blockIdx.y threadIdx.y
30 / 75
Premiers pas Les blocks Threads Optimisations
blockIdx.x
threadIdx.x
blockIdx.y threadIdx.y
30 / 75
Premiers pas Les blocks Threads Optimisations
blockIdx.x
threadIdx.x
blockIdx.y threadIdx.y
blockIdx.x*blockDim.x threadIdx.x
30 / 75
Premiers pas Les blocks Threads Optimisations
blockIdx.x
blockIdx.y*blockDim.y
threadIdx.x
threadIdx.y
blockIdx.y threadIdx.y
blockIdx.x*blockDim.x threadIdx.x
30 / 75
Premiers pas Les blocks Threads Optimisations
Addition de 2 matrices
• colonne = blockIdx.x*blockDim.x+theadIdx.x
• ligne = blockIdx.y*blockDim.y+theadIdx.y
blockIdx.x
blockIdx.y*blockDim.y
threadIdx.x
threadIdx.y
blockIdx.y threadIdx.y
blockIdx.x*blockDim.x threadIdx.x
31 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d add ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
i n t c o l o n n e = b l o c k I d x . x ∗ blockDim . x+t h e a d I d x . x ;
i n t l i g n e = b l o c k I d x . y ∗ blockDim . y+t h e a d I d x . y ;
i n t i n d i c e = l i g n e ∗ N + colonne ;
// N = g r i d D i m . x ∗ blockDim . x ;
c [ indice ] = a[ indice ] + b[ indice ];
}
i n t main ( i n t a r g c , c h a r ∗∗ a r g v )
{
...
dim3 b l o c k (THREAD_PER_BLOCK, THREAD_PER_BLOCK) ;
dim3 g r i d (N/ blockDim . x , N/ blockDim . y ) ;
add <<<g r i d , b l o c k >>> ( dev_a , dev_b , dev_c ) ;
...
}
32 / 75
Premiers pas Les blocks Threads Optimisations
• 1 thread = 1 coeur
• 1 block = 1SM
• 1 block est exécuté sur 1SM
• Blocks :
• Les blocks sont exécutés dans n’importe quel ordre,
séquentiellement ou en parallèle
• L’avantage est que ça scale automatiquement avec le nombre
de SM
Block0 Block1
Block0 Block1 Block2 Block3
Block2 Block3
33 / 75
Premiers pas Les blocks Threads Optimisations
• 1 thread = 1 coeur
• 1 block = 1SM
• 1 block est exécuté sur 1SM
• Blocks :
• Les blocks sont exécutés dans n’importe quel ordre,
séquentiellement ou en parallèle
• L’avantage est que ça scale automatiquement avec le nombre
de SM
• Threads
• Contrairement aux blocks, les threads peuvent
• Communiquer
• Se synchroniser
• Ces opérations sont à l’intérieur d’un block
33 / 75
Premiers pas Les blocks Threads Optimisations
• Les blocks :
• Le nombre de blocks doit être supérieur au nombre de SM
(pour que tous travaillent)
• Il devrait y avoir plusieurs blocks par SM, afin que d’autres
blocks s’exécutent pendant une synchronisation
→ Si une synchronisation est utilisée, il vaut mieux utiliser
plusieurs petits blocks qu’un grand
• Les threads :
• Les SM ordonnancent les threads par groupe SIMD de 32
(warp) sur Quadro 620
• Les threads d’un warp sont synchronisés
34 / 75
Premiers pas Les blocks Threads Optimisations
• Les blocks :
• Le nombre de blocks doit être supérieur au nombre de SM
(pour que tous travaillent)
• Il devrait y avoir plusieurs blocks par SM, afin que d’autres
blocks s’exécutent pendant une synchronisation
→ Si une synchronisation est utilisée, il vaut mieux utiliser
plusieurs petits blocks qu’un grand
• Les threads :
• Les SM ordonnancent les threads par groupe SIMD de 32
(warp) sur Quadro 620
• Les threads d’un warp sont synchronisés
34 / 75
Premiers pas Les blocks Threads Optimisations
35 / 75
Premiers pas Les blocks Threads Optimisations
Execice 4
36 / 75
Premiers pas Les blocks Threads Optimisations
a b
a0 ∗ b0
a1 ∗ b1
c
a2 ∗ b2
+
a3 ∗ b3
a4 ∗ b4
a5 ∗ b5
c = (a0 , a1 , a2 , a3 , a4 , a5 ).(b0 , b1 , b2 , b3 , b4 , b5 )
= a0 b0 + a1 b1 + a2 b2 + a3 b3 + a4 b4 + a5 b5
37 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d d o t ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
// c h a q u e t h r e a d c a l c u l e l e p r o d u i t d ’ une p a i r e
i n t temp = a [ t h r e a d I d x . x ] ∗ b [ t h r e a d I d x . x ] ;
}
38 / 75
Premiers pas Les blocks Threads Optimisations
__global__ v o i d d o t ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
// c h a q u e t h r e a d c a l c u l e l e p r o d u i t d ’ une p a i r e
i n t temp = a [ t h r e a d I d x . x ] ∗ b [ t h r e a d I d x . x ] ;
}
38 / 75
Premiers pas Les blocks Threads Optimisations
39 / 75
Premiers pas Les blocks Threads Optimisations
#d e f i n e N 512 // t a i l l e du t a b l e a u
__global__ v o i d d o t ( i n t ∗a , i n t ∗b , i n t ∗ c ) {
__shared__ i n t tmp [ N ]
// c h a q u e t h r e a d c a l c u l e l e p r o d u i t d ’ une p a i r e
i n t temp [ t h r e a d I d x . x ] = a [ t h r e a d I d x . x ] ∗ b [
threadIdx . x ] ;
// Le t h r e a d 0 e f f e c t u e l a somme
i f ( 0 == t h r e a d I d x . x ) {
i n t sum = 0 ;
f o r ( i n t i = 0 ; i < N ; i ++)
sum = sum + temp [ i ] ;
∗ c = sum ;
}
}
40 / 75
Premiers pas Les blocks Threads Optimisations
41 / 75
Premiers pas Les blocks Threads Optimisations
// S y n c h r o n i s a t i o n p o u r e t r e s u r que t o u t l e s
t h r e a d s ont f i n i
__syncthreads ( ) ;
// Le t h r e a d 0 e f f e c t u e l a somme
i f ( 0 == t h r e a d I d x . x ) {
i n t sum = 0 ;
f o r ( i n t i = 0 ; i < N ; i ++)
sum = sum + temp [ i ] ;
∗ c = sum ;
}
}
42 / 75
Premiers pas Les blocks Threads Optimisations
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
// a l l o c a t i o n de l ’ e s p a c e p o u r l e d e v i c e }
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_a , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_b , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_c , s i z e o f ( i n t ) ) ;
a=( i n t ∗ ) m a l l o c ( s i z e ) ;
b=( i n t ∗ ) m a l l o c ( s i z e ) ;
r a n d o m _ i n t s ( a , N) ;
r a n d o m _ i n t s ( b , N) ;
43 / 75
Premiers pas Les blocks Threads Optimisations
// Lancement de l ’ o p e r a t i o n a v e c N t h r e a d s e t un
seul block
d o t <<< 1 , N >>> ( gpu_a , gpu_b , gpu_c ) ;
// C o p i e du r e s u l t a t
cudaMemcpy(&c , gpu_c , s i z e o f ( i n t ) ,
cudaMemcpyDeviceToHost ) ;
44 / 75
Premiers pas Les blocks Threads Optimisations
a b
∗
∗ sum
∗ +
∗
∗
∗ c
∗
∗ sum
∗ +
∗
∗
∗
45 / 75
Premiers pas Les blocks Threads Optimisations
// S y n c h r o n i s a t i o n ( d a n s l e b l o c k )
__syncthreads ( ) ;
// Le t h r e a d 0 e f f e c t u e l a somme
i f ( 0 == t h r e a d I d x . x ) {
i n t sum = 0 ;
f o r ( i n t i = 0 ; i < THREADS_PER_BLOCK ; i ++)
sum = sum + temp [ i ] ;
∗ c = sum ;
}
} 46 / 75
Premiers pas Les blocks Threads Optimisations
Race condition
47 / 75
Premiers pas Les blocks Threads Optimisations
Race condition
47 / 75
Premiers pas Les blocks Threads Optimisations
// S y n c h r o n i s a t i o n ( d a n s l e b l o c k )
__syncthreads ( ) ;
// Le t h r e a d 0 e f f e c t u e l a somme
i f ( 0 == t h r e a d I d x . x ) {
i n t sum = 0 ;
f o r ( i n t i = 0 ; i < THREADS_PER_BLOCK ; i ++)
sum = sum + temp [ i ] ;
atomicAdd ( ∗ c , sum ) ;
}
} 48 / 75
Premiers pas Les blocks Threads Optimisations
i n t main ( v o i d ) {
i n t ∗a , ∗b , ∗ c ;
i n t ∗gpu_a , ∗gpu_b , ∗gpu_c ;
int size = N ∗ sizeof ( int ) ;
// a l l o c a t i o n de l ’ e s p a c e p o u r l e d e v i c e }
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_a , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_b , s i z e ) ;
c u d a M a l l o c ( ( v o i d ∗ ∗ )&gpu_c , s i z e ) ;
a=( i n t ∗ ) m a l l o c ( s i z e ) ;
b=( i n t ∗ ) m a l l o c ( s i z e ) ;
c=( i n t ∗ ) m a l l o c ( s i z e o f ( i n t ) ) ;
r a n d o m _ i n t s ( a , N) ;
r a n d o m _ i n t s ( b , N) ;
49 / 75
Premiers pas Les blocks Threads Optimisations
// Lancement de l ’ o p e r a t i o n a v e c THREAD_PER_BLOCK
par block
add <<< N/THREAD_PER_BLOCK,THREAD_PER_BLOCK >>> (
gpu_a , gpu_b , gpu_c ) ;
// C o p i e du r e s u l t a t
cudaMemcpy ( c , gpu_c , s i z e , cudaMemcpyDeviceToHost ) ;
50 / 75
Premiers pas Les blocks Threads Optimisations
Mesure du temps
cudaMemcpy ( d_x , x , N∗ s i z e o f ( f l o a t ) ,
cudaMemcpyHostToDevice ) ;
cudaMemcpy ( d_y , y , N∗ s i z e o f ( f l o a t ) ,
cudaMemcpyHostToDevice ) ;
t 1 = myCPUTimer ( ) ;
s a x p y <<<(N+255) / 2 5 6 , 256>>>(N, 2 . 0 , d_x , d_y ) ;
cudaDeviceSynchronize () ;
t 2 = myCPUTimer ( ) ;
cudaMemcpy ( y , d_y , N∗ s i z e o f ( f l o a t ) ,
cudaMemcpyDeviceToHost ) ;
51 / 75
Premiers pas Les blocks Threads Optimisations
Mesure du temps
cudaEvent_t s t a r t , s t o p ;
c u d a E v e n t C r e a t e (& s t a r t ) ;
c u d a E v e n t C r e a t e (& s t o p ) ;
...
cudaEventRecord ( s t a r t ) ;
s a x p y <<<(N+255) / 2 5 6 , 256>>>(N, 2 . 0 f , d_x , d_y ) ;
cudaEventRecord ( stop ) ;
c u d a E v e n t S y n c h r o n i z e ( s t o p ) ; // G a r a n t i t que l ’
evenement s ’ e s t e x e c u t e
...
f l o a t milliseconds = 0;
c u d a E v e n t E l a p s e d T i m e (& m i l l i s e c o n d s , s t a r t , s t o p ) ;
52 / 75
Premiers pas Les blocks Threads Optimisations
Exercice 5
53 / 75
Premiers pas Les blocks Threads Optimisations
http:
//docs.nvidia.com/cuda/cuda-c-best-practices-guide/
54 / 75
Premiers pas Les blocks Threads Optimisations
Throughput de la mémoire
55 / 75
Premiers pas Les blocks Threads Optimisations
La mémoire globale
1er load t0 t1 t2 t3
a(0, 0)a(0, 1)a(0, 2)a(0, 3)a(1, 0)a(1, 1)a(1, 2)a(1, 3)a(2, 0)a(2, 1)a(2, 2)a(2, 3)a(3, 0)a(3, 1)a(3, 2)a(3, 3)
56 / 75
Premiers pas Les blocks Threads Optimisations
La mémoire globale
1er load t0 t1 t2 t3
a(0, 0)a(0, 1)a(0, 2)a(0, 3)a(1, 0)a(1, 1)a(1, 2)a(1, 3)a(2, 0)a(2, 1)a(2, 2)a(2, 3)a(3, 0)a(3, 1)a(3, 2)a(3, 3)
56 / 75
Premiers pas Les blocks Threads Optimisations
La mémoire partagée
57 / 75
Premiers pas Les blocks Threads Optimisations
La mémoire partagée
58 / 75
Premiers pas Les blocks Threads Optimisations
Bank conflict
59 / 75
Premiers pas Les blocks Threads Optimisations
Bank conflict
60 / 75
Premiers pas Les blocks Threads Optimisations
Exercice 6
61 / 75
Premiers pas Les blocks Threads Optimisations
Multiplication de matrice
• C(0,0) ->
blockIdx.x=0,blockIdx.y=0 B(0,0)
• C(0,1) ->
blockIdx.x=1,blockIdx.y=0
• C(1,0) ->
blockIdx.x=0,blockIdx.y=1 B(1,0)
• C(1,1) ->
blockIdx.x=1,blockIdx.y=1
62 / 75
Premiers pas Les blocks Threads Optimisations
Multiplication de matrice
B(1,0)
62 / 75
Premiers pas Les blocks Threads Optimisations
Multiplication de matrice
62 / 75
Premiers pas Les blocks Threads Optimisations
Multiplication de matrice
62 / 75
Premiers pas Les blocks Threads Optimisations
blockIdx.x
blockIdx.y*blockDim.y
threadIdx.x
threadIdx.y
blockIdx.y threadIdx.y
blockIdx.x*blockDim.x threadIdx.x
63 / 75
Premiers pas Les blocks Threads Optimisations
donnée
blockIdx.y*blockDim.y
thread
threadIdx.y
blockIdx.y
tx
63 / 75
Premiers pas Les blocks Threads Optimisations
donnée
thread
ligne * nbColumnsA
blockIdx.y
tx
63 / 75
Premiers pas Les blocks Threads Optimisations
donnée
thread
ligne * nbColumnsA
blockIdx.y
tx TILE_WIDTH
63 / 75
Premiers pas Les blocks Threads Optimisations
donnée
thread
ligne * nbColumnsA
blockIdx.y
tx 2*TILE_WIDTH
63 / 75
Premiers pas Les blocks Threads Optimisations
• col = blockIdx.x*blockDim.x+theadIdx.x
• ligne = blockIdx.y*blockDim.y+theadIdx.y
• TILE_WIDTH = blockDim.x
• indice = ligne * nb_colA + TILE_WIDTH * tileId +
threadIdx.x
64 / 75
Premiers pas Les blocks Threads Optimisations
donnée threadIdx.y
thread
col
65 / 75
Premiers pas Les blocks Threads Optimisations
thread
col
65 / 75
Premiers pas Les blocks Threads Optimisations
thread nb_col*TILE_WIDTH
col
65 / 75
Premiers pas Les blocks Threads Optimisations
thread nb_col*TILE_WIDTH
nb_col*ty
col
65 / 75
Premiers pas Les blocks Threads Optimisations
thread
2*nb_col*TILE_WIDTH
col
nb_col*ty
65 / 75
Premiers pas Les blocks Threads Optimisations
• col = blockIdx.x*blockDim.x+theadIdx.x
• ligne = blockIdx.y*blockDim.y+theadIdx.y
• TILE_WIDTH = blockDim.x
• indice = col + (nb_colB * TILE_WIDTH * tileId + ty
* nb_col)
66 / 75
Premiers pas Les blocks Threads Optimisations
nbCol * ligne
blockIdx.y
col
67 / 75
Premiers pas Les blocks Threads Optimisations
68 / 75
Premiers pas Les blocks Threads Optimisations
69 / 75
Premiers pas Les blocks Threads Optimisations
Les streams
70 / 75
Premiers pas Les blocks Threads Optimisations
Les streams
71 / 75
Premiers pas Les blocks Threads Optimisations
Exemple d’exécution
temps
H2D K2 D2H
H2D K3 D2H
temps
72 / 75
Premiers pas Les blocks Threads Optimisations
cudaStream_T s t r e a m 1 , s t r e a m 2 , s t r e a m 3 , s t r e a m 4 ;
c u d a S t r e a m C r e a t e (& s t r e a m 1 ) ;
...
c u d a M a l l o c (&data_dev1 , s i z e ) ;
c u d a M a l l o c H o s t (& data_host1 , s i z e ) ;
...
cudaMemcpyAsync ( data_dev1 , data_host1 , s i z e ,
cudaMemcpyHostToDevice , s t r e a m 1 ) ;
k e r n e l 2 <<< g r i d , b l o c k , 0 , s t r e a m 2 >>> ( . . . ,
data_dev2 , . . . ) ;
k e r n e l 3 <<< g r i d , b l o c k , 0 , s t r e a m 3 >>> ( . . . ,
data_dev3 , . . . ) ;
cudaMemcpyAsync ( data_host4 , data_dev4 , s i z e ,
cudaMemcpyDeviceToHost , s t r e a m 4 ) ;
...
73 / 75
Premiers pas Les blocks Threads Optimisations
K1a
K1b
K2a
K2b
74 / 75
Premiers pas Les blocks Threads Optimisations
temps
K1a K1a
K1b K1b K2a
K2a K2b
K2b
74 / 75
Premiers pas Les blocks Threads Optimisations
Ordre d’émission
temps
74 / 75
Premiers pas Les blocks Threads Optimisations
Ordre d’émission
K2a
temps
temps
K1a K1a K1a K1a
K1b K1b K2a K2a K1b K2b
K2a K2b K1b
K2b K2b
74 / 75
Premiers pas Les blocks Threads Optimisations
Ordre d’émission
Ordre d’émission
K2a K1b
temps
temps
temps
K1a K1a K1a K1a K1a K1a
K1b K1b K2a K2a K1b K2a K2a K2b
K2b
K2a K2b K1b K2b
K2b K2b K1b
74 / 75
Premiers pas Les blocks Threads Optimisations
• MPI + CUDA :
http://on-demand.gputechconf.com/gtc/2014/
presentations/S4236-multi-gpu-programming-mpi.pdf
• Mémoire unifiée CPU + GPU :
http://www.drdobbs.com/parallel/
unified-memory-in-cuda-6-a-brief-overvie/
240169095?pgno=1
75 / 75