English · Español
Lab 00 — Hola, CUDA: comprobación del toolchain¶
Objetivo: verificar que el toolchain de la GPU en la nube funciona de extremo a extremo. Escribir un kernel CUDA trivial (suma vectorial), compilar, lanzar, validar contra NumPy. La idea es aflorar problemas de tooling antes de que los labs más duros dependan de ellos.
Tiempo estimado: 1–2 horas (la mayor parte es entorno).
Prerrequisito: Fase 23 completa. Instancia de GPU en la nube disponible (alquilada según el ritual de
phase-23/lab/00-provision-cloud-gpu.md).cupyocuda-pythoninstalado.
Lo que produces¶
Un directorio experiments/24-hello-cuda/ que contiene:
vec_add.cu— el código fuente del kernel.run.py— lanzamiento + comprobación de corrección.manifest.json— ver plantilla más abajo.README.md— 1 párrafo: qué ruta de build (cupy.RawKernelocuda-python), versión del driver, escollos encontrados.
El kernel¶
__global__ void vec_add(const float* a, const float* b, float* c, int N) {
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < N) c[tid] = a[tid] + b[tid];
}
TODOs¶
Bloque A — elegir la ruta de build¶
- Decide:
cupy.RawKernel(la más simple; JIT de Python a PTX) ocuda-pythonconnvrtc(más flexible; más cercana a producción). Por defecto:cupy.RawKernel. - Instala la ruta elegida vía
uv pip install. Fija la versión enpyproject.toml. - Verifica que
nvidia-smimuestra tu GPU. Verifica quenvcc --versiono la ruta JIT funciona.
Bloque B — lanzar el kernel¶
-
run.py: reserva dos arrays host de tamaño \(N = 2^{20}\) connp.random.default_rng(42). - Copia al device (
cupy.asarrayo equivalente). - Lanza con
<<<grid, 256>>>dondegrid = (N + 255) // 256. - Copia el resultado de vuelta al host. Compara con
a + bde NumPy. Aserta igualdad exacta (la suma en float32 es lo bastante asociativa para una sola operación).
Bloque C — cronometrar (a la ligera)¶
- Cronometra el kernel con eventos CUDA (NO con
time.perf_counterde Python — el lanzamiento es asíncrono; estarías midiendo la submission, no la ejecución). - Imprime el ancho de banda alcanzado: \(3 \cdot N \cdot 4\) bytes / tiempo. Compara con el pico de HBM (
nvidia-smi -q | grep "Memory Bus"o la spec publicada de la GPU en la nube). - Esperado: la suma vectorial está limitada por ancho de banda; debería alcanzar un 60–80% del pico de HBM. Si está <20%, algo va mal (probablemente
cudaMemcpyestá dentro de la ventana de cronometraje).
Bloque D — manifest¶
{
"experiment": "24-hello-cuda",
"date": "YYYY-MM-DD",
"seed": 42,
"gpu": {"model": null, "compute_capability": null, "driver": null},
"build_path": "cupy.RawKernel",
"versions": {"python": "3.11.x", "cupy": null, "cuda_runtime": null},
"results": {
"N": 1048576,
"kernel_time_us": null,
"achieved_bandwidth_gbs": null,
"peak_bandwidth_gbs": null,
"fraction_of_peak": null,
"correctness": "passed | failed"
}
}
Restricciones¶
- No cronometres
cudaMemcpydentro del tiempo del kernel. Usa eventos CUDA que rodeen únicamente el lanzamiento del kernel. - No avances si la corrección falla. La suma vectorial es el kernel más simple posible; si está mal, el toolchain o la sintaxis del lanzamiento están rotos.
- No tunees. Esto es una comprobación de toolchain, no un benchmark de rendimiento. ≥20% del pico es de sobra.
Condiciones de parada¶
Hecho cuando:
run.pyse ejecuta de extremo a extremo en la GPU en la nube.- La aserción de corrección pasa.
- El ancho de banda alcanzado es ≥20% del pico (chequeo de cordura).
manifest.jsoncommiteado.- La facturación de la instancia en la nube registrada en tu log de costes de la fase 23.
Escollos¶
- Overhead de la primera llamada a
cupy.RawKernel. La compilación JIT ocurre en la primera llamada (~1–2 s). Cronometra la segunda llamada. O usacp.cuda.compile_with_cache(...). - Desajuste de versión de
cupycon el CUDA runtime instalado.cupy-cuda12xno es la misma wheel quecupy-cuda11x. Hazla coincidir con el driver. - Off-by-one en
grid.N // 256se pierde la cola cuandoN % 256 != 0. Usa(N + 255) // 256y la guardaif (tid < N). - Carrera en el puntero del device. Devolver el resultado antes de
cudaDeviceSynchronizeo de sincronizar el stream da datos rancios.cupysincroniza en.get(); verifícalo.
Cuándo consultar solutions/¶
Tras cumplir todas las condiciones de parada. La referencia recorre el montaje de cupy.RawKernel y un cronometraje conocido-bueno de la suma vectorial.
Siguiente lab: lab/01-naive-kernel.md.