Múltiples GPU (y otras chauchas) Clase 16, 21/11/2013 http://fisica.cab.cnea.gov.ar/gpgpu/index.php/en/icnpg/clases Carlos Bederián bc@famaf.unc.edu.ar IFEG-CONICET, FaMAF-UNC
Motivación No desperdiciar recursos Placas con múltiples GPU (Tesla K10, GTX 590/690) Encarar problemas más grandes En tiempo de ejecución En tamaño del sistema
Motivación (cont.) Utilización efectiva de clusters heterogéneos Hoy: Uso de aceleradores para mejor relación FLOPS/W Una corrida de LINPACK en Sequoia (BlueGene/Q, 16,7 PFLOPS, 7,9MW) toma el equivalente de 100 barriles de petróleo! En Green 500: Tesla K20X: Hasta 3.2 GFLOPS/W Xeon Phi: Hasta 2.5 GFLOPS/W POWER: Hasta 2.3 GFLOPS/W
Y mañana? Top500 Junio 2013: Xeon Phi: 2,2% de los sistemas, 18,8% del poder de cómputo Tesla: 7,8% de los sistemas, 14,4% del poder de cómputo Top500 Noviembre 2013: Xeon Phi: 2,4% de los sistemas, 18,1% del poder de cómputo Tesla: 7.4% de los sistemas, 16,2% del poder de cómputo
La competencia Tesla K40 Cores 15 SMX 61 Ancho 6 warps 192 FP32, 64 FP64 Xeon Phi 7120X SMT 64 warps 4 threads 1 core P54C 1 unidad de vectores de 512 bits 16 FP32, 8 FP64 Frecuencia 745 875 MHz 1238 1333 MHz FLOPS 4.3 TFLOPS FP32 1.4 TFLOPS FP64 2.4 TFLOPS FP32 1.2 TFLOPS FP64 Memoria 384-bit GDDR5, 6GHz, 12GB 512-bit GDDR5, 5.5GHz, 16GB Bandwidth 288 GBps 354 GBps TDP 235W 300W Proceso TSMC HP 28nm Intel Tri-gate 22nm
Y mañana? (cont.) NVIDIA Maxwell (2014) TSMC 20nm Unified Virtual Memory CUDA 6: cudamallocmanaged en software Volta (2016?) Stacked DRAM, TSV, 1TBps Denver (2015?) CPU ARM de 64 bits + GPU
Y mañana? (cont.) Intel Knights Landing (2015?) Nueva arquitectura desde cero AVX3 Intel 14nm JEDEC HBM + DDR Bootea!
Y mañana? (cont.) AMD Kaveri (Febrero 2014) 2 módulos Steamroller (Bulldozer v3) GPU GCN 1.1 Heterogeneous System Architecture (HSA) GlobalFoundries 28nm
Formas de usar múltiples GPU Un proceso, múltiples GPU Sólo funciona en un nodo División de las GPU entre hilos Múltiples procesos Pasaje de mensajes entre procesos Comunicación intra-nodo o inter-nodo
Contextos Hay que crear un contexto CPU-GPU antes de hacer cualquier cosa en una GPU OpenCL: Explícito CUDA: La primer operación que cambia el estado del device actual crea un contexto de manera transparente Límite de contextos por GPU determinados por el administrador usando nvidia-smi Para dejar de usar un device, destruímos su contexto en el proceso: cudadevicereset()
Devices Ver cantidad de devices presentes: cudagetdevicecount (int* count) Ver características de un device particular: cudagetdeviceproperties(cudadeviceprop* p, int device) Cambiar de device: cudasetdevice (int device)
Uso Un proceso, un hilo: 1. Cambiar de device 2. Encolar operaciones 3. Repetir desde 1 hasta usar todos los devices 4. Sincronizar Un proceso, muchos hilos: Cada hilo toma un device
Comunicación entre devices Device Host Otro device Funciona en todos lados Overhead innecesario cudasetdevice(0); cudamemcpy*(h, d0, sz, cudamemcpydevicetohost); cudasetdevice(1); cudamemcpy*(d1, h, sz, cudamemcpyhosttodevice); Atajo: cudamemcpy*peer*(d1, 1, d0, 0, sz);
Pero... Llevar rastro de todo esto es engorroso El driver ya sabe dónde queda cada cosa! Si sólo tuviera suficientes direcciones...
Unified Virtual Addressing
Unified Virtual Addressing Requiere: CUDA 4.0 Fermi Sistema de operativo y aplicación de 64 bits En una aplicación de 64 bits hay espacio de direcciones de sobra UVA: El driver mapea toda la memoria de las GPU al mismo espacio de direcciones del proceso y lleva rastro de a quién le pertenece qué cosa.
Memcpy con UVA cudamemcpy*(..., cudamemcpydefault) Copia de cualquier lado a cualquier lado usando UVA (H2H, H2D, D2H, D2D, P2P*)
Acceso directo entre GPU Pasar por el host es lento e innecesario Device Otro device (GPUDirect 2) Requiere UVA Comunicación directa por PCI Express Si el I/O hub lo permite
GPUDirect 2
Acceso directo entre GPU cudadeviceenablepeeraccess (int peerdevice, 0) Permite que la GPU activa acceda a la memoria de otra GPU vía PCIe Podemos llamar un kernel con un puntero de otra GPU Datos cacheados en L2 de la GPU destino Coherencia? OJO: Esto es unidireccional
Memcpy directo entre GPU 1. Activar peer access 2. cudamemcpy(dst, src, sz, cudamemcpydefault);
Sincronización entre múltiples GPU No hay muchas opciones Sincronizar desde el host con cudadevicesynchronize en todas las GPU Sincronización automática con cudastreamwaitevent
Comunicación en clusters MPI Lingua franca del HPC Implementaciones optimizadas Participación de los fabricantes HPL es una aplicación MPI Single Program, Multiple Data (SPMD) Todos los procesos corren el mismo código Los procesos se diferencian por su índice (rank) de proceso Funciones de sincronización y comunicación La configuración de la cantidad y distribución de procesos se hace al lanzar el programa
GPGPU más allá de un nodo Necesidad de comunicar datos por la red GPU Host code Send bufer Red Recv bufer Host memory GPU (!!!) Las redes lentas limitan la escalabilidad Ethernet 10GbE, 40GbE Infiniband DDR (16Gbps), QDR (32Gbps), FDR (41Gbps), FDR14 (54Gbps) Menos que PCI Express, que ya era cuello de botella
Quitando copias GPUDirect v1 (2010) Colaboración entre NVIDIA y fabricantes de Infiniband
Sigue siendo lento GPUDirect RDMA (~2013) Transferencia directa entre GPU y el adaptador IB
Cómo lo uso? Hablando con el módulo de kernel de NVIDIA para configurar las transferencias desde otro módulo de kernel patcheado para que las soporte
Que otro se preocupe Las implementaciones CUDA-aware de MPI lo hacen Con código aportado por NVIDIA y Mellanox Esas implementaciones MPI detectan automáticamente dónde vive cada bufer y actúan en consecuencia
Entonces... 1. Pedirle al admin que compile e instale una de esas implementaciones: MVAPICH-2 (GPUDirect v1, v2 y RDMA en alpha) OpenMPI (GPUDirect v1 y v2) 2. Escribir código MPI que envía desde host o device en un proceso a host o device en otro proceso 3.??? MPI se encarga de los detalles 4. Profit
Bibliografía T. Schroeder, Peer-to-peer and Unified Virtual Addressing, GTC Express 2011 NVIDIA, NVIDIA GPUDirect