English · Español
Lab 01 — Medir el ancho de banda de la RAM empíricamente¶
Objetivo: probar que el techo de ancho de banda de DRAM existe, golpeándolo.
Tiempo estimado: 60–90 minutos.
Prerrequisito: el lab 00 (perfil del ordenador) debe estar comprometido primero.
Qué produces¶
Un directorio experiments/01-memcpy-bandwidth/ que contenga:
bench.py— tu script de medición (lo escribe Borja; SIN espiar el código fuente de NumPy).results.json— throughput medido a múltiples tamaños de buffer.bandwidth.png— gráfica de tamaño de buffer vs throughput, eje x logarítmico.manifest.json—{seed, versions, config, hardware}segúnLYNX_CORTEX.md§5.README.md(2–3 párrafos) explicando qué mediste, cómo, y qué te dice la forma de la curva.
El kernel¶
El "kernel" de este lab es la operación memory-bound más simple posible: copiar un buffer de N valores fp32 a otro buffer de N valores fp32, y cronometrar.
Cada iteración lee 4N bytes y escribe 4N bytes — 8N bytes movidos en total. Throughput en GB/s = 8N / time_seconds / 10⁹.
Quieres medir esto para tamaños de buffer que abarquen L1 → L2 → L3 → DRAM, es decir, desde ~1 KiB hasta ~1 GiB. La gráfica debería mostrar tres mesetas correspondientes a las tres caches, y luego asentarse en el ancho de banda de DRAM.
TODOs¶
Bloque A — escribe el kernel¶
- Usa arrays de
numpy(np.empty(N, dtype=np.float32)). NO listas de Python. - Usa
np.copyto(dst, src)para la copia real. (No escribas tu propio bucle — los bucles de Python sobre fp32 miden overhead del intérprete, no memoria.) - Cronometra con
time.perf_counter_ns(). Repite cada medición las suficientes veces para que una repetición completa tarde ≥ 100 ms (para sofocar el ruido del temporizador); típicamente 5–500 repeticiones según N. - Una iteración de warm-up antes de cronometrar, para poblar caches y evitar page faults.
- Tamaños de buffer: al menos 12 puntos, log-espaciados desde 1 KiB a 1 GiB. Sugerido:
[1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576] KiB(es decir,2^(0..20) KiB). - En cada tamaño, registra:
bytes_per_iter, iters, elapsed_s, throughput_GBs. Guarda comoresults.json.
Bloque B — gráfica¶
- matplotlib. eje x: tamaño de buffer en KiB, escala log. eje y: throughput en GB/s, lineal.
- Anota los límites L1/L2/L3 en la gráfica, usando los tamaños de tu
profile.md. (Líneas verticales discontinuas + etiquetas.) - Anota el techo esperado de DRAM desde
profile.mdcomo una línea horizontal discontinua. - Guarda como
bandwidth.pngy referéncialo desdeREADME.md.
Bloque C — interpreta¶
Tres preguntas a responder en README.md:
- ¿A qué tamaño de buffer cae el throughput de forma abrupta? Compara con los tamaños de L1, L2, L3. Deberían alinearse.
- ¿Dónde se asienta la curva a la derecha? Ese es tu ancho de banda medido de DRAM. ¿Cómo de cerca está del
β_peakteórico del lab 00? - ¿Por qué el throughput a tamaños de buffer pequeños (en L1) es menor que el ancho de banda L1 de ~1 TB/s? (Pista: piensa qué overhead domina una medición de 1 KiB.)
Bloque D — manifest¶
Esquema de manifest.json:
{
"experiment": "01-memcpy-bandwidth",
"date": "YYYY-MM-DD",
"seed": 42,
"versions": {
"python": "3.11.x",
"numpy": "X.Y.Z",
"matplotlib": "X.Y.Z",
"linux_kernel": "..."
},
"hardware": {
"cpu_model": "Intel Core i5-8250U",
"cores_threads": "4/8",
"ram_gib": 62,
"cpu_governor_at_run": "performance"
},
"config": {
"sizes_KiB": [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144, 1048576],
"min_elapsed_ms_per_size": 100,
"warmup_iters": 1
},
"results_summary": {
"peak_GBs_measured": null,
"L1_plateau_GBs_measured": null,
"DRAM_floor_GBs_measured": null
}
}
Rellena results_summary después de graficar.
Restricciones¶
- Sin
mlflow, sindvc, sinwandb. La Fase 0 los difirió según §A8. Un directorio + un archivo JSON es el manifest. - Sin threading aún. Solo benchmarks single-thread. El ancho de banda multi-hilo es tema de la Fase 35.
- CPU governor:
performance. Ponlo antes de ejecutar:sudo cpupower frequency-set -g performance. Revierte después. Regístralo en el manifest. - Ejecuta enchufado a la red, no con batería. La batería throttlea agresivamente.
- Cierra otras apps. El tráfico de memoria en segundo plano contamina la medición.
Condiciones de parada¶
Terminado cuando:
- El directorio tiene los seis archivos.
bandwidth.pngmuestra tres mesetas visibles (L1, L2, L3) y una cola en DRAM.- El ancho de banda DRAM medido está dentro del 30% del
β_peakdel lab 00. (Fuera de ese rango → probablemente el Turbo Boost está apagado o el governor no está configurado; revísalo antes de mirar la solución.) - El
README.mdresponde a las tres preguntas del Bloque C.
Escollos (lee antes de depurar)¶
- El throughput a 1 KiB parece 50 GB/s, no 1 TB/s. Sí. El overhead del temporizador domina. Es una característica, no un bug — anótalo en tu README.
- El throughput vuelve a subir a 1 GiB. Probablemente estás golpeando el cache de archivos del OS u otros artefactos. Re-comprueba con una asignación fresca en cada iteración (o
np.copyto(dst, src)donde ambos están pre-asignados). - La meseta L2 es invisible. Prueba con tamaños más espaciados cercanos alrededor de
L1_size × 1.5aL2_size × 1.5. La transición es gradual. - El ancho de banda está sospechosamente bajo en todas partes. Comprueba
cpupower frequency-info—powersavereduce a la mitad tus números.
Cuándo consultar solutions/¶
Después de haber comprometido tus seis archivos y respondido las preguntas del Bloque C. La solución en solutions/01-memcpy-bandwidth-ref.md (escrita en apertura de fase) compara tus números y la estructura de tu código.
Siguiente lab: lab/02-cache-walks.md.