CUDA 4 et Architecture Fermi GPUDirect2.0 et UVA



Documents pareils
Introduction à CUDA.

. Plan du cours. . Architecture: Fermi ( ), Kepler (12-?)

Calcul multi GPU et optimisation combinatoire

Introduction au calcul parallèle avec OpenCL

Introduction à la programmation des GPUs

Introduction au langage C

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Segmentation d'images à l'aide d'agents sociaux : applications GPU

1.6- Génération de nombres aléatoires

Derrière toi Une machine virtuelle!

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Brefs rappels sur la pile et le tas (Stack. / Heap) et les pointeurs

Une bibliothèque de templates pour CUDA

Windows Server Chapitre 1: Découvrir Windows Server 2008

Génération de code binaire pour application multimedia : une approche au vol

Introduction à la Programmation Parallèle: MPI

Programmation C. Apprendre à développer des programmes simples dans le langage C

Cours d initiation à la programmation en C++ Johann Cuenin

Cours de C++ François Laroussinie. 2 novembre Dept. d Informatique, ENS de Cachan

OS Réseaux et Programmation Système - C5

Veeam Backup and Replication

Info0804. Cours 6. Optimisation combinatoire : Applications et compléments

Processus! programme. DIMA, Systèmes Centralisés (Ph. Mauran) " Processus = suite d'actions = suite d'états obtenus = trace

Conventions d écriture et outils de mise au point

Guide de prise en main Symantec Protection Center 2.1

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

I. Introduction aux fonctions : les fonctions standards

Module.NET 3 Les Assemblys.NET

Architecture des ordinateurs

Exécutif temps réel Pierre-Yves Duval (cppm)

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Argument-fetching dataflow machine de G.R. Gao et J.B. Dennis (McGill, 1988) = machine dataflow sans flux de données

Exercices INF5171 : série #3 (Automne 2012)

Une introduction à Java

Bases de programmation. Cours 5. Structurer les données

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique

Généralités sur le Langage Java et éléments syntaxiques.

Recherche dans un tableau

Programmation en C/C++

Cette application développée en C# va récupérer un certain nombre d informations en ligne fournies par la ville de Paris :

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

Analyse de sécurité de logiciels système par typage statique

Master première année. Mention : Statistiques et Traitement de Données «STD» Rapport de stage

IFT Systèmes d exploitation - TP n 1-20%

Programmation C++ (débutant)/instructions for, while et do...while

Contrôle Non Destructif : Implantation d'algorithmes sur GPU et multi-coeurs. Gilles Rougeron CEA/LIST Département Imagerie Simulation et Contrôle

Claude Delannoy. 3 e édition C++

Virtual Box Mettez un PC dans votre... PC

Programmation stochastique

Java Licence Professionnelle CISII,

Compression de Données - Algorithme de Huffman Document de Conception

INFO-F-105 Language de programmation I Séance VI

Programme Compte bancaire (code)

27/11/12 Nature. SDK Python et Java pour le développement de services ACCORD Module(s)

3615 SELFIE. HOW-TO / GUIDE D'UTILISATION

Cours d Algorithmique et de Langage C v 3.0

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Remote Method Invocation Les classes implémentant Serializable

Le langage C. Séance n 4

Mysql. Les requêtes préparées Prepared statements

Comment utiliser Vijeo Designer avec les produits de machine virtuelle

REMBO Version 2.0. Mathrice 2004 DESCRIPTION MISE EN OEUVRE CONCLUSION.

INFO-F-404 : Techniques avancées de systèmes d exploitation

Acronis Backup & Recovery 10 Advanced Server Virtual Edition. Guide de démarrage rapide

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

as Architecture des Systèmes d Information

Instructions pour mettre à jour un HFFv2 v1.x.yy v2.0.00

Présentation du modèle OSI(Open Systems Interconnection)

Classe ClInfoCGI. Fonctions membres principales. Gestion des erreurs

Structure d un programme et Compilation Notions de classe et d objet Syntaxe

Corrigé des exercices sur les références

Le prototype de la fonction main()

COMPARAISONDESLANGAGESC, C++, JAVA ET

Warren PAULUS Robin GODEFROID. C++ - Interface Graphique avec Visual Studio 2010

Optimisations des SGBDR. Étude de cas : MySQL

ESXi: Occupation RAM avec VM_Windows et VM_Linux. R. Babel, A. Ouadahi April 10, 2011

A -Systèmes de fichiers 1 - FAT vs NTFS

Gestion de la mémoire

4. Outils pour la synchronisation F. Boyer, Laboratoire Lig


Introduction à l héritage en C++

Structure fonctionnelle d un SGBD

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013

Le Ro le Hyper V Premie re Partie Configuration et Prise en main du gestionnaire Hyper-V

Langage C. Patrick Corde. 22 juin Patrick Corde ( Patrick.Corde@idris.fr ) Langage C 22 juin / 289

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Informatique III: Programmation en C++

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Modernisation, développement d applications et DB2 sous IBM i Technologies, outils et nouveautés Volubis.fr

DNS Server RPC Interface buffer overflow. Céline COLLUMEAU Nicolas BODIN

JADE : Java Agent DEvelopment framework. Laboratoire IBISC & Départ. GEII Université & IUT d Evry nadia.abchiche@ibisc.univ-evry.

Le serveur HTTPd WASD. Jean-François Piéronne

Jean-Philippe Paquette

Principe. Technologies utilisées. 1. Linux et LVM. Les snapshots (instantannés) sous Linux et FreeBSD. Présentation de LVM. Organisation de LVM

Introduction à C++ et à wxwidgets

Les processus légers : threads. Système L3, /31

WORKSHOP OBIEE 11g (version ) PRE-REQUIS:

Exercices sur SQL server 2000

Transcription:

CUDA 4 et Architecture Fermi GPUDirect2.0 et UVA Pierre Kunzli - hepia 5 septembre 2012 1 Introduction La version 4.0 de CUDA introduit avec l'architecture Fermi deux nouveautés concernant la gestion de la mémoire sur les devices. GPUDirect2.0 premièrement, qui permet d'échanger des données entre deux devices (fonctionnalité appelée peer-to-peer g.1). Et l'unied Virtual Addressing (g.2), qui simplie la programmation, du fait qu'un espace d'adressage unié est utilisé pour le host et les devices. De plus, la gestion de plusieurs devices est maintenant facilitée. Figure 1 Echange peer-to-peer entre deux devices 2 Pré-requis An de proter de ces fonctionnalités, il faut que le runtime CUDA installé soit en version >= 4.0 et les devices doivent avoir un CUDA Capability Major version >= 2 (architecture Fermi). An de pouvoir utiliser l'uva, l'application doit être compilée en 64 bits et le mode TCC (Tesla Compute Cluster) doit être activé si l'application fonctionne sur Windows 7/Vista (voir [1] section 3.6). 1

Figure 2 Unied Virtual Addressing 3 Mise en oeuvre 3.1 Contrôle des pré-requis Le code suivant permet de s'assurer que le programme s'exécute sur une machine supportant les fonctionnalités UVA et P2P : #define checkcudaerrors(err) checkcudaerrors (err, FILE, LINE ) inline void checkcudaerrors( cudaerror err, const char *file, const int line ) if( cudasuccess!= err) fprintf(stderr, "%s(%i) : CUDA Runtime API error %d: %s.\n", file, line, (int)err, cudageterrorstring( err ) ); inline bool IsAppBuiltAs64() #if defined( x86_64) defined(amd64) defined(_m_amd64) return 1; #else return 0; #endif inline bool IsCuda4() #if CUDART_VERSION >= 4000 return 1; #else return 0; #endif // controler que l'application est compilee en 64 bits if (!IsAppBuiltAs64()) cout<<"uva is only supported on 64-bit OSs and the application must be built as a 64- bit target"<<endl; // controler que cuda4 est disponible if (!IsCuda4()) 2

cout<<"uva needs cuda4 runtime"<<endl; // controler que chaque device supporte p2p et uva int numgpus; checkcudaerrors(cudagetdevicecount(&numgpus)); cudadeviceprop deviceprop; for(int i=0;i<numgpus;i++) checkcudaerrors(cudagetdeviceproperties(&deviceprop, i)); if(!(deviceprop.major>=2)) cout<<"gpu 2.0 (fermi) requied to use UVA/P2P"<<endl; 3.2 UVA Lorsque les conditions sont remplies, l'uva est automatiquement activé. Un seul espace d'adressage est alors utilisé pour le host et pour les devices de compute capability >= 2. Cet espace d'adressage est utilisé pour toute allocation faite sur les devices, mais uniquement pour les allocations faites avec cudahostalloc() ou cudamallochost() pour la mémoire du host. La première conséquence est que lors des cudamemcpy() sur ou depuis n'importe quel device qui utilise l'uva, on peut utiliser la valeur cudamemcpydefault pour spécier le type de copie. Le runtime étant capable de déterminer la source et la destination à partir des pointeurs. Ensuite, lorsque l'uva est utilisé, les pointeurs alloués avec cudahostalloc() ou cudamallochost()peuvent être directement déréférencés depuis les kernels, et donc, la mémoire du host directement accédée. Il faut cependant utiliser cette fonctionalité avec précaution du fait des forts temps de latence qu'elle implique. global void kernel(int* ptr) int i = ptr[0]; ptr[1] = 3; // allouer de la memoire sur le host int* hostptr1; checkcudaerrors(cudamallochost(&hostptr1,10*sizeof(int))); int* hostptr2 = (int*)malloc(10*sizeof(int)); // la memoire allouee avec cudamallochost est directement accessible depuis le kernel kernel<<<dimgrid, dimblock>>>(hostptr1); int* deviceptr; checkcudaerrors(cudamalloc((void**)&deviceptr,10*sizeof(int))); // copier des donnees du host vers le device, inutile de specifier le type de copie // le runtime determine automatiquement la source et la destination checkcudaerrors(cudamemcpy(hostptr2,deviceptr,10*sizeof(int),cudamemcpydefault)); 3

3.3 Peer-to-Peer GPUDirect 2 permet des échanges directs entre deux devices, appelés copies peer-to-peer. Il est possible d'utiliser cette fonctionnalité sans que l'uva soit actif, cependant, cela implique que les données transitent par le host et cette façon de faire ne permet donc pas de gain de performance. Dans ce cas, il faut utiliser les fonctions de copies standard avec le suxe Peer. Par exemple, cudamemcpypeer(), qui prends en paramètre le pointeur destination, le device destination, le pointeur source, le device source, et enn la taille des données à copier. int* device0ptr; checkcudaerrors(cudamalloc((void**)&device0ptr,10*sizeof(int))); // allouer de la memoire sur le device 1 checkcudaerrors(cudasetdevice(1)); int* device1ptr; checkcudaerrors(cudamalloc((void**)&device1ptr,10*sizeof(int))); // copier les donnees du device 0 sur le device 1 checkcudaerrors(cudamemcpypeer(device1ptr, 1, device0ptr, 0, 10*sizeof(int))); 3.4 Peer-to-Peer avec UVA Lorsque l'uva est activé, un device peut accéder directement à la mémoire d'un autre device sans passer par le host. L'accès P2P doit être activé entre chaque device concerné. Une fois le P2P activé, la mise en oeuvre est très simple puisque qu'il sut d'utiliser la fonction cudamemcpy(), le runtime étant capable de déterminer la source et la destination à partir des pointeurs grâce à UVA. Ce type de copie ne transitant pas par le host, les performances sont bien meilleures que sans UVA. int* device0ptr; checkcudaerrors(cudamalloc((void**)&device0ptr,10*sizeof(int))); // activer acces p2p depuis device 0 sur device 1 checkcudaerrors(cudadeviceenablepeeraccess(1, 0)); // allouer de la memoire sur le device 1 checkcudaerrors(cudasetdevice(1)); int* device1ptr; checkcudaerrors(cudamalloc((void**)&device1ptr,10*sizeof(int))); // activer acces p2p depuis device 1 sur device 0 checkcudaerrors(cudadeviceenablepeeraccess(0, 0)); checkcudaerrors(cudamemcpy(device1ptr,device0ptr,10*sizeof(int),cudamemcpydefault)); De plus, lorsque l'uva est activé et que l'accès P2P est activé, un kernel peut accéder directement à la mémoire d'un autre device. Là encore, il faut faire attention aux temps de latence lors de tels accès. global void kernel(int* ptr) int i = ptr[0]; ptr[1] = 3; int* device0ptr; checkcudaerrors(cudamalloc((void**)&device0ptr,10*sizeof(int))); // activer acces p2p depuis device 0 sur device 1 4

checkcudaerrors(cudadeviceenablepeeraccess(1, 0)); // allouer de la memoire sur le device 1 checkcudaerrors(cudasetdevice(1)); int* device1ptr; checkcudaerrors(cudamalloc((void**)&device1ptr,10*sizeof(int))); // activer acces p2p depuis device 1 sur device 0 checkcudaerrors(cudadeviceenablepeeraccess(0, 0)); // le kernel va s'executer sur le device 1 et acceder directement a la memoire du device 2 kernel<<<dimgrid, dimblock>>>(device0ptr); 4 Utilisation de plusieurs devices Comme on peut le voir dans les exemples, un seul processus sur le CPU est capable de prendre le contôle de plusieurs devices. En eet, il est maintenant possible de lancer des exécutions asynchrones à partir d'un thread puis de prendre le contrôle d'un autre device an de lancer d'autres exécutions. Cela facilite dans certains cas la gestions de la programmation multi-devices puisqu'il n'est plus nécessaire d'utiliser plusieurs threads ou processus CPU. Dans l'autre sens, il est également maintenant possible pour plusieurs threads ou processus de prendre le contrôle d'un même device, les kernels sont alors exécutés en concurrence sur le device concerné. Cela permet de faire fonctionner plusieurs programmes CUDA simultanément ou de simplier la conception d'un programme dans certains cas. 5 Débits Des tests de débit ont été eectués. Les tests ont été eectués sur la machine cogito d'hepia, équipée de 4 GPUs Nvidia M2090 connectés à des ports PCIexpress 2.0 16x, permettant en théorie d'obtenir un débit de l'ordre de 8GO par seconde. An de mesurer le débit, on fait transiter 1GO de données : entre deux GPUs en p2p, entre deux GPUs en passant par le host et du host vers un GPU. Les résultats obtenus sont les suivants : type temps débit GPU -> GPU p2p 150 ms 6.7 GO/s GPU -> GPU via host 929 ms 1.07 GO/s HOST -> GPU 862 ms 1.16 GO/s On remarque alors que si les transferts qui transitent via la mémoire du host sont passablement lents par rapport au débit théorique, les transferts directs entre GPUs sont quant à eux beaucoup plus proches du maximum théorique. Références [1] NVidia. Cuda c programming guide 4.1 sections 3.2.6 et 3.2.7, 2012. http://developer.download.nvidia.com/compute/devzone/docs/html/c/doc/cuda_c_ Programming_Guide.pdf. [2] Tim C. Schroeder. Peer-to-peer & unied virtual addressing cuda webinar, 2011. http://developer.download.nvidia.com/cuda/training/cuda_webinars_gpudirect_uva. pdf. 5

A Exemple de code complet #include <cuda_runtime.h> #include <iostream> #include <stdlib.h> using namespace std; /* fonctions d'aide pour cuda */ #define getlastcudaerror(msg) getlastcudaerror (msg, FILE, LINE ) inline void getlastcudaerror( const char *errormessage, const char *file, const int line ) cudaerror_t err = cudagetlasterror(); if( cudasuccess!= err) fprintf(stderr, "%s(%i) : getlastcudaerror() CUDA error : %s : (%d) %s.\n", file, line, errormessage, (int)err, cudageterrorstring( err ) ); #define checkcudaerrors(err) checkcudaerrors (err, FILE, LINE ) inline void checkcudaerrors( cudaerror err, const char *file, const int line ) if( cudasuccess!= err) fprintf(stderr, "%s(%i) : CUDA Runtime API error %d: %s.\n", file, line, (int)err, cudageterrorstring( err ) ); inline bool IsAppBuiltAs64() #if defined( x86_64) defined(amd64) defined(_m_amd64) return 1; #else return 0; #endif inline bool IsCuda4() #if CUDART_VERSION >= 4000 return 1; #else return 0; #endif // nombre de threads par block #define NT 128 6

// kernel basique global void kernel(int *d2, int *d1, int *h1, int size) int mypos = blockidx.x*nt + threadidx.x; if(mypos<size) d2[mypos]=d1[mypos]; h1[size-1]=2; int main( int argc, char** argv) // controler que le systeme possede 2 GPU au moins int numgpus; checkcudaerrors(cudagetdevicecount(&numgpus)); if(numgpus<2) cout<<"this application needs at least 2 devices"<<endl; // controler que l'application est compilee en 64 bits if (!IsAppBuiltAs64()) cout<<"uva is only supported on 64-bit OSs and the application must be built as a 64-bit target"<<endl; // controler que cuda4 est disponible if (!IsCuda4()) cout<<"uva needs cuda4 runtime"<<endl; // controler que les deux premiers devices supporte p2p et uva cudadeviceprop deviceprop; for(int i=0;i<2;i++) checkcudaerrors(cudagetdeviceproperties(&deviceprop, i)); if(!(deviceprop.major>=2)) cout<<"gpu 2.0 (fermi) requied to use UVA/P2P"<<endl; int size = 200; // prendre le controle du device 0 // activer l'acces p2p du device 0 sur le device 1 checkcudaerrors(cudadeviceenablepeeraccess(1, 0)); int *device0ptr; checkcudaerrors(cudamalloc((void**)&device0ptr,size*sizeof(int))); // prendre le controle du device 1 checkcudaerrors(cudasetdevice(1)); // activer l'acces p2p du device 1 sur le device 0 checkcudaerrors(cudadeviceenablepeeraccess(0, 0)); // allouer de la memoire sur le device 1 int *device1ptr; checkcudaerrors(cudamalloc((void**)&device1ptr,size*sizeof(int))); 7

// allouer de la memoire sur le host accessible depuis les devices int *hostptr; checkcudaerrors(cudamallochost(&hostptr,size*sizeof(int))); hostptr[size-1]=0; // affiche 0 cout<<hostptr[size-1]<<endl; // effectuer une copie du device 0 sur le device 1 // (automatiquement p2p, pas besoin de specifier le type de copie) checkcudaerrors(cudamemcpy(device1ptr,device0ptr,size*sizeof(int),cudamemcpydefault)); dim3 dimgrid ((size + NT - 1)/NT,1); dim3 dimblock (NT,1); // executer le kernel sur le device 0 kernel<<<dimgrid, dimblock>>>(device1ptr, device0ptr, hostptr, size); getlastcudaerror("copy() execution failed.\n"); checkcudaerrors(cudathreadsynchronize()); // affiche 2 car la memoire du host a ete modifiee par le kernel cout<<hostptr[size-1]<<endl; 8