[Notes de démarrage CUDA] Présentation

1. Architecture CUDA

(1) Un GPU contient plusieurs processeurs multicœurs ;
(2) Un processeur multicœur contient plusieurs processeurs de threads
(3) Les processeurs de threads sont les unités de calcul les plus élémentaires et possèdent leur propre mémoire locale et leurs propres registres

2, fil, bloc, grille sens

(1) le thread correspond au processeur de thread sur le matériel ;
(2) la grille correspond à un GPU
(3) le bloc est composé de plusieurs processeurs de thread dans un processeur multicœur ;
(4) un processeur multicœur peut être divisé en Blocs multiples ;
(5) Lors de l'exécution d'une instruction, une chaîne d'unité d'exécution (warp) exécutera 32 threads en parallèle, donc lorsque nous divisons la taille de bloc, elle est généralement définie sur un multiple de 32

3. Programmation CUDA

(1) Allouez la mémoire vidéo sur le GPU et copiez les données du CPU dans la mémoire vidéo
(2) Utilisez la fonction du noyau pour terminer le calcul des données dans la mémoire vidéo du GPU
(3) Copiez les résultats du calcul dans le mémoire vidéo vers la mémoire CPU pour
calculer l'addition de la matrice : C = A + B, soit AB une matrice unidimensionnelle de longueur n

//La fonction du noyau (c'est-à-dire la fonction exécutée dans le GPU/déclarée avec __global__)
explique ici que
threadIdx indique le nombre de threads, et la plage est blocksize (blockDim) ;
blockIdx est le nombre de blocs, et la plage est taille de la grille;

__global__
void vecAddKernel(float* A_d, float* B_d, float* C_d, int n)
{
    
    
    int i = threadIdx.x + blockDim.x * blockIdx.x;  //计算线程ID
    if (i < n) C_d[i] = A_d[i] + B_d[i];  //筛选ID小于n的线程,即例如线程1计算C_d[1] = A_d[1] + B_d[1]
}



Comment appeler:

//划分GPU的block和Grid
    int threadPerBlock = 256;  //一个warp大小为32,一般设置为32的倍数
    int blockPerGrid = (n + threadPerBlock - 1)/threadPerBlock;  //根据划分的blocksize计算gridsize
	
	//调用核函数
    vecAddKernel <<< blockPerGrid, threadPerBlock >>> (da, db, dc, n);


Les blockPerGrid, threadPerBlock ci-dessus correspondent respectivement à Gridsize, blocksize (blockDim)

Lorsque la dimension est bidimensionnelle :


//核函数(传入显存ABC以及维度信息MNK)
__global__ void multiplicateMatrix(float *array_A, float *array_B, float *array_C, int M_p, int K_p, int N_p)
{
    
    
	//这里我们划分的lblock和grid是二维的,分别计算线程的二维索引(x方向和y方向的索引)
	int ix = threadIdx.x + blockDim.x*blockIdx.x;//row number,
	int iy = threadIdx.y + blockDim.y*blockIdx.y;//col number

	if (ix < N_p && iy < M_p)  //筛选线程,每个线程计算C中的一个元素,线程的xy索引与C的元素位置索引对应
	{
    
    
		float sum = 0;
		for (int k = 0; k < K_p; k++) //C中的某个元素为A中对应行和B中对应列向量的乘积和。
		{
    
    
			sum += array_A[iy*K_p + k] * array_B[k*N_p + ix];
		}
		array_C[iy*N_p + ix] = sum;
	}
}

//划分GPU的block和Grid
    int dimx = 2;
    int dimy = 2;
    dim3 block(dimx, dimy);
    dim3 grid((M + block.x - 1) / block.x, (N + block.y - 1) / block.y);
    
    //调用核函数
    multiplicateMatrix<<<grid,block>>> (d_A, d_B, d_C, M, K, N);

Question : pourquoi dim3 block(2, 2) n'a pas besoin d'être un multiple de 32

4. Stratégie d'accélération avancée CUDA

(1) Utiliser la mémoire partagée pour accélérer l'accès à la mémoire
Registre de thread : 1 cycle
Mémoire partagée de bloc : 5 cycles
Mémoire globale de grille : 500 cycles
Mémoire constante de grille : 5 cycles
(2) Utiliser le flux pour accélérer la lecture et l'écriture chronophages de gros lots de fichiers IO
Lorsque nous utilisons GPU Lors de l'exécution de calculs, nous pouvons activement ouvrir plusieurs flux, similaires au multi-threading d'un CPU. Nous pouvons attribuer un grand nombre de lectures et d'écritures de fichiers à plusieurs flux pour l'exécution, ou utiliser différents flux pour calculer différentes fonctions du noyau. Les multiples flux ouverts sont asynchrones, et les calculs côté flux et côté CPU sont également asynchrones. Nous devons donc faire attention à l'ajout d'opérations synchrones.
Il convient de noter que, limité par la bande passante du bus PCIe, lorsqu'un flux effectue des opérations de lecture et d'écriture, l'autre flux ne peut pas effectuer d'opérations de lecture et d'écriture en même temps, mais d'autres flux peuvent effectuer des tâches de calcul numérique. Ceci est quelque peu similaire au mécanisme de pipeline dans le CPU.
(3) Appelez l'API de la bibliothèque cuBLAS pour le calcul matriciel
cuBLAS est une implémentation BLAS qui permet aux utilisateurs d'utiliser les ressources de calcul du GPU de NVIDIA. Lors de l'utilisation de cuBLAS, l'application doit allouer l'espace mémoire GPU requis par la matrice ou le vecteur, charger les données, appeler la fonction cuBLAS requise, puis télécharger le résultat du calcul de l'espace mémoire GPU vers l'hôte. fonctions d'assistance pour écrire ou lire des données à partir du GPU.
Documentation officielle : https://docs.nvidia.com/cuda/cublas/index.html

Je suppose que tu aimes

Origine blog.csdn.net/qq_34106574/article/details/128330070
conseillé
Classement