Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Introducción a la Computación Heterogénea Comunicación Directa Carlos Bederián, Nicolás Wolovick FaMAF, Universidad Nacional de Córdoba, Argentina 22 de Febrero de 2013 [email protected] Revisión 3890, 2013-02-22 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Velocidades Todo depende por donde pasan los datos. UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Copias host↔device Para transferir por el PCIe se necesita memoria que no swapee. Pinned Memory Para pedir/devolver page-locked memory en CUDA: cudaError_t cudaMallocHost(void **ptr, size_t size) Es una versión de cudaHostAlloc sin el tercer parámetro. cudaError_t cudaFreeHost (void* ptr) Usan los syscalls: #include <sys/mman.h> int mlock(void *addr, size_t length); int munlock(void *addr, size_t length); Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Pinned Memory – performance Evita una copia, deberı́a ser 2x más rápido. “Performance of GPUDirect with MPI”, NVIDIA, 2012. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Pinned Memory – limitaciones Es un recurso escaso: RLIMIT_MEMLOCK. $ ulimit -a | grep locked max locked memory (kbytes, -l) 64 El runtime de CUDA se las arregla para utilizar este poquitito. Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Copy engines Las placas de lı́nea Tesla permiten . . . rio66@mini:~$ LD_LIBRARY_PATH=/opt/cuda-4.2.9/lib64/ /opt/cudasdk/C/bin/linux/release/deviceQuery [deviceQuery] starting... /opt/cudasdk/C/bin/linux/release/deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Found 2 CUDA Capable device(s) Device 0: "Tesla C2070" CUDA Driver Version / Runtime Version CUDA Capability Major/Minor version number: Total amount of global memory: (14) Multiprocessors x ( 32) CUDA Cores/MP: GPU Clock rate: Memory Clock rate: ... Concurrent copy and execution: ... Support host page-locked memory mapping: Concurrent kernel execution: ... Device supports Unified Addressing (UVA): ... 5.0 / 4.2 2.0 6143 MBytes (6441598976 bytes) 448 CUDA Cores 1147 MHz (1.15 GHz) 1494 Mhz Yes with 2 copy engine(s) Yes Yes Yes Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA Superposición • 1 kernel engine. • 2 copias, una PCIe up engine y otra down engine. ¿Cómo puedo usar concurrentemente estas unidades? GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Superposición • 1 kernel engine. • 2 copias, una PCIe up engine y otra down engine. ¿Cómo puedo usar concurrentemente estas unidades? Streams • Cola de tareas. • Orden secuencial intra stream. • Absoluto no-determinismo extra streams (concurrencia!). Cuidado, necesita que la memoria host esté pinned. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Streams Default Stream cudaMemcpy(d_a, a, numBytes, cudaMemcpyHostToDevice); increment<<<1,N>>>(d_a); cudaMemcpy(a, d_a, numBytes, cudaMemcpyDeviceToHost); El truco fácil para hacer superposición. Overlap CPU-GPU cudaMemcpy(d_a, a, numBytes, cudaMemcpyHostToDevice); increment<<<1,N>>>(d_a); do_something_CPU(a); cudaMemcpy(a, d_a, numBytes, cudaMemcpyDeviceToHost); Cuidado, el default stream tiene propiedades especiales. • Es mútuamente exclusiva con las otras! “How to Overlap Data Transfers in CUDA C/C++”, k ∀, 2012. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Streams – ciclo de vida Creación cudaStream_t stream1; cudaError_t result; result = cudaStreamCreate(&stream1) Uso result = cudaMemcpyAsync(d_a, a, N, cudaMemcpyHostToDevice, stream1) increment<<<1,N,0,stream1>>>(d_a) Sincronización result = cudaStreamSynchronize(stream0) Destrucción result = cudaStreamDestroy(stream1) El tercer parámetro de <<< >>>, es la cantidad de memoria compartida dinámica. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA Paralelismo al final de la cola En Fermi: • Los streams no son completamente paralelos. • Serializados por una única cola de trabajos. • Pensar esto al usar las unidades: D2H, H2D, KER. GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin Streams – ejemplo cudaStream_t stream0, stream1; cudaStreamCreate(&stream0); cudaStreamCreate(&stream1); float *d_A0, *d_B0, *d_C0; // device memory para stream 0 float *d_A1, *d_B1, *d_C1; // device memory para stream 1 // cudaMalloc ... for (int i = 0; i < n; i += SegSize*2) { cudaMemcpyAsync(d_A0, h_A+i, SegSize*sizeof(float),.., stream0); cudaMemcpyAsync(d_B0, h_B+i, SegSize*sizeof(float),.., stream0); vecAdd<<<SegSize/256, 256, 0, stream0>>>(d_A0, d_B0, d_C0); cudaMemcpyAsync(d_C0, h_C+i, SegSize*sizeof(float),.., stream0); cudaMemcpyAsync(d_A1, cudaMemcpyAsync(d_B1, vecAdd<<<SegSize/256, cudaMemcpyAsync(d_C1, h_A+i+SegSize, SegSize*sizeof(float),.., stream1); h_B+i+SegSize, SegSize*sizeof(float),.., stream1); 256, 0, stream1>>>(d_A1, d_B1, d_C1); h_C+i+SegSize, SegSize*sizeof(float),.., stream1); } h2d0, h2d0, ker0, h2d0, h2d1 , h2d1, ker1, h2d1 Totalmente secuencial! “Heterogeneous Parallel Programming”, Wen-mei W. Hwu, 2012. Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin Streams – ejemplo – 2 Eliminar un poco de dependencias. for (int i = 0; i < n; i += SegSize*2) { cudaMemcpyAsync(d_A0, h_A+i, SegSize*sizeof(float),.., stream0); cudaMemcpyAsync(d_B0, h_B+i, SegSize*sizeof(float),.., stream0); cudaMemcpyAsync(d_A1, h_A+i+SegSize, SegSize*sizeof(float),.., stream1); cudaMemcpyAsync(d_B1, h_B+i+SegSize, SegSize*sizeof(float),.., stream1); vecAdd<<<SegSize/256, 256, 0, stream0>>>(d_A0, d_B0, d_C0); vecAdd<<<SegSize/256, 256, 0, stream1>>>(d_A1, d_B1, d_C1); cudaMemcpyAsync(d_C0, h_C+i, SegSize*sizeof(float),.., stream0); cudaMemcpyAsync(d_C1, h_C+i+SegSize, SegSize*sizeof(float),.., stream1); } Hay un poco de paralelismo. h2d0, h2d0, h2d1, h2d1, h2d0, h2d1 ker0, ker1, Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 HyperQ No hay restricciones en Kepler (full): K20, K20X, GTX Titan. HyperQ da 32 colas fı́sicas que trabajan en paralelo. Excelente para GPU-paralelizar (rápidamente) un programa MPI. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Work queues • Fermi puede tener activos hasta 16 grids, pero sı́ncronas en inicio y fin! (especulación nuestra) • El scheduler de Kepler (GK110) es mucho más complejo. Mayor grado de utilización de la pastilla. Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 UVA Tenemos Unified Virtual Addressing–UVA (CUDA≥4.0) • Punteros adornados para identificar CPU, GPU0, GPU1, . . . • Elimina el paso por la CPU: direct access, direct transfer . Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA Habilitando el acceso directo cudaDeviceEnablePeerAccess(1,0); GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin Direct transfer Para copiar entre placas directamente. // http://kylespafford.com/2012/02/29/gpu-direct. cudaSetDevice(0); cudaDeviceEnablePeerAccess(1,flags); //flags=0 cudaSetDevice(1); cudaDeviceEnablePeerAccess(0,flags); //flags=0 // Pedir memoria float *gpu0data, *gpu1data; cudaSetDevice(0); cudaMalloc(&gpu0data, nbytes); cudaSetDevice(1); cudaMalloc(&gpu1data, nbytes); // Hace la copia p2p cudaMemcpy(gpu0data, gpu1data, cudaMemcpyDefault) // Quitar el acceso cudaDeviceDisablePeerAccess(0); cudaDeviceDisablePeerAccess(1); Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin Direct access El kernel accede a la memoria de otra placa! __global__ void kernel(float *src, float *dst) { const int i = blockIdx.x * blockDim.x + threa dst[i] = src[i]; } void main() { ... cudaSetDevice(0); kernel<<<b,t>>> (gpu0data, cudaSetDevice(0); kernel<<<b,t>>> (gpu1data, cudaSetDevice(1); kernel<<<b,t>>> (gpu0data, cudaSetDevice(1); kernel<<<b,t>>> (gpu1data, Podemos hacer algo similar a OpenMP para GPUs. (de hecho pueden interoperar bien) gpu1data); gpu0data); gpu1data); gpu0data); Motivación Pinned Memory Superposición de Comunicación y Computación Topologı́a y localidad UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Topologı́a y localidad – 2 • Programas y job-scheduler, NUMA-aware. • Se puede usar hwloc para mirar la topologı́a. • lstopo. UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 GPUDirect2 Finalmente el pináculo de la comodida es GPUDirect2. Podemos pasar punteros de device a la implementación del MPI. if (rank == 0) { MPI_Send(d_a, MPI_Recv(d_b, } else { MPI_Recv(d_a, MPI_Send(d_b, } size, MPI_DOUBLE, 1-rank, 0, MPI_COMM_WORLD); size, MPI_DOUBLE, 1-rank, 0, MPI_COMM_WORLD, &status); size, MPI_DOUBLE, 1-rank, 0, MPI_COMM_WORLD, &status); size, MPI_DOUBLE, 1-rank, 0, MPI_COMM_WORLD); Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 GPUDirect2 – requisitos Requisitos • MVAPICH2-1.8, openmpi-1.7. • Para OpenMPI no hay collective (Reduce) ni one-sided communication (MPI2). • Tampoco permite copias intra-nodo. • MVAPICH2 es más sólida • 4.2≤CUDA. • Al menos arquitectura Fermi, lı́nea Tesla. Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Performance “Performance of GPUDirect with MPI”, NVIDIA, 2012. Fin Motivación Pinned Memory Superposición de Comunicación y Computación Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 Fin UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación Resumen • • • • • Velocidades de cada parte Pinned memory. Kernels y copias ası́ncronas (streams). UVA (movimiento intra-nodo). GPUDirect2 (movimiento extra-nodo). UVA GPUDirect2 Fin Motivación Pinned Memory Superposición de Comunicación y Computación UVA GPUDirect2 De ahora en adelante • Los esperamos del 7 al 10 de Mayo en WHPC13 (TBA). Córdoba, FaMAF–UNC. • Los esperamos a fines de ∼22 Julio en ECAR13 (TBA). HPCLatAM13, Mendoza, UNCuyo. • Los esperamos en HPCDay, 18 de Septiembre (TBA). 42JAIIO, Córdoba, FaMAF–UNC. En todos habrá grandes figuras del HPC. Fin