En la clase observamos aspectos de paralizacion.
- Localidad en memoria (diferencia entre recorrer por filas o por columnas)
- OpenMP: Anotaciones y schedule
Anotaciones
Conceptos Fundamentales
Jerarquía de Memoria y Acceso a Datos
- Cache como puerta de entrada: El procesador accede primero a cache, luego a RAM
- Localidad espacial: Acceso contiguo mejora rendimiento
- Row-major order: En C++, arreglos 2D se almacenan por filas en memoria
Impacto del Patrón de Acceso
| Acceso por Filas |
Acceso por Columnas |
| ✅ Memoria contigua |
❌ Saltos en memoria |
| ✅ Pocos cache misses |
❌ Múltiples cache misses |
| ✅ Prefetching efectivo |
❌ Prefetching ineficiente |
| ✅ Alta localidad |
❌ Baja localidad |
Tabla de Conceptos Clave
| Concepto |
Descripción |
Impacto en Rendimiento |
| Localidad Espacial |
Acceso a datos contiguos en memoria |
Reduce cache misses, mejora prefetching |
| Falsa Compartición |
Múltiples hilos acceden a misma línea de cache |
Invalida cache, aumenta latencia |
| Cache Miss |
Dato no encontrado en cache, debe cargarse de RAM |
Añade 10-100x más latencia |
| Row-major Order |
Almacenamiento por filas en memoria (C/C++) |
Acceso por filas = óptimo |
| Reducción OpenMP |
Combina resultados parciales de hilos |
Evita condiciones de carrera |
| Schedule Static |
Distribución fija de iteraciones |
Overhead mínimo, buen balance uniforme |
| Schedule Dynamic |
Asignación dinámica con chunks |
Mejor load balancing, overhead moderado |
| Schedule Guided |
Bloques decrecientes |
Compromiso overhead/balance |
| Chunk Size |
Tamaño de bloque para distribución |
Pequeño = mejor balance, Grande = menos overhead |
Directivas OpenMP Principales
| Directiva |
Propósito |
Uso Típico |
parallel for |
Paralelizar loops |
Operaciones independientes |
reduction |
Combinar resultados |
Sumas, máximos, productos |
schedule |
Controlar distribución |
Optimizar balance de carga |
critical |
Sección exclusiva |
Acceso seguro a variables compartidas |
atomic |
Operación atómica |
Incrementos simples |
runtime |
Schedule configurable |
Pruebas sin recompilar |
Optimizaciones Comprobadas
1. Patrón de Acceso Óptimo
// ✅ CORRECTO - Acceso por filas
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
sum += arr[i][j]; // [i][0], [i][1], [i][2]...
}
}
2. Schedule Recomendado
- dynamic con chunk pequeño (2-10): Mejor balance carga + mínima falsa compartición
- Resultado: 49.83 ms vs 66.26 ms (32% mejora)
3. Operaciones Paralelizables vs No Paralelizables
- ✅ Paralelizables: Map, filter, reducciones (independientes)
- ❌ No paralelizables: Prefix sum, Fibonacci (dependencias)
Conclusiones Prácticas
- El cuello de botella es la memoria cache, no la CPU
- Acceso por filas + dynamic scheduling = combinación óptima
- Chunks pequeños mejoran balance pero aumentan overhead
- OpenMP runtime permite experimentar sin recompilar
- Medir siempre el speedup real considerando overhead