TP 2 : Programming with CUBLAS

Mineure CalHau-2

Stéphane Vialle, CentraleSupélec & LRI, Stéphane.Vialle@centralesupelec.fr  

Co-auteur du TP :  Laércio Lima Pilla, CNRS & LRI, pilla@lri.fr

Objectifs du TP :

Ce TP a pour objectif de pratiquer la programmation d'un GPU à travers une bibliothèque de type BLAS, au sein d'un noeud de calcul CPU+GPU : il consiste à implanter des appels CUBLAS de plus en plus efficaces.

Plate-forme de développement : 

Les machines utilisées seront celles des clusters Tx ou Cameron du DCE de CentraleSupélec :

L'environnement CUDA C et C++ est disponible sur chaque machine (et donc le compilateur "nvcc" et les drivers pour utiliser le GPU).

Vous utiliserez les comptes de TP "gpucs1_#i", où #i est une valeur entière entre 1 et 16.

Depuis votre poste de travail :

Ex: oarsub -p "cluster='Tx'" -l nodes=1,walltime=4:00:00 -I

Travail à effectuer :

Remarques préliminaires :
  • Le squelette de programme que vous utiliserez contient un code de produit de matrices denses en OpenMP et CUDA.
  • La partie OpenMP est complète, et est destinée à permettre de comparer les résultats numériques et les performances duCPU et du GPU
  • La partie CUDA est en partie développée, mais il vous reste à compléter le fichier gpu.cu :
    • Le squelette est compilable et contient une aide intégrée : exécutez 'make' puis './MatrixProduct -h'.
    • Pour valider votre premier code vous compilerez en Double Précision (le type "T_real" devient le type "double")  avec "-DDP" dans le Makefile, les résultats seront identiques sur CPU et sur GPU, mais les performances des GPU s'effondreront (car il s'agit de cartes GPU grand public non adaptées à la Double Précision).
    • Pour faire vos mesures de performances vous compilerez en Simple Précision (le type "T_real" devient le type "float") avec "#-DDP" dans le Makefile. La simple précision est adaptée aux capacités des GeForce GTX1080 et RTX2080, mais il se peut que vous observiez des différences entre les calculs sur CPU et sur GPU!!
    1 - Implantation d'un appel CUBLAS "gemm" suivi du lancement d'un kernel de transposition
    1. Récupérez et compilez le squelette de programme OpenMP+CUDA.
      • Squelette, ou bien allez le recopier sur votre compte de TP par la commande : cp ~vialle/tmp/MatrixProduct-CUBLAS-enonce.zip .
      • Compilez ce squelette et testez son fonctionnement sur CPU (exécutez la commande ./MatrixProduct -h pour voir les détails de fonctionnement de l'application).
      1. Implantez le pseudo-kernel K4 dans le fichier 'gpu.cu' pour calculer C = AxB :
        • utilisez la routine CUBLAS_GEMM(...) (voir main.h), il s'agit du renommage de cublasSgemm ou de cublasDgemm, selon que l'on compile en simple ou double précision (-DDP dans le Makefile),
        • utilisez la macro CHECK_CUBLAS_SUCCESS (voir gpu.h) pour lancer vos appels CUBLAS et tester leurs codes de retour,
        • et lancez une grille de blocs du kernel TransposeKernel_v1, associé à des blocs carrés de BLOCK_SIZE_XY_KT1 x BLOCK_SIZE_XY_KT1 threads, pous transposer le résultat de l'appel CUBLAS. Lancez une grille de blocs adaptée à toutes les tailles de matrices (SIZE x SIZE).
      • Testez votre implantation sur une matrice de 4096x4096 DOUBLE (option -DDP active dans le 'Makefile' et changement de SIZE dans le 'main.h'). Obtenez-vous les mêmes valeurs qu'avec les BLAS sur CPU : MatrixProduct -t CPU -cpu-k 1 -cpu-nt 4, sur Tx (et -cpu-nt 6 sur Cameron) ?
      1. Mesurez les performances du pseudo-kernel K4 obtenues sur une matrice de 4096x4096 FLOAT éléments (#-DDP dans le Makefile).
      • Récupérez le fichier Excel de saisi des résultats, et complétez-le au fur et à mesure du TP.
      • Comparez aux meilleures performances obtenues sur CPU multi-coeurs en OpenMP avec un kernel de même niveau (kernel 1 - BLAS sur CPU), 
      • MatrixProduct -t CPU -cpu-k 1 -cpu-nt 4  sur Tx
      • MatrixProduct -t CPU -cpu-k 1 -cpu-nt 6 sur Cameron
      • Calculez le speedup GPU vs best-config-CPU.
        2 - Implantation d'un appel CUBLAS "gemm" suivi d'un appel CUBLAS "geam"
        1. Créez le pseudo-kernel K5 dans le fichier 'gpu.cu' :
          • utilisez la routine CUBLAS_GEMM(...) : voir main.h
          • et utilisez la routine CUBLAS_GEAM(...) : voir main.h
        • Testez et validez votre implantation sur une matrice de 4096x4096 FLOAT.
        • Vérifiez que vous obtenez les mêmes valeurs qu'avec le pseudo-kernel K4.
        1. Mesurez les performances obtenues sur une matrice de 4096x4096 FLOAT.
        • Comparez-les aux performances obtenues avec le pseudo-kernel K4
        • Comparez-les aux performances de la meilleure configuration sur le CPU

        3 - Implantation d'un unique appel CUBLAS "gemm" permettant d'obtenir C = AxB
        1. Créez le pseudo-kernel K6 dans le fichier 'gpu.cu' :
          • utilisez la routine CUBLAS_GEMM(...) : voir main.h
          • pour qu'elle calcule C = AxB à elle seule
        • Testez et validez votre implantation sur une matrice de 4096x4096 FLOAT.
        • Vérifiez que vous obtenez les mêmes valeurs qu'avec le pseudo-kernel K5.
        1. Mesurez les performances obtenues sur une matrice de 4096x4096 FLOAT.
        • Comparez-les aux performances obtenues avec le pseudo-kernel K5
        • Comparez-les aux performances de la meilleure configuration sur le CPU

         4 - Améliorez la vitesse des transferts de données CPU-GPU
        1. Implantez des transferts à partir ou vers des données CPU "vérouillées en mémoire" (pinned).
          • Verrouillez en mémoire les matrices A, B et C sur le CPU (ne changez par leur allocation/déclaration).
          • Puis déverouillez-les après avoir fini les transferts et les calculs.
          • Testez les codes de retour de vos opérations CUDA, pour vérifier qu'elles retournent bien cudaSuccess
        • Vérifiez que vos transferts mémoires ne déclenchent pas de messages d'erreur.
        • Vérifiez que vous obtenez toujours les mêmes résultats (comparez-les à ceux d'un kernel CPU ou aux valeurs obtenues précédemment sur GPU).
        1. Mesurez les performances obtenues sur une matrice de 4096x4096 FLOAT.
        • Re-mesurez les performances obtenues avec les kernels 0, 1, 4, 5 et 6
        • Observez-vous des gains significatifs ?
        • Mettez-à-jour l'onglet "K4-7 CUBLAS" du fichier Excel
         
        5 - Utilisation des TensorCores
        1. Implantez le pseudo-kernel K7 dans le fichier 'gpu.cu' pour utilisez les TensorCores :
          • Utilisez la routine cublasGemmEx(...)
          • et précisez le type T_CUBLAS_real défini dans 'main.h'
          • et précisez l'algorithme CUBLAS_GEMM_DEFAULT_TENSOR_OP
        • Testez et validez votre implantation sur une matrice de 4096x4096 DOUBLE
        • Vérifiez que vous obtenez les mêmes valeurs qu'avec le pseudo-kernel K6.
        1. Mesurez les performances obtenues sur les TensorCores avec une matrice de 4096x4096 FLOAT.
        • Comparez-les performances obtenues maintenant avec le pseudo-kernel K6 à celles obtenues précédemment
        • Comparez-les aux performances de la meilleure configuration sur le CPU
        1. Mesurez les performances obtenues sur les TensorCores avec une matrice de 4096x4096 DOUBLE
          • Recompilez en double précision (-DDP dans le Makefile)
          • Obtenez-vous les mêmes résultats que le pseudo-kernel K6 ?
          • Comparez-les performances obtenues avec celles du pseudo-kernel K6
        1. Vous pouvez expérimenter d'autres algorithmes :
        • De CUBLAS_GEMM_ALGO0_TENSOR_OP   à   CUBLAS_GEMM_ALGO15_TENSOR_OP
        • Relevez les performances et l'écart relatif maximum avec le calcul en FLOAT sur CPU (affichés par le programme)
        • L'algorithme le plus performant affiche-t-il une erreur relative plus forte que les autres ?

        Document à rendre : 

        Vous rendrez un SEUL document par binôme : un fichier Word (.doc) ou PDF :
        • Taille maximale de vos rapports : <voir taille maximale annoncée en cours>
        • Date limite de remise de vos rapports : <voir date annoncée en cours>
        • Remise par e-mail à Stephane Vialle (Stephane.Vialle@centralesupelec.fr)