Tema 1: Evaluación de las prestaciones
Antecedentes
En Algoritmia se analizaba la eficiencia de algoritmos secuenciales con un enfoque monovariable (solo la talla ). Aquí se reutilizan esos modelos y se amplían a algoritmos paralelos, donde el tiempo depende también del número de procesadores .
Tiempo de ejecución secuencial: tiempo que tarda el programa en una sola unidad de proceso (procesador o core). Depende de la entrada, el compilador, el programador… pero se ignoran las constantes del sistema y se asume que solo depende de la talla: .
- En el análisis a priori se cuentan FLOPs (no pasos).
- En el análisis a posteriori se mide tiempo (segundos).
Sumatorios que aparecen continuamente:
Ejemplos de conteo (1 FLOP por iteración interna):
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (i</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; i</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; i</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-comment)"> // T(n) = n^2 FLOPs</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (j</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; j</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; j</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)"> y[i][j];</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (i</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; i</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; i</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-comment)"> // T(n) ≈ n^2/2 + n/2 ≈ n^2/2 FLOPs</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (j</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)">i; j</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; j</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)"> y[i][j];</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (i</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; i</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; i</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-comment)"> // T(n) ≈ n^3/3 FLOPs</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (j</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)">i; j</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; j</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (k</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)">i; k</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; k</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> b </span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)"> y[i][k];</span></span>
<span></span>
Por qué hace falta un modelo
El objetivo de un algoritmo paralelo es reducir el tiempo de ejecución: si el secuencial tarda , con procesadores se busca (como máximo teórico) . El rendimiento real es un conjunto de aspectos muy distintos (tiempo, productividad o throughput, latencia, portabilidad, escalabilidad…), ; en este curso se simplifica a .
Extrapolar observaciones no sirve
"Con 12 procesadores y el speedup fue 10.8". ¿Y con 1000 procesadores? ¿Y con ? ¿Y si las comunicaciones cuestan 10 veces más? Una medida aislada no responde. Con ecuaciones sí: dados , y , se puede estudiar cuál es mejor según y (el término de acaba dominando cuando crece ).
| Análisis a priori (teórico) | Análisis a posteriori (empírico) | |
|---|---|---|
| Cuándo | En el diseño, independiente de la máquina | Sobre una implementación y máquina concretas |
| Sirve para | Elegir la mejor opción y descubrir las tallas adecuadas | Encontrar cuellos de botella, dependencias, conflictos… no vistos en el diseño |
| Herramientas | Las de Algoritmia (, , ) ampliadas | Medidas de tiempo |
Lo recomendable es combinar ambos: saber modelizar y saber medir.
Parámetros absolutos y relativos
- Absolutos: dan el coste real (muy importantes en tiempo real). Hay que normalizarlos y aun así no sirven para comparar algoritmos. Se usará el tiempo de ejecución, que es la base de los relativos.
- Relativos: miden lo bien que el algoritmo aprovecha los recursos y permiten comparar algoritmos (paralelos y secuenciales). Se estudian coste, sobrecarga (overhead), eficiencia, speedup y escalabilidad.
Tiempo de ejecución paralelo
Definición: tiempo transcurrido desde que empieza el primer procesador hasta que termina el último.
Saber cuándo empieza o termina cada procesador no es trivial (es un orden parcial). Como en secuencial, admite análisis a priori y a posteriori. El modelo simplificado depende de la talla y del número de procesadores: .
Primera aproximación:
con el tiempo de cálculo (aritmético) y el de comunicaciones. En un diagrama de Gantt, cada procesador alterna computación, comunicación e inactividad; es lo que tarda el más lento.
Segunda aproximación:
- : tiempo de solapamiento entre cálculo y comunicación.
- : tiempo de sobrecarga (esperas, creación de procesos…).
| Tipo de algoritmo | Tiempo |
|---|---|
| Síncrono () | |
| Asíncrono | , con |
y son difíciles de estimar, así que en el curso se admite:
Para calcularlo: estudiar y por separado y luego combinar, suponiendo una arquitectura paralela ideal.
Tiempo de cálculo
Tiempo que el algoritmo pasa haciendo cálculos. Se expresa en FLOPs (en segundos en el modelo empírico):
donde es el número de FLOPs y el tiempo por FLOP.
Tiempo de comunicaciones
Tiempo que pasa enviando mensajes (memoria distribuida, MD) o sincronizándose (memoria compartida, MC). Por simplicidad se usa el mismo modelo para ambos, y también para comunicaciones internas y externas.
Un intercambio entre dos procesos vecinos (P2P) cuesta:
- : tamaño del mensaje.
- : latencia (start-up time).
- : inversa del ancho de banda (tiempo por palabra).
Como la latencia domina, es mejor enviar un mensaje grande que muchos pequeños:
- y pueden variar con la red o el tráfico; ese efecto no se considera.
- El modelo P2P no vale para operaciones colectivas (difusiones, recolecciones…): se expresan en función de operaciones P2P.
- En MC la sincronización se puede modelizar como mensajes de tamaño constante (coste constante) o en función de .
FLOP y rendimiento teórico
FLOP: una operación en coma flotante básica (suma, resta, multiplicación, división). El coste de otras operaciones en coma flotante se expresa en FLOPs, y el resto (aritmética entera, etc.) normalmente no se cuenta.
FLOPS (o FLOP/s, para no confundir): FLOPs por segundo.
Theoretical Peak Performance en doble precisión (), en GFLOPS. Es una estimación muy optimista, pero útil en el diseño. Se acepta (simple precisión).
(con varios nodos se multiplica también por chasis y nodos por chasis). Los FLOPs por ciclo dependen de las extensiones vectoriales (SIMD):
| Extensión | Factor (doble precisión) | Ejemplo |
|---|---|---|
| FMA (Fused Multiply-Add, ) | 2 | |
| SSE (128 bits) | 2 × nº unidades | Nehalem / Westmere: 4 FLOPs/ciclo |
| SSE2, AVX (256 bits) | 4 × nº unidades | Sandy/Ivy Bridge: 8 FLOPs/ciclo |
| AVX2 (AVX + FMA) | 8 × nº unidades | Haswell / Broadwell: 16 FLOPs/ciclo |
| AVX-512 | 8 × nº unidades | Knights Landing: 8 y 16 FLOPs/ciclo |
| AVX-512 + FMA | 16 × nº unidades | Skylake-SP / Cascade Lake: 32 FLOPs/ciclo |
Ejemplos (frecuencia base):
| Modelo | Sockets | Cores/socket | GHz | FLOPs/ciclo (DP–SP) | (GFLOPS) | |
|---|---|---|---|---|---|---|
| Xeon E5-2603 v4 | 2 | 6 | 1.7 | 16–32 | 326.4 | 652.8 |
| Xeon E5620 | 2 | 4 | 2.4 | 4–8 | 76.8 | 153.6 |
| i3-2100 | 1 | 2 | 3.1 | 8–16 | 49.6 | 99.2 |
| Ryzen 7 3700X | 1 | 8 | 2.2 | 16–32 | 281.6 | 563.2 |
| AMD EPYC 7413 | 1 | 24 | 2.65 | 16–32 | 1017.6 | 2035.4 |
Por ejemplo, Xeon E5620: GFLOPS.
Pico anunciado vs. rendimiento real
En el ejemplo de clase: pico anunciado (PAP) 5.00 TFLOPs, LINPACK 3.05 TFLOPs y rendimiento medio sostenido en aplicaciones reales (ASAP) solo 0.40 TFLOPs. Y la distancia entre PAP y ASAP ha ido creciendo con los años. Usar un sistema de forma eficiente es justo el objetivo de la asignatura.
Coste y sobrecarga
Coste:
Un algoritmo es de coste óptimo si es proporcional a . Ejemplo: , , .
Sobrecarga (overhead): tiempo extra que los procesadores consumen entre todos respecto al mejor algoritmo secuencial.
Speedup y eficiencia
Speedup: ganancia de velocidad del paralelo frente al secuencial.
Cualquier algoritmo paralelo se puede simular en una máquina secuencial ejecutando sus pasos en serie (ignorando comunicaciones), así que:
- Si se usa como el paralelo con un procesador, , el speedup mide la bondad del diseño paralelo.
- Si se usa el mejor secuencial conocido, mide la eficacia (prestaciones) real del algoritmo paralelo.
| Speedup | Nombre | Causa |
|---|---|---|
| Lineal | Sin penalización por comunicaciones, sin dependencias, todos trabajan a la vez, carga balanceada | |
| Sublineal | Dependencias de datos, el problema no se divide en partes concurrentes… | |
| Superlineal | El secuencial no era óptimo, hay un error de cálculo o efectos colaterales (p. ej., cachés) |
Eficiencia: grado de aprovechamiento del sistema (fracción de trabajo útil).
Ejemplos
1. Producto de matrices secuencial
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (i</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; i</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; i</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (j</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; j</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">m; j</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">) {</span></span>
<span><span style="color: var(--shiki-color-text)"> c[i][j] </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">0.0</span><span style="color: var(--shiki-color-text)">;</span></span>
<span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (r</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; r</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">k; r</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)"> c[i][j] </span><span style="color: var(--shiki-token-keyword)">+=</span><span style="color: var(--shiki-color-text)"> a[i][r] </span><span style="color: var(--shiki-token-keyword)">*</span><span style="color: var(--shiki-color-text)"> b[r][j];</span></span>
<span><span style="color: var(--shiki-color-text)"> }</span></span>
<span></span>
Con FMA la multiplicación y la suma cuentan como una sola operación: .
2. Grafo de tareas
Cuatro tareas independientes – de coste 50 y una tarea final de coste 20 que depende de las cuatro. Secuencial: .
| 2 | 240 | 20 | 1.83 | 0.916 | |
| 3 | 360 | 140 | 1.83 | 0.61 | |
| 4 | 280 | 60 | 3.14 | 0.786 | |
| 5 | 350 | 130 | 3.14 | 0.629 |
Con 3 procesadores una de las tareas de 50 sigue necesitando una segunda "ronda", así que no mejora respecto a 2. A partir de : el tiempo y el speedup quedan constantes, el coste y la sobrecarga crecen y la eficiencia decrece (). No compensa usar más de 4 procesadores. El área en la que los procesadores están parados es justo la sobrecarga.
Adelanto: cota de Brent
donde es el tiempo del camino crítico (se ve en el tema siguiente).
3. Suma de un vector con
<span><span style="color: var(--shiki-token-comment)">/* Secuencial */</span></span>
<span><span style="color: var(--shiki-color-text)">s </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">0.0</span><span style="color: var(--shiki-color-text)">;</span></span>
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (i</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">; i</span><span style="color: var(--shiki-token-keyword)"><</span><span style="color: var(--shiki-color-text)">n; i</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">) s </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> s </span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)"> v[i];</span></span>
<span></span>
<span><span style="color: var(--shiki-token-comment)">/* Paralelo, en cada Pi con i = 0..(n/2)-1: reducción en árbol */</span></span>
<span><span style="color: var(--shiki-color-text)">in </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">2</span><span style="color: var(--shiki-token-keyword)">*</span><span style="color: var(--shiki-color-text)">i; des </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-color-text)">;</span></span>
<span><span style="color: var(--shiki-token-keyword)">for</span><span style="color: var(--shiki-color-text)"> (k</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-constant)">1</span><span style="color: var(--shiki-color-text)">; k</span><span style="color: var(--shiki-token-keyword)"><=</span><span style="color: var(--shiki-token-function)">log2</span><span style="color: var(--shiki-color-text)">(n) </span><span style="color: var(--shiki-token-keyword)">&&</span><span style="color: var(--shiki-color-text)"> (i </span><span style="color: var(--shiki-token-keyword)">%</span><span style="color: var(--shiki-color-text)"> des </span><span style="color: var(--shiki-token-keyword)">==</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">0</span><span style="color: var(--shiki-color-text)">); k</span><span style="color: var(--shiki-token-keyword)">++</span><span style="color: var(--shiki-color-text)">) {</span></span>
<span><span style="color: var(--shiki-color-text)"> a[in] </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> a[in] </span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)"> a[in</span><span style="color: var(--shiki-token-keyword)">+</span><span style="color: var(--shiki-color-text)">des];</span></span>
<span><span style="color: var(--shiki-color-text)"> des </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> des</span><span style="color: var(--shiki-token-keyword)">*</span><span style="color: var(--shiki-token-constant)">2</span><span style="color: var(--shiki-color-text)">;</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
- ,
- ,
No es de coste óptimo: el coste crece como frente a .
4. Suma con
Cada procesador suma primero su bloque de elementos y después se hace la reducción en árbol entre los resultados:
(los extremos son y ). Con , : y , la misma eficiencia que el algoritmo anterior. Con menos procesadores () el término domina y la eficiencia mejora.
5. Algoritmo iterativo con matrices
Con , cada producto de matrices cuesta y , son producto y división elemento a elemento:
Repetir
B = W^T W H
C = W^T A
H = H ⊛ C ⊘ B
D = W H H^T
E = A H^T
W = W ⊛ E ⊘ D
Fin repetir
Hay 6 productos de matrices () y 4 operaciones elemento a elemento:
Modelos de rendimiento
Ley de Amdahl (tamaño fijo del problema)
Mide el speedup máximo alcanzable. El tiempo secuencial se divide en una parte no paralelizable y una paralelizable :
Normalizando :
- Paralelizable al 90 %: , por muchos procesadores que se usen.
- Paralelizable al 50 %: .
Escrito con la fracción paralela (en tantos por uno):
Rendimiento efectivo en doble precisión: el speedup de Amdahl por lo que da un solo core.
| Modelo | () | ||||
|---|---|---|---|---|---|
| Xeon E5-2603 v4 | 326.4 | 294.1 | 210.6 | 155.4 | 87.0 |
| Xeon Phi 31S1P | 1003.0 | 306.8 | 81.2 | 42.3 | 17.4 |
| i3-2100 | 49.6 | 49.1 | 47.2 | 45.1 | 39.7 |
| AMD EPYC 7413 | 1017.6 | 827.3 | 473.3 | 308.4 | 150.8 |
Por ejemplo, Xeon E5-2603 v4 (, ): y .
Consecuencias de Amdahl
- Con el tamaño del problema fijo (strong scaling), la eficiencia decrece al aumentar .
- En programas reales el tiempo puede incluso aumentar al crecer (overhead, comunicaciones…), aunque el modelo teórico no lo refleje.
- Para un tamaño fijo, a partir de cierto número de procesadores no compensa añadir más.
- Una máquina con muchos cores lentos (Xeon Phi) se hunde en cuanto la fracción secuencial no es mínima.
- Speedup y eficiencia dependen de y : las conclusiones pueden cambiar si cambia cualquiera de ellos.
Ley de Gustafson–Barsis
Speedup escalado:
donde es el tamaño computacional del problema.
- Amdahl responde: ¿cuánto se puede acelerar un problema de tamaño fijo?
- Gustafson responde: con más recursos, ¿cuánto más grande puede ser el problema manteniendo el tiempo aproximadamente constante?
Escalabilidad
Modelos de isorendimiento: caracterizan la escalabilidad manteniendo constante una métrica de rendimiento.
- Isotiempo: se mantiene el tiempo; el recurso es el número de procesadores.
- Isoeficiencia: se mantiene la eficiencia; el recurso es el número de procesadores.
Función de isoeficiencia: ¿cómo debe crecer el tamaño computacional en función de para que sea constante?
Algoritmo escalable: aquel cuya función de isoeficiencia es lineal en . Cuanto menos tenga que crecer al aumentar , más escalable es.
Enfoque 1: fijar la eficiencia y despejar
Ejemplo, con y :
| Algoritmo | |
|---|---|
| A | |
| B |
- Con : ambos dan , es decir, . Iguales.
- Con : A da y B da . Analíticamente distintos, pero asintóticamente equivalentes ().
Enfoque 2: Kumar et al.
Partiendo de la sobrecarga:
Llamando (constante si lo es), la función de isoeficiencia es:
Cómo se usa: se calcula y se analiza cada término por separado (el de , el de , el de ); la isoeficiencia del algoritmo es la del término que exige un crecimiento mayor. Los términos que no dependen de no afectan a la escalabilidad.
Ejemplo
y , con .
- : no depende de → no afecta.
- : .
- : .
La isoeficiencia es . Otras variantes del mismo problema dan o si las comunicaciones tienen un factor .
Ejemplo con dos casos
y :
- : .
- con : .
- con : .
Enfoque 3: sobrecarga relativa
Mira cómo crece la sobrecarga respecto al mejor secuencial:
Si el algoritmo escala óptimamente. Manteniendo constante la eficiencia sale ; si la sobrecarga no obliga a que crezca más que linealmente. Como además el límite de concurrencia impone , el mejor crecimiento posible es : exactamente la escalabilidad óptima del enfoque 2.
Interpretación de la isoeficiencia
| Función de isoeficiencia | Escalabilidad |
|---|---|
| Óptima | |
| Buena, pero no óptima | |
| Peor | |
| Mala: exige que el problema crezca muy rápido |
Siempre que se pueda mantener constante la eficiencia haciendo crecer , el algoritmo es escalable, por mala que sea su escalabilidad. Si no se puede (el término se cancela), no escala.
Eficiencia escalada
Otra forma de medir la escalabilidad: se multiplican el tamaño del problema y el número de procesadores por el mismo factor y se compara el tiempo.
- Si el tiempo se mantiene aproximadamente constante, : comportamiento ideal de escalado débil (weak scaling).
- Algunos autores consideran cuasi-escalable un algoritmo mientras (Prieto et al., 2003).
- Multiplicar por 2 es buena estrategia, pero un intervalo de observación mal elegido puede llevar a conclusiones erróneas.
Ejemplo
, , , con , y .
- , →
- , →
Sistemas híbridos / heterogéneos
Sistemas formados por elementos de distinta naturaleza: CPU + GPU, ordenadores con distintas prestaciones, etc. Los grupos suelen (no necesariamente) hacer los mismos cálculos y comunicaciones.
El modelo se generaliza con varias constantes de cálculo y comunicación. Se obtiene el de cada grupo por separado y luego se compone . El resto del análisis es igual, solo que más complejo algebraicamente.
Clúster con CPU + GPU
ordenadores iguales en red (, ). Cada uno tiene una CPU con núcleos () y una GPU 9 veces más potente (constantes , , ). , sin dependencias externas y todos hacen el mismo cálculo.
a) Tiempo de cada ordenador. Cada ordenador recibe . Dentro, el reparto es proporcional a la potencia: a la CPU y a la GPU. Se envía y recibe lo mismo a/de la GPU y la carga está balanceada ():
b) Sistema completo, con coste CPU/GPU nulo. Distribuir y recolectar entre los ordenadores con P2P (no óptimo):
c) Escalabilidad.
- : no depende de .
- : .
- : . aparece en los dos lados y se cancela: aumentar el problema no compensa el crecimiento de . No escala.
Resumen de fórmulas
| Concepto | Fórmula |
|---|---|
| Tiempo paralelo | |
| Síncrono | |
| Asíncrono | |
| Cálculo | |
| Comunicación P2P | |
| Coste | |
| Sobrecarga | |
| Speedup | |
| Eficiencia | |
| Amdahl | |
| Gustafson–Barsis | , |
| Rendimiento teórico | |
| Rendimiento efectivo | |
| Isoeficiencia | , |
| Sobrecarga relativa | ; escala óptimamente si |
| Eficiencia escalada | |
| Grado medio de concurrencia | (ver Tema 2 - Diseño de algoritmos paralelos) |
| Relación superficie-volumen |