¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Cómo escribir un kernel de GPU

Después de esta lección: Puedo escribir un kernel para un trabajo sencillo y simular su lanzamiento en Python.

Lección de 60 min2 comandosLaboratorio de computación paralela: cómo piensa una GPU, sin GPU, en JupyterLab

Rebajar cinco precios a la vez

Un kernel es la función pequeña que ejecuta cada hilo de una GPU, cada uno sobre su propio elemento. Escribir un kernel es escribir el trabajo de un solo hilo y dejar que el lanzamiento lo repita miles de veces.

Una tienda quiere rebajar un 10 % todos sus precios. El kernel rebaja un precio, y la rejilla se encarga del resto. Aquí no hay GPU: el lanzamiento se simula en Python.

Al final de esta lección

Nota

Puedo escribir un kernel para un trabajo sencillo y simular su lanzamiento en Python.

Palabras clave

PalabraQué significa
Kernella función que ejecuta cada hilo sobre su elemento
Lanzamientola orden que crea la rejilla y ejecuta el kernel en cada hilo
Guardala comprobación que deja sin trabajar a los hilos ociosos
Entradael array del que el kernel lee
Salidael array en el que el kernel escribe

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un kernel trabaja para un solo hilo

El kernel no tiene un bucle sobre todos los datos. Cuenta lo que hace un hilo: calcula su índice global, lee su elemento y escribe su resultado.

Si hay 5 elementos, habrá 5 hilos útiles ejecutando ese mismo kernel. El bucle lo pone la rejilla, no el programador.

Un kernel sigue siempre tres pasos

Primero, calcular el índice global con bloque, tamaño y hilo. Segundo, comprobar que el índice cae dentro de los datos: es la guarda, y protege a los hilos ociosos. Tercero, leer de la entrada y escribir en la salida, solo en la posición propia.

Si un hilo escribe en la posición de otro, los resultados dependen del orden y dejan de ser fiables.

Un kernel de descuento y su lanzamiento

Código: python
# Precios en céntimos. Un kernel que aplica un 10 % de descuento a UN elemento.
precios = [1200, 3000, 800, 2500, 990]
rebajados = [0] * len(precios)
tam_bloque = 2


def kernel_descuento(bloque, hilo):
    i = bloque * tam_bloque + hilo
    if i < len(precios):
        rebajados[i] = precios[i] * 90 // 100


bloques = (len(precios) + tam_bloque - 1) // tam_bloque
for bloque in range(bloques):
    for hilo in range(tam_bloque):
        kernel_descuento(bloque, hilo)
print("Rebajados:", rebajados)
# Cambia el 90 por 80 y vuelve a ejecutar.

Ejemplo: cinco precios con bloques de 2 hilos

BloqueHiloÍndicePrecioResultado
00012001080
01130002700
102800720
11325002250
204990891
215no hayocioso, no escribe

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

El orden de los hilos no importa

En una GPU real, los hilos corren a la vez y ninguno espera a otro. No se sabe qué hilo acaba primero.

Por eso un buen kernel no necesita lo que escribió otro hilo. Si el resultado cambia al ejecutar los hilos en otro orden, el kernel está mal escrito. La simulación permite comprobarlo.

Lanzar los bloques en orden inverso

Código: python
# El mismo lanzamiento, pero con los bloques en orden inverso.
precios = [1200, 3000, 800, 2500, 990]
rebajados = [0] * len(precios)
tam_bloque = 2


def kernel_descuento(bloque, hilo):
    i = bloque * tam_bloque + hilo
    if i < len(precios):
        rebajados[i] = precios[i] * 90 // 100


bloques = (len(precios) + tam_bloque - 1) // tam_bloque
for bloque in range(bloques - 1, -1, -1):
    for hilo in range(tam_bloque):
        kernel_descuento(bloque, hilo)
print("Rebajados:", rebajados)
# Sale lo mismo: ningún hilo necesita lo que hizo otro.

Qué enseña el script del laboratorio

El laboratorio trae steps/kernel.py, una simulación de un lanzamiento. Con el primer comando verás su texto: el kernel, la guarda y los dos bucles que simulan la rejilla.

Es un script en inglés, con los nombres en inglés. Solo se lee: lo que hace con sus datos lo viste en la lección anterior.

Leer el kernel del laboratorio

Comando
docker exec jupyter cat steps/kernel.py

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Contar los bloques al revés

Comando
docker exec jupyter python3 -c "print(list(range(2, -1, -1)))"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error muy común

Advertencia

Mucha gente escribe un bucle dentro del kernel para recorrer todos los datos. Entonces cada hilo repite el trabajo de todos. El kernel debe tratar un solo elemento, el que dice su índice global, y la rejilla pone tantos hilos como elementos.

Sobre este laboratorio y su código: Laboratorio de computación paralela: cómo piensa una GPU, sin GPU, en JupyterLab

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.