Je cours CUBLAS v2.0 sur différents flux sur un seul GPU (Tesla C2050) en subdivisant les matrices d'entrée (A [x/num_of_streams * y] B [x y] = C [x/num_of_streams * y]), mais en quelque sorte cela prend plus de temps quand j'utilise des flux CUDA. Voici l'extrait de code:Problèmes avec les flux CUDA
//plan is a struct containing the matrix dimensions and stream numbers
//parallel in nstreams - should be! MAX 16 streams could run concurrently
//Copy A - cudaMemCpyAsync
for(i = 0; i < nstreams; i++)
cudgemm_copyA_in_streams (&plan[i]);
//Copy B - cudaMemCpyAsync
for(i = 0; i < nstreams; i++)
cudgemm_copyB_in_streams (&plan[i]);
//Create handles - serial
for(i = 0; i < nstreams; i++)
handle[i] = create_handle();
//Run kernels - first doing a cublasSetStream(handle, plan->stream) before running cublasDgemm...
for(i = 0; i < nstreams; i++)
cudgemm_kernel_in_streams (&plan[i], handle[i], 1.0f, 1.0f);
//Destroy handles - serial
for(i = 0; i < nstreams; i++)
destroy_handle (handle[i]);
//Copy C - cudaMemCpyAsync
for(i = 0; i < nstreams; i++)
cudgemm_copyC_in_streams (&plan[i]);
//EDIT: Function body
//The other two copy functions are exactly the same as this
void cudgemm_copyA_in_streams(TGPUplan *plan)
{
cudasafe(cudaMemcpyAsync(plan->Ad_Data, plan->Ah_Data, (plan->Acols * plan->Arows * sizeof(double)), cudaMemcpyHostToDevice, plan->stream));
}
//Create handle
cublasHandle_t create_handle()
{
cublasHandle_t handle;
checkError(cublasCreate(&handle), "cublasCreate() error!\n");
return handle;
}
//Destroy handle
void destroy_handle (cublasHandle_t handle)
{
checkError(cublasDestroy(handle), "cublasDestroy() error!\n");
}
//Kernel
void cudgemm_kernel_in_streams(TGPUplan *plan, cublasHandle_t handle, const double alpha, const double beta)
{
cublasStatus_t ret;
cublasSetStream(handle, plan->stream);
ret = cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, plan->Arows, plan->Ccols, plan->Acols, &alpha, plan->Ad_Data, plan->Arows, plan->Bd_Data, plan->Brows, &beta, plan->Cd_Data, plan->Crows);
checkError(ret, "cublas Dgemm returned an error!\n");
}
Je suis rebondissant entre les flux et l'attribution du travail, en attendant d'obtenir un meilleur temps d'exécution, mais je remarque que plus le nombre de flux, le programme prend plus de temps que par rapport à la version qui n'utilise pas de flux. Où vais-je mal? poste de la Croix à des forums Nvidia - http://forums.nvidia.com/index.php?showtopic=209420
EDIT:
Je modifié mon programme comme suit:
//copy data
for(i = 0; i < nstreams; i++)
{
cudgemm_copyA_in_streams (&plan[i]);
cudgemm_copyB_in_streams (&plan[i]);
}
//Run kernel and copy back
for(i = 0; i < nstreams; i++)
{
cudgemm_kernel_in_streams (&plan[i], handle[i], 1.0f, 1.0f);
cudgemm_copyC_in_streams (&plan[i]);
}
Quand je profil mon programme pour une commande de matrice de 6144, je reçois les informations suivantes:
Kernel time = 42.75 % of total GPU time
Memory copy time = 28.9 % of total GPU time
Kernel taking maximum time = fermiDgemm_v2_kernel_val (42.8% of total GPU time)
Memory copy taking maximum time = memcpyHtoDasync (21.7% of total GPU time)
Total overlap time in GPU = 65268.3 micro sec. (3.6% of total GPU time)
Quand je chronomètre la boucle ci-dessus, j'obtiens un temps de 0,000284s, vs 1,703289s pour la version qui n'utilise pas de flux (dans cette version aussi, je chronomètre les deux copies séquentielles, l'invocation du noyau et le memCpy restant). Je pense que puisque je n'utilise pas de constructions de synchronisation, il se peut que j'imprime le temps avant que le calcul ne finisse réellement (j'ai du mal à croire qu'il y a une amélioration de 100%).
Il y a trop d'abstraction dans ce code pour dire quelque chose sur pourquoi, mais je devinerais * que ce sont les copies de la mémoire. Votre appareil dispose de 2 moteurs DMA, il peut chevaucher l'exécution du noyau avec des transferts de mémoire asynchrones sur au plus 2 flux, ou effectuer un seul transfert bi-directonal. Mettre en file d'attente aveuglément 16 transferts n'est pas une recette pour la performance. Pouvez-vous poster le code d'une de vos méthodes de copie? – talonmies
Je ne suis pas allé jusqu'à 16 flux, mais je teste avec des flux de 2,4,8. Merci de me rappeler le nombre de moteurs ... mais la troisième copie entre en vigueur après l'exécution du noyau, c'est-à-dire après la fin des deux premières copies, donc les moteurs DMA devraient être libres quand je copie C? – Sayan