Logo Studenta

Computadores Paralelos

¡Este material tiene más páginas!

Vista previa del material en texto

COMPUTADORES 
PARALELOS 
 
 
Computación de Alta Velocidad 
 
 
 
 
 
 
 
 
 
A. Arruabarrena — J. Muguerza 
 
Konputagailuen Arkitektura eta Teknologia saila 
Informatika Fakultatea — Euskal Herriko Unibertsitatea 
 
 
 
 
 
 
 
COMPUTADORES 
PARALELOS 
 
 
Computación de Alta Velocidad 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
A. Arruabarrena — J. Muguerza 
 
Konputagailuen Arkitektura eta Teknologia saila 
Informatika Fakultatea — Euskal Herriko Unibertsitatea 
 
 
 
 
 
 
 
 
septiembre 2011 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ÍNDICE 
 
 
 Introducción ......................................................................... 1 
Capítulo 1. Computadores Vectoriales ............................................... 7 
1.1 ¿Qué es un computador vectorial? ................................................................... 7 
1.1.1 Algunos problemas ............................................................................................... 10 
1.1.1.1 La memoria de un computador vectorial .......................................... 10 
1.1.1.2 Unidades funcionales vectoriales ........................................................ 11 
1.1.1.3 Registros vectoriales ............................................................................... 11 
1.1.1.4 Programas vectoriales ............................................................................ 12 
1.1.2 Arquitectura y lenguaje-máquina ...................................................................... 13 
1.2 Dependencias de datos ..................................................................................... 15 
1.2.1 Encadenamiento (chaining) ........................................................................................... 16 
1.2.1.1 Encadenamiento con dos instrucciones ............................................ 17 
1.2.2 Tablas de ejecución de las instrucciones ........................................................ 18 
1.3 Dependencias estructurales .............................................................................. 20 
1.3.1 Buses de memoria (unidades funcionales LV/SV) ........................................ 20 
1.3.2 Conflictos en el uso de los módulos de memoria ........................................ 22 
1.3.2.1 Una sola operación de memoria ......................................................... 22 
1.3.2.2 Varias operaciones de memoria .......................................................... 26 
1.3.3 Longitud de los registros vectoriales (strip mining) ...................................... 29 
1.4 Velocidad de cálculo de los computadores vectoriales ............................ 30 
1.4.1 Velocidad de cálculo en función de la longitud de los vectores .............. 31 
1.4.1.1 R∞ y N1/2..................................................................................................... 31 
1.4.1.2 Speed-up o factor de aceleración ....................................................... 33 
1.4.1.3 Nv ................................................................................................................. 34 
1.4.2 Influencia del código escalar. Ley de Amdahl. .............................................. 34 
1.5 Técnicas de compilación para generar código vectorial ........................... 37 
1.5.1 Dependencias de datos entre instrucciones .................................................. 38 
1.5.2 Vectorización ......................................................................................................... 40 
1.5.2.1 Vectores de una dimensión .................................................................. 40 
1.5.2.2 Vectores de N dimensiones ................................................................. 44 
1.5.2.3 Condición para vectorizar un bucle ................................................... 45 
1.5.2.4 Test de dependencias ............................................................................ 46 
1.5.3 Optimizaciones...................................................................................................... 50 
1.5.3.1 Sustitución global hacia adelante (global forward substitution) ................... 50 
▪ vi ▪ ÍNDICE 
1.5.3.2 Eliminación de las variables de inducción ......................................... 51 
1.5.3.3 Antidependencias (DR, WAR) ...................................................................... 52 
1.5.3.4 Dependencias de salida (RR, WAW) ........................................................ 53 
1.5.3.5 Intercambio de bucles (loop-interchanging) .......................................... 54 
1.5.3.6 Expansión escalar (scalar expansion) ........................................................ 56 
1.5.3.7 Fusión de bucles (loop fusion) ..................................................................... 57 
1.5.3.8 Colapso de bucles (loop collapsing) ......................................................... 58 
1.5.3.9 Otras optimizaciones ............................................................................. 59 
1.5.4 Vectores de máscara y vectores de índices ................................................... 60 
1.5.4.1 Uso de máscaras ..................................................................................... 60 
1.5.4.2 Vectores de índices ................................................................................ 61 
1.6 Resumen ................................................................................................................ 64 
Capítulo 2. Computadores Paralelos (conceptos básicos) ................. 69 
2.1 Introducción ......................................................................................................... 69 
2.2 Computadores DM-SIMD ................................................................................. 71 
2.3 Computadores MIMD ........................................................................................ 73 
2.3.1 Memoria compartida (shared memory) .................................................................. 73 
2.3.2 Memoria privada o distribuida (distributed memory) ....................................... 74 
2.3.3 Memoria lógicamente compartida pero físicamente distribuida 
(distributed shared memory) ......................................................................................... 75 
2.3.4 Clusters, constellations... y otros ....................................................................... 76 
2.4 Algunos problemas ............................................................................................. 77 
2.5 Rendimiento del sistema paralelo (leyes de Amdahl y Gustafson) ......... 79 
Capítulo 3. Coherencia de los Datos en los Computadores 
SMP ...................................................................................... 83 
3.1 Presentación del problema y revisión de conceptos .................................. 83 
3.1.1 Coherencia de los datos en los sistemas de un solo procesador ............. 84 
3.1.2 Coherencia de los datos en los multiprocesadores de memoria 
compartida (SMP) ................................................................................................. 85 
3.1.3 Falsa compartición ................................................................................................ 86 
3.1.4 Definición de la coherencia................................................................................ 87 
3.2 Protocolos de coherencia snoopy .................................................................. 88 
3.2.1 Estados de los bloques en la memoria cache y señales de control .......... 90 
3.2.2 Protocolos de invalidación ................................................................................. 93 
3.2.2.1 Un protocolo de tres estados, MSI ..................................................... 94 
3.2.2.2 El protocolo Illinois, MESI ...................................................................... 97 
3.2.2.3 El protocoloBerkeley, MOSI ................................................................ 99 
3.2.2.4 Resumen de los protocolos de invalidación................................... 100 
ÍNDICE ▪ vii ▪ 
3.2.3 Protocolos de actualización ............................................................................. 101 
3.2.3.1 El protocolo Firefly, MSE(I) .................................................................. 101 
3.2.3.2 El protocolo Dragon, MOES(I) ........................................................... 103 
3.2.4 Resumen de los protocolos de tipo snoopy ................................................ 105 
3.3. Implementación de los protocolos snoopy ................................................ 105 
3.3.1 Problemas ............................................................................................................. 105 
3.3.1.1 Directorio de la memoria cache ........................................................ 106 
3.3.1.2 Búferes de escritura .............................................................................. 107 
3.3.1.3 Protocolo de petición de bus ............................................................. 108 
3.3.1.4 Atomicidad: estado del controlador snoopy .................................. 109 
3.3.2 El protocolo Illinois y la atomicidad ................................................................ 110 
3.3.2.1 Carreras: estados transitorios, señales BRQ y BGN ..................... 110 
3.3.2.2 Deadlock, livelock, starvation ............................................................ 112 
3.4 Snoopy jerárquico ............................................................................................. 113 
3.4.1 Lecturas .................................................................................................................. 115 
3.4.2 Escrituras ................................................................................................................ 116 
Capítulo 4. Sincronización de Procesos en los Computado-
res SMP .............................................................................. 119 
4.1 Introducción ....................................................................................................... 119 
4.2 Exclusión mutua (mutual exclusion) ............................................................. 123 
4.2.1 Instrucciones Test&Set y Swap ........................................................................ 125 
4.2.1.1 Instrucción Test&Set ............................................................................. 125 
4.2.1.2 Instrucción Swap ................................................................................... 125 
4.2.1.3 Análisis del tráfico ................................................................................. 126 
4.2.1.4 Procedimiento Test&Set with backoff .............................................. 127 
4.2.1.5 Procedimiento Test-and-Test&Set ...................................................... 128 
4.2.1.6 Resumen de características ................................................................ 130 
4.2.2 Instrucciones Load Locked / Store Conditional y Compare&Swap ....... 131 
4.2.2.1 Instrucciones LL y SC ........................................................................... 132 
4.2.2.2 Instrucción Compare&Swap ............................................................... 134 
4.2.2.3 Algunos problemas con las instrucciones LL/SC ........................... 135 
4.2.3 Instrucciones Fetch&Op .................................................................................... 136 
4.2.4 Alternativas para reducir el tráfico .................................................................. 137 
4.2.4.1 Tickets ...................................................................................................... 137 
4.2.4.2 Vectores de cerrojos ............................................................................ 139 
4.3 Sincronización "punto a punto" mediante eventos ................................... 141 
4.4 Sincronización mediante barreras ................................................................. 142 
4.4.1 Una barrera sencilla ............................................................................................ 142 
4.4.2 Barreras reutilizables .......................................................................................... 143 
4.4.3 Eficiencia ................................................................................................................ 145 
4.5 Resumen .............................................................................................................. 146 
▪ viii ▪ ÍNDICE 
Capítulo 5. Consistencia de la Memoria en los Computa-
dores Paralelos ................................................................ 149 
5.1 Introducción ....................................................................................................... 149 
5.1.1 Sistemas de un solo procesador ...................................................................... 149 
5.1.2 Sistemas multiprocesador ................................................................................. 150 
5.1.3 Semántica de los programas y orden de ejecución de las 
instrucciones ......................................................................................................... 151 
5.1.4 Atomicidad de las instrucciones ...................................................................... 153 
5.1.5 Modelos de consistencia ................................................................................... 154 
5.2 Consistencia secuencial (SC, sequential consistency) .............................. 155 
5.2.1 Orden y atomicidad de las instrucciones de memoria .............................. 156 
5.2.2 Efectos en el hardware y en el compilador .................................................. 158 
5.3 Modelos relajados (relaxed) ........................................................................... 159 
5.3.1 Total Store Ordering (TSO) / Processor Consistency (PC) ....................... 160 
5.3.2 Partial Store Ordering (PSO) ............................................................................ 162 
5.3.3 Modelos más relajados ...................................................................................... 163 
5.3.3.1 Weak Ordering (WO) .......................................................................... 164 
5.3.3.2 Release Consistency (RC) ................................................................... 164 
5.4 Resumen y perspectivas .................................................................................. 166 
Capítulo 6 La Red de Comunicación de los Computadores 
Paralelos. Comunicación mediante Paso de 
Mensajes. .......................................................................... 169 
6.1 Introducción ....................................................................................................... 169 
6.2 Topología de la red ........................................................................................... 171 
6.3 Redes formadas por conmutadores .............................................................. 173 
6.3.1 El conmutador (switch) .................................................................................................. 174 
6.3.2 Red crossbar ......................................................................................................... 175 
6.3.3 Redes multietapa (multistage) .................................................................................... 176 
6.3.3.1 La red Omega ........................................................................................ 176 
6.3.3.2 Encaminamiento en la red Omega ................................................... 178 
6.3.3.3 Conflictos de salida y bloqueos ......................................................... 179 
6.3.3.4 Otro patrón de comunicación: broadcast. ..................................... 181 
6.3.3.5 Otras redes .............................................................................................181 
6.3.3.6 Resumen .................................................................................................. 183 
6.4 Redes formadas por encaminadores de mensajes .................................... 184 
6.4.1 Encaminadores de mensajes ............................................................................ 184 
6.4.2 Topologías de red más utilizadas .................................................................... 185 
6.4.2.1 Redes de una dimensión: la cadena y el anillo .................................. 186 
6.4.2.2 Mallas y Toros (mesh, torus) ....................................................................... 187 
ÍNDICE ▪ ix ▪ 
6.4.2.3 Hipercubos (hypercube) ............................................................................... 188 
6.4.2.4 Árboles y árboles densos (fat tree) ........................................................... 190 
6.4.2.5 Resumen de topologías ....................................................................... 191 
6.4.2.6 Los enlaces físicos ................................................................................. 193 
6.5 La comunicación a través de la red en los sistemas paralelos ............... 193 
6.5.1 Los mensajes ........................................................................................................ 194 
6.5.2 Patrones de comunicación: con quién y cuándo hay que 
efectuar la comunicación. ................................................................................. 195 
6.5.3 Construcción del camino (switching strategy) ................................................... 198 
6.5.4 Encaminamiento de los mensajes (routing) ......................................................... 199 
6.5.4.1 El registro de encaminamiento .......................................................... 200 
6.5.4.2 Elección del camino: estático o adaptativo .................................... 203 
6.5.5 Control del flujo de información ..................................................................... 206 
6.5.5.1 Avance de los paquetes: Store-and-forward, 
Wormhole y Cut-through .................................................................... 206 
6.5.5.2 Conflictos en el uso de recursos: los búferes ................................. 210 
6.5.6 Eficiencia de la comunicación: latencia y throughput ............................... 214 
6.5.6.1 Tiempo de comunicación en la red .................................................. 215 
6.5.6.2 Considerando el tráfico en la red ...................................................... 217 
6.5.6.3 Cálculo del throughput máximo ........................................................ 219 
6.5.6.4 Análisis global ......................................................................................... 221 
6.5.7 Problemas de la comunicación ....................................................................... 222 
6.5.7.1 Deadlock (interbloqueos) Canales virtuales. Giros 
controlados (Turn model). Control de la inyección de 
paquetes. Utilización de caminos seguros ..................................... 222 
6.5.7.2 Problemas de livelock y starvation.................................................... 229 
6.5.8 Protocolos de comunicación ........................................................................... 230 
6.6 Evolución de los computadores paralelos ................................................... 232 
 
Apéndice. Cálculo de las distancias medias en diferentes topologías .......... 235 
Capítulo 7. Coherencia de los Datos en los Computadores 
DSM .................................................................................... 241 
7.1 Introducción ....................................................................................................... 241 
7.2 Directorios de coherencia ............................................................................... 243 
7.2.1 Introducción y clasificación ................................................................................ 243 
7.2.1.1 Problemas................................................................................................ 245 
7.2.2 Estructura de los directorios ............................................................................. 246 
7.2.2.1 Directorios implementados en memoria principal ....................... 246 
7.2.2.2 Directorios implementados en memoria cache ............................ 251 
7.2.3 Optimización del tráfico de coherencia ........................................................ 254 
7.2.4 Atomicidad de las operaciones: carreras ...................................................... 257 
▪ x ▪ ÍNDICE 
7.3 Implementación de los protocolos de coherencia: dos 
ejemplos .............................................................................................................. 259 
7.3.1 Protocolo de coherencia de los multicomputadores SGI Origin ............ 259 
7.3.1.1 Lecturas .................................................................................................... 260 
7.3.1.2 Escrituras .................................................................................................. 263 
7.3.1.3 Actualización de la memoria principal ............................................ 268 
7.3.2 El protocolo de coherencia estándar SCI en la máquina NUMA-Q 
de Sequent. ........................................................................................................... 269 
7.3.2.1 SCI: estados y operaciones ................................................................. 270 
7.3.2.2 Lecturas .................................................................................................... 272 
7.3.2.3 Escrituras .................................................................................................. 273 
7.3.2.4 Actualización de la memoria principal ............................................ 277 
7.3.2.5 Atomicidad y carreras .......................................................................... 277 
7.4 Resumen .............................................................................................................. 279 
Capítulo 8. Paralelización y Planificación de Bucles .................. 281 
8.1 Introducción ....................................................................................................... 281 
8.1.1 Ideas básicas sobre paralelización de bucles ............................................... 287 
8.2. Estructuras básicas para expresar el paralelismo de los bucles .............. 290 
8.2.1 Bucles sin dependencias entre iteraciones: bucles doall .......................... 290 
8.2.2 Bucles con dependencias entre iteraciones ................................................. 291 
8.2.2.1 Bucles forall (sincronización global .................................................. 292 
8.2.2.2 Bucles doacross (sincronización punto a punto) .......................... 293 
8.2.3 Efecto de las antidependencias y de las dependencias de salida ........... 298 
8.2.4 Atención con las instrucciones if ..................................................................... 299 
8.3 Implementación de la sincronización........................................................... 300 
8.3.1 Sincronización mediante contadores ............................................................. 301 
8.3.2 Un único contador por procesador................................................................ 303 
8.4 Optimizaciones para paralelizar bucles de manera eficiente ................. 304 
8.4.1 Eliminación del efecto de las dependencias que no son esenciales ...... 304 
8.4.2 Fisión de bucles ................................................................................................... 305 
8.4.3 Ordenación de las dependencias ................................................................... 306 
8.4.4 Alineación de las dependencias (peeling) .................................................... 307 
8.4.5 Extracción de threads independientes (switching) .....................................309 
8.4.6 Minimización de las operaciones de sincronización ................................. 310 
8.4.7 Tratamiento de bucles (reordenación...) ........................................................ 311 
8.4.7.1 Intercambio de bucles.......................................................................... 311 
8.4.7.2 Cambio de sentido................................................................................ 314 
8.4.7.3 Desplazamientos (skew) ....................................................................... 314 
8.4.7.4 Colapso y coalescencia de bucles .................................................... 315 
8.5 Planificación de bucles (scheduling) ............................................................... 316 
8.5.1 Reparto de las iteraciones: consecutivo o entrelazado ............................. 317 
ÍNDICE ▪ xi ▪ 
8.5.2 Planificación estática o dinámica .................................................................... 318 
8.5.2.1 Planificación estática ............................................................................ 319 
8.5.2.2 Planificación dinámica: autoplanificación (self/chunk 
scheduling), autoplanificación guiada (GSS) y trapezoidal 
(trapezoid self scheduling) ........................................................................... 319 
8.6 Secciones paralelas: Fork / Join ..................................................................... 323 
8.7 Análisis del rendimiento................................................................................... 325 
Capítulo 9. Computadores de Alta Velocidad. Herramientas 
para Programar Aplicaciones Paralelas 
(introducción). ..................................................................... 327 
9.1 Computadores paralelos de alto rendimiento ............................................ 328 
9.2 Herramientas para programar aplicaciones paralelas (introducción) ... 331 
9.2.1 OpenMP ................................................................................................................ 332 
9.2.2 MPI ......................................................................................................................... 336 
 
 
 
 
 
 
Introducción 
 
 
 
 
 
 
 
 
 
 
 
 
¿Qué tiempo hará mañana en esta ciudad? ¿Cómo evolucionan las 
galaxias? ¿Cómo interaccionan los electrones en una molécula de clorofila? 
¿Se comportarán de manera adecuada las alas de un avión en una 
turbulencia? Para dar respuesta adecuada a esas y otras muchas preguntas, 
científico/as e ingeniera/os utilizan potentes computadores, la herramienta 
principal de cualquier laboratorio en la actualidad. Las aplicaciones técnico-
científicas requieren de grandes cantidades de cálculo, casi de manera 
ilimitada, y además hay que obtener resultados en el menor tiempo posible, 
(prever mañana las lluvias torrenciales de hoy no sirve para mucho!). A 
pesar del espectacular incremento en la velocidad de cálculo de los 
procesadores, las necesidades van siempre muy por delante. A lo largo de la 
evolución de los computadores tres han sido las líneas principales que han 
▪ 2 ▪ INTRODUCCIÓN 
permitido aumentar de manera continuada la velocidad de los mismos: los 
avances en la tecnología electrónica, el desarrollo de nuevas estructuras o 
arquitecturas de computadores, y el uso de tecnologías del software 
(compiladores, etc.) cada vez más eficientes. 
Mediante la tecnología electrónica se ha conseguido integrar en un sólo 
chip una cantidad ingente de transistores: hoy en día por encima de 1.000 
millones (y cada vez más). A consecuencia de este avance, cada vez son más 
las "partes" del computador que se van integrando en un solo chip junto con 
el procesador: unidades funcionales específicas, registros, memoria cache... e 
incluso varios procesadores o núcleos (core). Del mismo modo, la frecuencia 
del reloj del computador es cada vez más alta (aunque la carrera para usar 
relojes cada vez más rápidos está detenida en este momento), actualmente en 
el intervalo 1-4 GHz, lo que quiere decir que el tiempo de ciclo está por 
debajo del nanosegundo (F = 1 GHz → T = 1 ns) y, como consecuencia, se 
pueden hacer más operaciones por unidad de tiempo. 
Desde el punto de vista de la arquitectura del sistema, todos los 
procesadores actuales son superescalares o de tipo VLIW (la ejecución de las 
instrucciones es segmentada y se intenta ejecutar más de una instrucción 
cada ciclo); la jerarquía de memoria cache permite accesos más rápidos, los 
registros se organizan para optimizar el uso de los datos, etc. 
Las técnicas de compilación también han avanzado mucho. El objetivo 
principal es eliminar el efecto de las dependencias existentes entre las 
instrucciones, y ocultar la latencia de la unidades funcionales (aprovechando 
ese tiempo para realizar trabajo útil). 
Sin embargo, a pesar de que tenemos procesadores superescalares muy 
rápidos —que llegan a superar la velocidad de cálculo de 10 Gflop/s— para 
muchas aplicaciones, tales como previsiones meteorológicas, simulaciones 
de procesos físicos y químicos, diseños de aeronáutica, prospecciones 
geológicas, diseño de nuevos materiales, desarrollos diversos en ingeniería, 
avances en biología, genética y farmacia, etc., dicha velocidad no es 
suficiente. En el periodo 1986-2002, la tasa de crecimiento del rendimiento 
de los procesadores fue de un %52 anual (!), pero dicho crecimiento se ha 
reducido notablemente estos últimos años, situándose en torno al 20%: la 
velocidad que se puede conseguir con un procesador está llegando a sus 
límites físicos (y económicos). Por tanto, se necesita de desarrollar otro tipo 
de estrategias para conseguir las velocidades de cálculo —Teraflop/s, 
Petaflop/s, es decir, 1012, 1015 operaciones de coma flotante por segundo— 
que demandan las aplicaciones citadas. 
INTRODUCCIÓN ▪ 3 ▪ 
El paso que hay que dar es bastante claro: utilizar muchos procesadores, 
para repartir la ejecución de un programa entre ellos; es decir, utilizar 
sistemas paralelos. Además, las tecnologías de fabricación facilitan esta 
posibilidad: construido un procesador (chip), se hacen fácilmente miles de 
ellos y de manera relativamente barata. Por tanto, ¿por qué no utilizar 100, 
1.000, 10.000... procesadores para resolver un problema? Teóricamente, y si 
supiéramos cómo hacerlo, utilizando P procesadores podríamos ejecutar un 
programa P veces más rápido. Por desgracia, esto no va a ser así, ya que van 
a aparecer importantes problemas nuevos: ¿cómo se reparte el trabajo entre 
los procesadores? ¿son independientes los procesos o hay que 
sincronizarlos? ¿cómo se implementa la comunicación entre procesadores?... 
Existen muchas maneras de estructurar un computador de P procesadores. 
Algunas características serán comunes en todos ellos, y otras, en cambio, no. 
Existen diferentes formas de clasificar estas arquitecturas o estructuras. De 
entre ellas, la más conocida o utilizada es, seguramente, la de Flynn (1966), 
quizás por lo simple que es. En esta clasificación se tienen en cuenta dos 
parámetros: el número de flujos de instrucciones (es decir, el número de PCs 
o contadores de programa) y el número de flujos de datos que operan 
simultáneamente. La siguiente figura recoge dicha clasificación: 
 
 flujos de datos 
 uno muchos 
flujos de 
instrucciones 
uno SISD SIMD 
muchos MIMD 
 
• Computadores de tipo SISD (Single-Instruction-Single-Data) 
 Se ejecuta un único programa sobre un único conjunto de datos; por 
tanto, a esta clase pertenecen los sistemas clásicos de un sólo 
procesador (ordenadores personales, estaciones de trabajo…). Aunque 
en algunos casos dispongan de más de un procesador, éstos realizan el 
trabajo de manera independiente. 
 Como ya hemos comentado, las instrucciones se ejecutan de manera 
segmentada, dividida en varias fases —búsqueda, descodificación, 
lectura de operandos, memoria, unidad aritmética, escritura de 
resultados…—, y en cada fase habrá una instrucción (o varias, en el 
casode los procesadores superescalares). Así pues, se utiliza 
▪ 4 ▪ INTRODUCCIÓN 
paralelismo a nivel de instrucción (ILP, Instruction Level 
Parallelism). Además, el procesador (con ayuda del hardware o del 
compilador) es capaz de modificar el orden de ejecución de las 
instrucciones para conseguir la mayor eficiencia (velocidad) posible. 
 A lo largo del texto supondremos que todos esos conceptos son 
conocidos. 
• Computadores de tipo SIMD (Single-Instruction-Multiple-Data) 
 En este tipo de computadores se ejecuta simultáneamente el mismo 
programa en todos los procesadores, pero sobre diferentes conjuntos 
de datos; se aprovecha, por tanto, el paralelismo de datos (DLP, Data 
Level Parallelism). Dentro de este grupo podemos distinguir dos 
subgrupos: los denominados processor-array (distributed memory 
SIMD) y los procesadores vectoriales (shared memory SIMD). 
 En el primer caso, el computador dispone de muchos procesadores 
normalmente muy "simples" (por ejemplo, 16 k procesadores de un 
bit); todos los procesadores ejecutan el mismo programa de manera 
sincronizada, pero sobre datos diferentes. Se han construido muchas 
máquinas de tipo SIMD, sobre todo en los años 80-95, y para ciertas 
aplicaciones, tales como cálculo numérico, procesamiento de señal, 
etc., ofrecen muy buen rendimiento. 
 Sin embargo, hoy en día no se fabrican computadores de este modelo 
(aunque ideas similares se utilizan para generar entornos virtuales de 
dos y tres dimensiones); sí, en cambio, computadores vectoriales. 
 
• Computadores de tipo MIMD (Multiple-Instruction-Multiple-Data) 
 Es el caso general de un sistema paralelo. Se ejecutan muchos 
procesos (muchos PCs) sobre diferentes conjuntos de datos. ¡Ojo! no 
se trata de un conjunto de máquinas SISD, ya que los programas que 
se ejecutan no son independientes. 
 Este es el modelo que permite obtener elevadas velocidades de 
cómputo: computadores de paralelismo masivo, en los que P 
procesadores (un número alto) colaboran en la resolución de un 
problema; es decir, se explota el paralelismo a nivel de hilo o proceso 
(TLP, Thread Level Parallelism). En cualquier caso, surgen muchos 
problemas nuevos, a los que, si se quiere conseguir un buen 
rendimiento, habrá que buscar soluciones adecuadas. 
INTRODUCCIÓN ▪ 5 ▪ 
 Tal y como veremos en los próximos capítulos, podemos hacer una 
subclasificación en el grupo de las máquinas MIMD: 
 
• Sistemas de memoria compartida, en los que todos los 
procesadores utilizan el mismo espacio de direccionamiento. La 
memoria puede estar centralizada (SMP, symmetric 
multiprocessors) o distribuida (DSM, distributed shared 
memory). La comunicación entre procesos se realiza mediante el 
uso de variables compartidas. 
 
• Sistemas de memoria privada distribuida, en los que cada uno 
de los procesadores utiliza su espacio propio de memoria. LA 
comunicación entre procesos se realiza mediante paso de 
mensajes. 
 
 
A lo largo de los capítulos del texto vamos a analizar las máquinas 
paralelas de tipo MIMD, pero en el primero vamos a tratar sobre un tipo 
especial de computador SIMD de muy alto rendimiento: los computadores 
vectoriales. Se trata de una arquitectura de procesador específica, destinada 
al procesamiento de vectores, que ha conseguido un lugar destacado en la 
historia de la computación. En el capítulo 2 haremos una breve presentación 
de los sistemas paralelos: principales modelos y arquitecturas, problemas 
más importantes, la ley de Amdahl, etc. En el capítulo 3 analizaremos el 
problema de la coherencia de los datos en sistemas SMP; en el 4, las 
instrucciones y procedimientos básicos para sincronizar procesos paralelos: 
T&S, LL, SC...; y en el 5, los modelos de consistencia, secuencial y 
relajados, de la memoria de un sistema paralelo. En el capítulo 6, 
analizaremos la topología, estructura y funcionamiento de la red de 
comunicación de un sistema paralelo, así como la eficiencia de los 
mecanismos de comunicación entre procesadores. En el capítulo 7 
analizaremos nuevamente el problema de la coherencia de los datos, pero en 
los sistemas DSM: los directorios de coherencia. Dedicaremos el capítulo 8 a 
presentar las técnicas de paralelización de bucles y el reparto de tareas a los 
procesadores. Finalmente, en el capítulo 9 haremos un breve resumen de la 
situación actual de los sistema paralelos, analizando la lista top500, así como 
una breve presentación de las herramientas básicas para programar 
aplicaciones en paralelo: OpenMP, para los sistemas de memoria compartida 
SMP, y MPI, para el caso de paso de mensajes (en sistemas DSM o MPP). 
▪ 6 ▪ INTRODUCCIÓN 
 
 
 
 
▪ 1 ▪ 
 
 
Computadores Vectoriales 
 
 
 
 
 
 
 
 
 
1.1 ¿QUÉ ES UN COMPUTADOR VECTORIAL? 
Como hemos comentado en la introducción, las arquitecturas de tipo 
MIMD son las más adecuadas para resolver en paralelo aplicaciones de tipo 
general. Existen, sin embargo, algunos problemas importantes, desde el 
punto de vista del cálculo requerido, en los que es posible utilizar otro tipo 
de arquitecturas para lograr ejecuciones con un alto rendimiento. 
Como ya se sabe, en los programas de cálculo científico la mayor parte 
del tiempo de ejecución se invierte en la ejecución de bucles. Por ejemplo: 
 
do i = 0, N-1 
 C(i) = A(i) + B(i) 
enddo 
 
Si N es muy grande (N = 109, por ejemplo) el tiempo de ejecución de ese 
bucle será muy alto, a pesar de su estructura tan simple. Si lo ejecutamos en 
un procesador escalar, el código ensamblador será, por ejemplo, el siguiente: 
▪ 8 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
buc: FLD F1,A(R1) 
 FLD F2,B(R1) 
 FADD F3,F2,F1 
 FST C(R1),F3 
 
 ADDI R1,R1,#8 
 SUBI R2,R2,#1 
 BNZ R2,buc 
 
En un procesador escalar se ejecutaría, en el mejor de los casos, una 
instrucción por ciclo1, por lo que para ejecutar una iteración del bucle se 
necesitarían 7 ciclos; por tanto, el tiempo de ejecución de todo el programa 
sería de TE = 7N. 
El bucle anterior tiene dos características específicas. Por un lado, las 
estructuras de datos que utiliza —los vectores A, B y C— son muy regulares; 
y, por otro lado, todas las iteraciones del bucle se pueden ejecutar de manera 
independiente, ya que no existen dependencias de datos entre ellas. 
Para comenzar, definamos qué es, en este contexto, un vector. Un vector 
es una estructura que se puede definir mediante tres parámetros: 
 
• dirección de comienzo: dirección de memoria del primer elemento 
del vector. 
• longitud: número de elementos del vector. 
• paso (stride): distancia en memoria entre dos elementos consecutivos 
del vector. 
 
Por ejemplo, un vector que esté almacenado en las posiciones 1000, 1002, 
1004, 1006, 1008, 1010, 1012 y 1014 de memoria (cada componente ocupa 
una posición de memoria) se definiría así: 
 
 dirección de comienzo = 1000 longitud = 8 paso = 2 
 
Un procesador escalar, como su nombre indica, trabaja con escalares. Sin 
embargo, en las áreas de Ciencia e Ingeniería es muy común el uso de 
vectores y el tiempo de ejecución se invierte, principalmente, en la 
ejecución, una y otra vez, de bucles como el anterior. ¿Por qué no definir una 
arquitectura y un lenguaje máquina que directamente sean capaces de tratar 
con vectores? ¿Por qué no escribir el programa anterior de la siguiente 
manera? 
 
1 Si el procesador fuera superescalar, quizás se podría conseguir algo más de una instrucción por ciclo. 
1.1 ¿QUÉ ES UN COMPUTADOR VECTORIAL? ▪ 9 ▪ 
LV V1,A(R1) ; leer el vector A 
LV V2,B(R1) ; leer el vector B 
ADDV V3,V1,V2 ; sumar ambos vectores 
SV C(R1),V3 ; escribir el resultado en el vector C 
 
En este nuevo juego de instrucciones, la instrucción LV V1,A(R1) 
implicaría lo siguiente (utilizando, a modo de ejemplo, el esquema de 
segmentación que se muestra2): 
 
LV V1,A(R1) BD L AM M M M E 
 M M M E 
 M M M E 
 ... ... ... 
 M M M E 
 
Podríamos representar la ejecuciónanterior, de manera simplificada, de la 
siguiente forma: 
 
LV V1,A(R1) BD L AM M M M E E ... ... E 
 
Así pues, mediante una única instrucción leemos de memoria un vector 
completo de N elementos. Para que esto sea posible la memoria debe de estar 
segmentada, con lo que, si no existe algún otro impedimento, en cada ciclo 
proporcionará un elemento del vector, que se irán escribiendo en un registro 
vectorial. 
El siguiente esquema presenta la ejecución del programa anterior fase a 
fase (las latencias de las unidades funcionales son un simple ejemplo): 
 
LV V1,A(R1) BD L AM M M M E ... (N ciclos) ... 
LV V2,B(R1) BD L AM M M M E ... (N ciclos) ... 
ADDV V3,V1,V2 BD . . . . L A A E ... (N ciclos) ... 
SV C(R1),V3 BD L AM . . . . L M M M E ... ... E 
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... ... 14+N 
 
 ti N 
 
(Por ahora, supongamos que los operandos que necesitan las instrucciones ADDV y SV se 
pueden obtener en los ciclos 8 y 11, tal como se indica en la tabla). 
 
2 Las fases de ejecución habituales: BD, búsqueda y descodificación de la instrucción; L, lectura de los 
operandos; AM, cálculo de la dirección de memoria; A, una operación en una unidad funcional; M, una 
operación en memoria; E, escritura del resultado en los registros. Cada instrucción utiliza solamente 
las fases que necesita para su ejecución. 
▪ 10 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
Si el modelo de ejecución es ese, podemos hacer un análisis sencillo para 
obtener el tiempo de ejecución del bucle (de manera simplificada; un poco 
más adelante formalizaremos este cálculo): existe un tiempo de inicio —ti— 
antes de que la última instrucción comience a escribir, y después, para 
terminar la ejecución, se necesitan N ciclos, uno por cada elemento del 
vector. Por tanto: 
 
TV = ti + N 
 
 
Si comparamos esta expresión con la que hemos obtenido para un 
procesador escalar, la mejora es clara. Por ejemplo, si el número de 
elementos de los vectores es N = 128, y si ti = 14 ciclos, tendríamos los 
siguientes tiempos de ejecución: 
 
TE = 7 N = 896 ciclos 
TV = ti + N = 142 ciclos (un 16%) 
 
No es ésta la única ventaja. Por un lado, han desaparecido las 
dependencias de control3 debida al bucle, ya que, por definición, ha 
desaparecido el propio bucle. Por otro lado, sólo se han ejecutado 4 
instrucciones, y no las 7N que componían el bucle escalar. Esto implica que 
el uso de la cache de instrucciones es mucho más bajo, y, por consiguiente, 
el tráfico en el bus también. 
Pero, por supuesto, todas esas ventajas no salen “gratis”. A decir verdad, 
tenemos que analizar con más detalle el esquema de ejecución anterior, para 
conocer los recursos que se necesitan para poder ejecutar de esa manera las 
instrucciones vectoriales. 
1.1.1 Algunos problemas 
1.1.1.1 La memoria de un computador vectorial 
Un procesador vectorial utiliza la memoria de modo intensivo. Por 
ejemplo, en el caso anterior tenemos 3 instrucciones, 2 LV y 1 SV, que están 
utilizando simultáneamente la memoria y, además, cada instrucción realiza N 
accesos a memoria. Por tanto, hay que solucionar dos aspectos: 
 
3 Las responsables de las dependencias de control son las instrucciones de salto. En general, después 
de la instrucción de dirección i se ejecuta la instrucción de dirección i+1, salvo en el caso de los 
saltos. Cuando ejecutamos un salto no sabemos qué instrucción será la siguiente hasta que el salto 
termine, por lo que hay que parar al procesador (aunque existen muchas técnicas para evitar esos 
ciclos "muertos"). 
1.1 ¿QUÉ ES UN COMPUTADOR VECTORIAL? ▪ 11 ▪ 
1. ¿Cuántos buses hay para acceder a memoria? El procesador y el 
sistema de memoria se comunican mediante el bus de datos. Una 
operación vectorial de memoria va a ocupar el bus de datos durante N 
ciclos (supongamos que se transfiere una palabra por ciclo). Por tanto, 
si sólo hubiera un bus, sólo una instrucción podría acceder a memoria 
en cada momento, y todas las demás deberían esperar a que ésta 
terminara. Por consiguiente, el tiempo de ejecución no sería de orden 
N, sino de kN (con k = 2, 3, 4..., número de instrucciones de memoria). 
 
2. ¿No habrá conflictos en el uso de los módulos de memoria? A pesar 
de que el espacio de memoria esté entrelazado entre los diferentes 
módulos de memoria, puede suceder que en un momento determinado 
se necesite acceder a elementos de vectores almacenados en el mismo 
módulo. Si sucede esto, para poder comenzar un acceso habrá que 
esperar a que termine el anterior acceso al mismo módulo, con lo que 
aumentará el tiempo de ejecución. 
 
Queda claro que el sistema de memoria de un computador vectorial juega 
un papel muy importante en el rendimiento final del sistema: hacen falta 
múltiples buses, y la memoria debe estar entrelazada en muchos módulos, 
para reducir los conflictos de acceso a los mismos. 
1.1.1.2 Unidades funcionales vectoriales 
Analizando el esquema de ejecución anterior, queda claro que las 
unidades funcionales deben estar segmentadas. Una única instrucción 
(ADDV, por ejemplo) realiza N operaciones en la unidad funcional, una por 
ciclo. Si no estuviera segmentada, no sería posible generar un dato por ciclo. 
De la misma manera, parece necesario poder disponer de varias unidades 
funcionales de cada tipo, ya que una instrucción ocupa cada unidad 
funcional durante N ciclos. 
1.1.1.3 Registros vectoriales 
¿Qué es un registro vectorial? ¿De qué tamaño son? ¿Cómo se leen y se 
escriben? En un registro vectorial se guardan los elementos de un vector. 
Cada elemento, normalmente, será un escalar representado en coma flotante, 
por ejemplo en 64 bits. Por tanto, en un registro tendremos 64 × N bits. El 
tamaño de los registros es, en todo caso, limitado. Es habitual que un registro 
vectorial permita almacenar 64 o 128 (Lmax) elementos de un vector, con lo 
▪ 12 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
que su capacidad sería de 64 (o 128) × 64 = 4 (u 8) kilobits. Si nos fijamos 
en el tamaño, se comprende fácilmente que no se disponga de un número 
muy elevado de registros vectoriales. Normalmente dispondremos de 8-16 
registros (16 × 8 = 128 kilobits). En algunas máquinas, el tamaño de los 
registros es variable; es decir, el "espacio de memoria" de que se dispone se 
puede utilizar para definir muchos registros de pocos elementos o unos 
pocos de muchos elementos. 
 
 
 
 
 
¿Qué se debe hacer cuando la longitud de los vectores que tenemos que 
procesar es mayor que Lmax (64 o 128 elementos)? No hay más remedio que 
formar un bucle, y en cada iteración del mismo procesar Lmax elementos 
(strip mining). Por tanto, aparecen de nuevo las dependencias de control, 
aunque esta vez cada 64 (128) elementos. 
En los primeros computadores vectoriales los registros se trataban como 
una “unidad”, por lo que no era posible leer y escribir sobre el mismo 
registro a la vez. Hoy en día, los elementos que conforman un registro 
vectorial se tratan como unidades independientes que pueden direccionarse 
de manera separada, con lo que es posible acceder a los primeros elementos 
de un vector ya almacenados en un registro mientras se sigue escribiendo el 
resto de elementos. Por otro lado, dado que diferentes instrucciones irán 
produciendo datos para escribir en el banco de registros vectoriales, y que 
cada una de ellas necesitará muchos ciclos para escribir el vector resultado, 
serán necesarios varios (muchos) buses de escritura (evidentemente, también 
se necesitan “muchos” buses de lectura). Con todo ello, el banco de registros 
de un procesador vectorial resulta ser un dispositivo complejo. 
1.1.1.4 Programas vectoriales 
¿Qué tipo de programas se pueden ejecutar en un computador vectorial? 
Los procesadores vectoriales están optimizados para procesar vectores, pero 
en los programas reales, además de procesar vectores, habrá que procesar 
código escalar.¿Cómo se hace eso? ¿Qué influencia tiene en la velocidad de 
cálculo? (como veremos, el efecto del código escalar puede ser muy grande). 
registros vectoriales U.F. 
1.1 ¿QUÉ ES UN COMPUTADOR VECTORIAL? ▪ 13 ▪ 
Analicemos de nuevo qué se hace cuando se procesan vectores. Veamos el 
siguiente ejemplo: 
 
do i = 0, N-1 
 A(i) = A(i) + 1 
enddo 
 
Si se ejecutara escalarmente, y simplificando, el orden de ejecución de las 
diferentes operaciones sería el siguiente (L = load; S = store; + = suma; i = 
elemento del vector): 
 
L0 +0 S0 / L1 +1 S1 / L2 +2 S2 / L3 +3 S3 / ... / LN–1 +N–1 SN–1 
 
Si lo ejecutáramos vectorialmente (LV - ADDV - SV), el orden pasaría a 
ser el siguiente: 
 
L0 L1 L2 ... LN–1 / +0 +1 +2 ... +N–1 / S0 S1 S2 ... SN–1 
 
Esto es, la ejecución vectorial implica desordenar el código original. Y 
como ya sabemos, esto no siempre es posible, ya que hay que respetar las 
dependencias de datos entre las instrucciones. Por tanto, para decidir si un 
programa se puede ejecutar vectorialmente o no, hay que hacer un 
meticuloso análisis de las dependencias, tarea que, como veremos, va a 
recaer, en gran medida, en un buen compilador vectorial. 
Resumiendo todo lo anterior: aunque hemos definido un modelo de 
computador con un rendimiento teórico muy elevado, en la realidad tenemos 
que superar muchos problemas para poder llegar a esa velocidad de cálculo. 
1.1.2 Arquitectura y lenguaje máquina 
Existen diferentes arquitecturas para los computadores vectoriales, casi 
tantas como fabricantes. En los primeros diseños, los computadores 
vectoriales no tenían registros, y todas las operaciones se hacían con los 
operandos en memoria. A este modelo se le denomina "Memoria-Memoria" 
(M/M). Pero pronto se añadieron los registros vectoriales; como 
consecuencia, los operandos de las operaciones vectoriales se obtienen de 
registros y los resultados se dejan en registros (modelo R/R). 
En la siguiente figura se muestra un esquema lógico, muy simple, de un 
computador vectorial. Podemos distinguir dos secciones: la sección escalar y 
la vectorial. El procesador escalar se encarga de la búsqueda y 
descodificación de las instrucciones. Si la instrucción es escalar, la ejecuta él 
▪ 14 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
mismo, utilizando los registros escalares necesarios; pero si es vectorial, 
pasa el control al procesador vectorial para que la ejecute. Salvo que 
especifiquemos alguna otra opción, vamos a suponer que la unidad de 
control es de tipo Tomasulo (desorden/desorden). 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Tal y como hemos comentado, aunque vamos a trabajar con vectores, en 
la realidad tendremos una mezcla de código vectorial y escalar. Por tanto, 
tendremos que utilizar tanto instrucciones vectoriales como escalares. Las 
instrucciones escalares son las habituales en cualquier procesador RISC. En 
función del computador, existen diferentes juegos de instrucciones 
vectoriales y de formatos de instrucciones; las más habituales son las 
siguientes (más tarde veremos algunas otras): 
 
OPV Vi,Vj,Vk Vi = Vj OP Vk 
 (OP = ADD, SUB, MUL, DIV...) 
 Operación entre dos vectores. El resultado es otro 
vector. 
 
OPVS Vi,Vj,Fk Vi = Vj OP Fk 
OPVI Vi,Vj,#inm Vi = Vj OP #inm 
 (OP = ADD, SUB, MUL, DIV...) 
 Operación entre un vector y un escalar. El 
resultado es un vector. 
 
 
Registros 
 
 
Unidades 
funcionales 
Procesador 
escalar 
(completo) 
Control del 
procesador 
vectorial 
Unidad de 
direcciones 
(datos) 
M
em
o
ri
a 
(op.) 
1.2 DEPENDENCIAS DE DATOS ▪ 15 ▪ 
LV Vi,A(Rj) Se lee a partir de la dirección de memoria A+Rj 
un vector, y se deja en el registro Vi (puede 
haber más modos de direccionamiento). 
 
SV A(Rj),Vi Similar a la anterior, pero, en lugar de leer, 
escribe un vector en memoria. 
 
Para identificar un vector en memoria, hay que dar tres parámetros: 
dirección de comienzo, longitud y paso. La dirección de comienzo se indica 
en la propia instrucción LV/SV (de acuerdo al modo de direccionamiento que 
se utilice). La longitud del vector y el paso, en cambio, hay que indicarlos 
previamente a la operación de lectura o escritura. Para ello utilizaremos dos 
registros especiales: VL (vector length), para indicar el número de elementos 
del vector, su longitud, y VS (vector stride), para indicar el paso. Si el 
contenido de VL es mayor que Lmax (tamaño de los registros vectoriales), 
sólo se procesarán Lmax elementos. 
Así pues, tenemos que ejecutar las siguientes instrucciones para, por 
ejemplo, leer un vector: 
 
 MOVI VL,#64 ; los vectores son de 64 elementos 
 MOVI VS,#8 ; el paso es 8 
 LV V1,A(R1) 
 
De esta manera se cargarán en el registro V1 64 elementos de un vector, 
correspondientes a las direcciones A+R1, A+R1+8, A+R1+16… 
En algunos computadores es necesario indicar explícitamente el paso de 
los vectores en la propia instrucción, utilizando para ello un registro de 
propósito general. 
 
1.2 DEPENDENCIAS DE DATOS 
Al igual que sucede con los procesadores (super)escalares, la velocidad de 
cálculo de los procesadores vectoriales está limitada por las dependencias de 
datos. Una instrucción depende de otra anterior si uno de sus operandos es el 
resultado de dicha instrucción, por lo que deberá esperar a que finalice antes 
de poder ejecutarse. Ya sabemos que, en los procesadores escalares, para 
▪ 16 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
atenuar la pérdida de rendimiento debida a las dependencias de datos se 
utilizan cortocircuitos (forwarding) entre las unidades funcionales; una idea 
similar se aplica también en los procesadores vectoriales. 
Para los siguientes ejemplos utilizaremos el siguiente esquema de 
segmentación (Tomasulo): 
 
 LV/SV → BD L AM M M M E 
 ADDV → BD L A A E 
1.2.1 Encadenamiento (chaining) 
Se dice que dos instrucciones se encadenan si la segunda utiliza el vector 
generado por la primera sin esperar a que ésta lo haya guardado en el 
registro vectorial. Veamos un ejemplo sencillo: 
 
do i = 0, N-1 LV V1,A(R1) 
 A(i) = A(i) + 1 → ADDVI V2,V1,#1 
enddo SV A(R1),V2 
 
El bucle presenta dependencias de datos muy claras: LV → ADDVI (V1) y 
ADDVI → SV (V2). Entonces ¿cómo se ejecutará ese programa? Tenemos 
dos alternativas: sin realizar encadenamiento entre las dos instrucciones, o 
encadenándolas. 
 
a. Si no se realiza encadenamiento, la segunda instrucción deberá esperar 
a que termine la primera, para poder leer el registro vectorial 
correspondiente (V1). En la figura se muestra un esquema de 
ejecución, en el que se puede ver cuándo se realizan las lecturas (L). 
 
LV V1,A(R1) BD L AM M M M E ... E 
ADDVI V2,V1,#1 BD . . . . . ... . L A A E ... E 
SV A(R1),V2 BD L AM . . ... . . . . . ... . L M M M E ... 
ciclos ← 6 → ← N → ← 3 → ← N → ← 4 → ← N 
 
 Por tanto, el tiempo de ejecución en este caso es TV = 13 + 3N ciclos. 
 
b. En cambio, si se realiza encadenamiento, según se van generando los 
vectores se van utilizando en la siguiente unidad funcional; es decir, se 
utiliza el cortocircuito E → L. 
1.2 DEPENDENCIAS DE DATOS ▪ 17 ▪ 
LV V1,A(R1) BD L AM M M M E E ... (N cicl.) ... 
ADDVI V2,V1,#1 BD . . . . L A A E E ... (N cicl.) ... 
SV A(R1),V2 BD L AM . . . . L M M M E ... ... E 
ciclos ← 6 → ← 3 → ← 4 → ← N → 
 
 En este segundo caso, el tiempo de ejecución es TV = 13 + N ciclos. 
 
Podemos analizar el mismo comportamiento de manera cualitativa. Por 
ejemplo, la siguiente figura muestra un esquema de ejecución muy 
simplificado del programa anterior (LV / ADDVI / SV), en función de si se 
encadenan o no las instrucciones: 
 
 
 
 
 sin encadenamiento: T ~ 3N con encadenamiento: T ~ N 
 
La diferencia entre ambas opciones es clara. En el primer caso, el tiempo 
de ejecución es del orden de 3N; en el segundo, en cambio, es deorden N. 
Por ejemplo, para N = 64 el tiempo de ejecución bajaría de 13 + 3×64 = 205 
ciclos a 13 + 64 = 77 ciclos (un 38%). Así pues, necesitamos poder 
encadenar las instrucciones para conseguir un buen rendimiento. 
 
1.2.1.1 Encadenamiento con dos instrucciones 
En el ejemplo del apartado anterior, el encadenamiento se ha realizado 
con una única instrucción anterior: la instrucción ADDVI con la instrucción 
LV, o la instrucción SV con la instrucción ADDVI. En un caso más general, 
tendríamos que poder encadenar una instrucción con dos instrucciones 
anteriores. Veamos un ejemplo (C = A + B): 
 
LV V1,A(R1) BD L AM M M M E E ... (N ciclos) ... 
LV V2,B(R1) BD L AM M M M E E ... (N ciclos) ... 
ADDV V3,V1,V2 BD . . . . L A A E E ... (N ciclos) ... 
SV C(R1),V3 BD L AM . . . L M M M E ... ... E 
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 14+N 
LV 
ADDVI 
SV 
ADDVI 
SV 
LV 
▪ 18 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
La tercera instrucción (ADDV) necesita los vectores V1 y V2, que son 
generados por las dos primeras instrucciones respectivamente. Pero estos dos 
vectores no se generan sincronizados: el primero se comienza a generar en el 
ciclo 7 y el segundo en el 8 (y a partir de ahí el resto de elementos). Por 
tanto, en el ciclo 7 no está preparado el primer elemento del segundo 
operando (V2), y en el ciclo 8 se pierde la posibilidad de tomar el primer 
elemento del primer operando (V1) (los datos no se “pierden”, claro ya que 
se están cargando en el registro vectorial). ¿Qué se puede hacer? 
Para poder efectuar el encadenamiento hay que coger un operando según 
sale de la unidad funcional y leer el otro del registro correspondiente (V1), 
donde ya se está escribiendo. Para ello es necesario que el banco de registros 
permita la lectura y escritura simultánea del mismo registro (lo habitual en 
las máquinas vectoriales actuales, y que se conoce como flexible chaining o 
encadenamiento flexible); si eso no es posible, se perderá la posibilidad de 
encadenar (salvo que se aplique alguna otra solución) y habrá que esperar a 
que finalice la escritura de ambos operandos. 
1.2.2 Tablas de ejecución de las instrucciones 
Representar los esquemas de ejecución de un conjunto de instrucciones 
vectoriales fase a fase es un poco pesado. Por ello, en lugar de hacer ese tipo 
de esquemas, vamos a resumir en una tabla las acciones principales que 
suceden cuando se ejecutan las instrucciones: 
 
• Inicio de ejecución: cuántos ciclos han pasado, desde el comienzo, 
hasta el momento previo a iniciar la operación en la UF. El inicio 
puede ser tras la lectura de los registros, o mediante encadenamiento, 
en cuyo caso indicaremos el número de ciclos entre [ ]. 
 (La ejecución de instrucciones es segmentada, y las instrucciones se ejecutan de una 
en una, no es superescalar.) 
• Latencia de la unidad funcional. 
• Ciclo en el que se genera el primer elemento. 
• Ciclo en el que se genera el último (N) elemento. 
 
Por ejemplo, para una instrucción LV la tabla correspondiente sería: 
 
BD L AM M M M E ... ... E 
comienzo (3) lat. UF (3) dato 1 (6+1) dato N (6+N) 
1.2 DEPENDENCIAS DE DATOS ▪ 19 ▪ 
Las ejecuciones de los dos ejemplos anteriores se pueden resumir así: 
 
 sin encadenamiento con encadenamiento 
A = A + 1 inic. lat. UF dato 1 dato N inic. lat. UF dato 1 dato N 
LV V1,A(R1) 3 3 6+1 6+N 3 3 6+1 6+N 
ADDVI V2,V1,#1 6+N+1 2 9+N+1 9+2N [7] 2 9+1 9+N 
SV A(R1),V2 9+2N+1 3 13+2N+1 13+3N [10] 3 13+1 13+N 
 
Si la ejecución de las instrucciones no se encadena, la instrucción ADDVI 
tiene que esperar a que termine la escritura en el registro V1 (ciclo 6+N) y 
luego leer del registro (+1). Lo mismo le sucede a la instrucción SV: tiene 
que esperar a que la instrucción ADDVI termine (9+2N), y entonces leer V2 
y escribir en memoria. 
Si la ejecución de las instrucciones se encadena, la suma puede comenzar 
en el ciclo 7 (en ese ciclo llega de memoria el primer elemento del vector), y 
la escritura en memoria puede comenzar en el ciclo 10 (ciclo en que la suma 
genera el primer dato). 
 
En el segundo ejemplo podemos observar el mismo comportamiento. Si 
no se puede encadenar, la instrucción ADDV tiene que esperar a tener listos 
ambos operandos (ciclo 7+N) y entonces leerlos. Cuando se encadena, uno 
de los operandos (V2) se obtiene directamente de la memoria y el otro (V1) 
del registro (donde se ha escrito en el ciclo anterior); el ciclo de 
encadenamiento es, por tanto, el ciclo 8. 
 
 sin encadenamiento con encadenamiento 
C = A + B inic. lat. UF dato 1 dato N inic. lat. UF dato 1 dato N 
LV V1,A(R1) 3 3 6+1 6+N 3 3 6+1 6+N 
LV V2,B(R1) 4 3 7+1 7+N 4 3 7+1 7+N 
ADDV V3,V1,V2 7+N+1 2 10+N+1 10+2N [8] 2 10+1 10+N 
SV C(R1),V3 10+2N+1 3 14+2N+1 14+3N [11] 3 14+1 14+N 
 
Nota: estamos aplicando un modelo “didáctico” de ejecución vectorial, y el objetivo 
es mostrar el comportamiento general, no los detalles particulares. Lo computadores 
comerciales utilizan estrategias similares, aunque los detalles de implementación 
pueden variar. 
▪ 20 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
1.3 DEPENDENCIAS ESTRUCTURALES 
Después de analizar las dependencias de datos, analicemos las 
dependencias estructurales. Recuerda que un conflicto o dependencia 
estructural surge cuando se quiere utilizar un recurso mientras está ocupado 
por otra instrucción. Además de las unidades funcionales, el recurso más 
importante en un computador vectorial es la memoria. Para poder utilizar la 
memoria, primeramente hay que disponer de un bus libre. ¿Cuántos buses 
tenemos para acceder a la memoria? Por otro lado, se utilizan los propios 
módulos de memoria. ¿Están libres los módulos que hay que utilizar? Si 
están ocupados, ¿cuánto tiempo hay que esperar? 
1.3.1 Buses de memoria (unidades funcionales LV/SV) 
La ejecución de las instrucciones LV y SV implica una transferencia con 
memoria en la que se utilizan los buses. Cuando se ejecuta una instrucción 
LV o SV, el bus se ocupa durante N ciclos; mientras una instrucción está 
utilizando el bus, la siguiente deberá esperar hasta que se libere el bus. Por 
tanto, si el computador no tuviera un número suficiente de buses, la 
velocidad de cálculo de la máquina no sería muy alta. 
Analicemos la influencia del número de buses mediante el ejemplo 
anterior (A = A + 1; LV / ADDVI / SV). Supongamos que la máquina puede 
encadenar las instrucciones, pero que sólo posee un bus para trabajar con 
memoria (LV o SV)4. En estas condiciones, cuando la instrucción SV quiere 
empezar a escribir en memoria, en el ciclo de encadenamiento, el bus no está 
disponible, ya que lo ocupa la instrucción LV (y lo mantendrá ocupado 
muchos ciclos). Por tanto, deberá esperar hasta que termine la primera 
instrucción (y se libere el bus) y leer entonces el registro en el que se están 
escribiendo los resultados (V2)5. 
Este sería el esquema de ejecución: 
 
 
 
4 Los buses de memoria pueden usarse tanto para una lectura como para una escritura; en algunas 
máquinas, en cambio, los buses están "dedicados": unos son sólo para leer y otros sólo para escribir. 
5 Si no puede leerse un registro mientras se está escribiendo, entonces habrá que esperar a que finalice 
la escritura. 
1.3 DEPENDENCIAS ESTRUCTURALES ▪ 21 ▪ 
LV V1,A(R1) BD L AM M M M E E ... (N ciclos) ... E 
ADDVI V2,V1,#1 BD . . . . L A A E E ... (N ciclos) ... E 
SV A(R1),V2 BD L AM . . . . ? . ... ... L M M M E ... (N cicl.) 
 bus ocupado... libre 
 
o, esquemáticamente: 
 
 
 
 
La tabla correspondiente a la ejecución sería la siguiente: 
 
 un bus / encadenamiento 
A = A + 1 inic. lat. UF dato 1 dato N 
LV V1,A(R1) 3 3 6+1 6+N 
ADDVI V2,V1,#1 [7] 2 9+1 9+N 
SV A(R1),V2 [6+N] 3 9+N+1 9+2N 
 
Repitamos el análisis, pero con el segundo ejemplo que hemos visto antes. 
En ambos casos, las instrucciones se encadenan, pero en el primer caso la 
máquinacuenta con un solo bus de memoria, y en el otro caso cuenta con 
dos buses. 
 
 un bus / encadenamiento dos buses / encadenamiento 
C = A + B inic. lat. UF dato 1 dato N inic. lat. UF dato 1 dato N 
LV V1,A(R1) 3 3 6+1 6+N 3 3 6+1 6+N 
LV V2,B(R1) 6+N 3 9+N+1 9+2N 4 3 7+1 7+N 
ADDV V3,V1,V2 [10+N] 2 12+N+1 12+2N [8] 2 10+1 10+N 
SV C(R1),V3 [9+2N] 3 12+2N+1 12+3N [6+N] 3 9+N+1 9+2N 
 
Cuando sólo hay un bus, la segunda instrucción LV no puede utilizar la 
memoria hasta que el primer LV la deje de utilizar, y lo mismo le sucede a la 
instrucción SV (para cuando se libera el bus, la escritura en el registro V3 
está terminando). Por tanto, el tiempo de ejecución es de orden 3N. Si la 
ADDVI 
SV 
LV 
T ~ 2N 
▪ 22 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
máquina tiene dos buses, las instrucciones LV se ejecutarán a la vez, pero la 
instrucción SV tendrá que esperar. 
Esquemáticamente: 
 
 
 
 
 un bus / encadenamiento: 3N dos buses / encadenamiento: 2N 
 
La conclusión es sencilla: si no existen suficientes recursos (buses) para 
poder ejecutar las instrucciones de memoria, a pesar de tener la posibilidad 
de encadenar las instrucciones el tiempo de ejecución será elevado. 
 
En resumen, los resultados que hemos obtenido con ambos ejemplos son 
los siguientes: 
 
1. A = A + 1 (N = 64) 
sin encadenamiento 13 + 3N = 205 ciclos → 3,20 ciclos/dato 
encadenamiento / 1 bus 9 + 2N = 137 ciclos → 2,14 c/d 
encadenamiento / 2+ buses 13 + N = 77 ciclos → 1,20 c/d 
 
2. C = A + B (N = 64) 
sin encadenamiento / 1 bus 16 + 4N = 272 ciclos → 4,25 c/d 
sin encadenamiento / 3 buses 14 + 3N = 206 ciclos → 3,22 c/d 
encadenamiento / 1 bus 12 + 3N = 204 ciclos → 3,19 c/d 
encadenamiento / 2 buses 9 + 2N = 137 ciclos → 2,14 c/d 
encadenamiento / 3 buses 14 + N = 78 ciclos → 1,22 c/d 
 
Los datos muestran claramente la importancia de disponer de suficientes 
buses a memoria y de que las instrucciones puedan encadenarse para que las 
instrucciones se ejecuten eficientemente. 
1.3.2 Conflictos en el uso de los módulos de memoria 
1.3.2.1 Una sola operación de memoria 
Tras haber analizado el problema de los buses en un procesador vectorial, 
analicemos ahora el uso de la propia memoria. La memoria de cualquier 
computador está entrelazada en varios módulos; así, las direcciones i e i+1 
LV 
LV 
SV 
ADDV 
LV 
LV 
SV 
ADDV 
1.3 DEPENDENCIAS ESTRUCTURALES ▪ 23 ▪ 
no corresponden al mismo módulo de memoria, sino a módulos 
consecutivos. De esta manera es posible, por ejemplo, efectuar una 
operación simultánea en dos (en general nm, el número de módulos) 
direcciones consecutivas; si estuvieran en el mismo módulo tendríamos que 
esperar a que finalizara una operación antes de empezar con la siguiente. 
Cuando se ejecuta una instrucción LV o SV se efectúan N lecturas o 
escrituras en memoria, una por ciclo. Para que se haga de manera eficiente, 
es necesario que se acceda a módulos que estén libres; si no, tendríamos un 
conflicto estructural, y no lograríamos efectuar una operación por ciclo. 
Veamos el problema con un ejemplo. Hay que leer el vector A(A0:A15); la 
memoria está entrelazada en 4 módulos, y el vector se encuentra en módulos 
consecutivos (s = 1) a partir de m0. La latencia de la memoria es de 3 ciclos. 
La situación de la memoria según se lee el vector A es la siguiente: 
 
m0 m1 m2 m3 
A0 A1 A2 A3 
A4 A5 A6 A7 
A8 A9 A10 A11 
A12 A13 ... 
 
→ tiempo (ciclos) 
m0 M M M M M M ... 
m1 M M M M M M ... 
m2 M M M M M M 
m3 M M M M M M 
 
La lectura comienza en m0, y sigue en m1, m2, m3, y se vuelve a m0, 
para seguir leyendo más elementos del vector. En ese momento, m0 está 
libre, puesto que ya ha terminado el primer acceso, y por tanto no tendremos 
ningún problema. 
Pero si, por ejemplo, la latencia de la memoria fuera de 8 ciclos, al ir a 
utilizar nuevamente m0 lo encontraríamos ocupado, ejecutando todavía la 
operación anterior. Tendríamos, por tanto, que esperar a que finalizara antes 
de poder seguir leyendo el vector. Como consecuencia del conflicto 
estructural, el tiempo de ejecución de la operación sería más alto. 
El problema puede ser grave, en función de la definición del vector. Por 
ejemplo, si el paso del vector del ejemplo anterior fuera s = 4, entonces todos 
los elementos del vector estarían en el mismo módulo, m0: todos los accesos 
significarían un conflicto, ya que cada acceso dura 3 ciclos. 
▪ 24 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
Para analizar si surgirán o no conflictos en memoria, hay que considerar 
tres parámetros: el tiempo de acceso o latencia de la memoria —tm—, el 
número de módulos en que está entrelazada la memoria —nm—, y el paso 
de los vectores —s—. Dos de esos parámetros, latencia y número de 
módulos, son decisiones de diseño: se deciden al construir la máquina y no 
son modificables por el usuario. El tercero, en cambio, el paso de los 
vectores, corresponde al programa concreto que se ejecuta, y puede 
modificarse para intentar evitar conflictos. 
Cuando s = 1, se utilizan todos los módulos de memoria al acceder a un 
vector (m0-m1-m2-...). Por tanto, para que no haya conflictos se debe 
cumplir que: 
 
mtnm ≥ 
De esa manera, cuando hay que reutilizar un determinado módulo ya han 
pasado al menos nm ciclos, y por tanto estará libre. 
Para el caso general, s > 1, hay que calcular cuántos módulos se utilizan 
en una determinada operación. Por ejemplo, en el caso anterior, cuando s = 
4, sólo se utiliza un módulo de memoria, siempre el mismo (m0). Puede 
demostrarse fácilmente que el número de módulos que se utilizan en una 
operación de memoria es: 
),( snmMCD
nm
 (MCD = máximo común divisor) 
Así pues, y generalizado el resultado anterior, no habrá conflictos en 
memoria si el número de módulos que se van a utilizar es mayor o igual que 
la latencia: 
mtsnmMCD
nm
≥
),( 
 
Analizando la expresión anterior. se observa que la mejor situación se 
corresponde con el caso MCD(nm,s) = 1, es decir cuando, nm y s son primos 
entre sí, ya que se utilizan todos los módulos de memoria. En los casos más 
habituales, nm es una potencia de 2 (8, 16, 32, 64...). En esos casos, y si no 
hay conflicto cuando s = 1, no habrá conflictos para cualquier vector de paso 
impar (1, 3, 5...), pero podría haberlos para los casos de s par. 
Existe una situación óptima. Si el número de módulos de memoria, nm, es 
un número primo, entonces cualquier paso s será primo con él (salvo sus 
múltiplos). Por ejemplo, si nm = 5, no hay problemas con los vectores de 
1.3 DEPENDENCIAS ESTRUCTURALES ▪ 25 ▪ 
paso s = 1, 2, 3, 4, 6, 7, 8... Por desgracia, cuando la memoria se entrelaza en 
un número primo de módulos, 17 por ejemplo, calcular el módulo y la 
dirección dentro del módulo que corresponden a una palabra dada es una 
operación “compleja” (operación que debe realizar el controlador de 
memoria, para efectuar cualquier acceso a memoria), ya que habrá que 
efectuar una división para obtener el cociente y el resto (cuando nm = 2i, los 
i bits de menos peso indican el módulo, y el resto la dirección dentro del 
módulo). Debido a esa división, no se suele entrelazar la memoria en un 
número primo de módulos. 
El valor de s es muy variable en los programas vectoriales. Por ejemplo, al 
procesar matrices pueden definirse diferentes tipos de vectores: filas, 
columnas, diagonales... Para multiplicar dos matrices, por ejemplo, hay que 
usar filas en una y columnas en la otra. En algunos casos, para optimizar el 
acceso a memoria, las matrices no se guardan en posiciones consecutivas de 
memoria, sino que se dejan huecos sin ocupar (padding). 
Veamos un ejemplo de la utilidad de esta estrategia. Sea una memoria 
entrelazada en 4 módulos y una matriz de tamaño 4×4, de la que se van a 
utilizar las filas y las columnas. Como puede verse, no hay problemas en el 
acceso a una fila (s = 1), ya que los elementos están en módulos de memoria 
diferentes, pero el acceso a cualquier columna es muy conflictivo,ya que 
todos los elementos están en el mismo módulo de memoria. Sin embargo, si 
se dejan huecos en memoria entre los elementos de la matriz (en la tabla se 
muestra un ejemplo), entonces es posible acceder tanto a filas (s = 1) como a 
columnas (ahora s = 5) sin conflictos (aunque se generen conflictos en el 
acceso a las diagonales6). 
 
m0 m1 m2 m3 m0 m1 m2 m3 
A00 A01 A02 A03 A00 A01 A02 A03 
A10 A11 A12 A13 → - A10 A11 A12 
A20 A21 A22 A23 A13 - A20 A21 
A30 A31 A32 A33 A22 A23 - A30 
 A31 A32 A33 - 
 
sf = 1 sin conflictos sf = 1 sin conflictos 
sc = 4 conflictos (todos en m0) sc = 5 sin conflictos 
sD = 5 sin conflictos sD = 6 conflictos 
sd = 3 sin conflictos sd = 4 conflictos 
 
6 Como hemos comentado, el ideal sería que nm fuera un número primo. Por ejemplo, si nm fuera 5, 
los cuatro vectores del ejemplo (f, c, D y d) podrían accederse sin problemas si se dejan los 
correspondientes huecos (lo dejamos como ejercicio para el lector). 
▪ 26 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
1.3.2.2 Varias operaciones de memoria 
Como acabamos de ver, la ejecución de una instrucción vectorial de 
memoria, LV o SV, puede producir problemas en el acceso a los módulos de 
memoria. Lo mismo ocurre cuando se están ejecutando más de una 
instrucción de memoria. Aunque cada una de ellas no tuviera conflictos 
consigo misma, es posible que existan colisiones entre ellas; es decir, que 
una segunda instrucción quisiera utilizar un módulo de memoria ocupado en 
ese instante por otra instrucción. 
Analicemos el problema mediante un ejemplo. Supongamos que la 
memoria está entrelazada en 8 módulos y que la latencia es 3 ciclos (con el 
mismo esquema de segmentación de los ejemplos anteriores). Hay 
suficientes buses a memoria y las instrucciones pueden encadenarse. El 
primer elemento de A esta en el módulo m0 y el paso es s = 1. 
 
 2 buses / encadenamiento 
A = A + 1 inic. lat. UF dato 1 dato N 
LV V1,A(R1) 3 3 6+1 6+N 
ADDVI V2,V1,#1 [7] 2 9+1 9+N 
SV A(R1),V2 [10] 
 
Como hemos visto antes, la instrucción SV puede encadenarse en el ciclo 
10, e ir a memoria. Pero, ¿cómo se encuentran en ese momento los módulos 
de memoria, libres u ocupados? El esquema siguiente muestra el uso de los 
módulos de memoria ciclo a ciclo. La instrucción LV comienza la lectura en 
el ciclo 4, en el módulo m0, por ejemplo. Supongamos, por simplificar el 
problema, que el paso de A es 1. Por tanto, tras el módulo m0 se accederá a 
m1, m2..., m7, y nuevamente a m0, m1... Dado que la latencia es 3 ciclos, la 
instrucción no tiene ningún conflicto consigo misma (nm ≥ tm). 
 
 t (ciclos) 
mem. 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
m0 M M M - M M M m m m 
m1 M M M - - M M M m m m 
m2 M M M M M M 
m3 M M M M M M 
m4 M M M M M M 
m5 M M M M M M 
m6 M M M M M 
m7 M M M M 
1.3 DEPENDENCIAS ESTRUCTURALES ▪ 27 ▪ 
La instrucción SV puede encadenarse en el ciclo 10, para empezar en 
memoria en el ciclo 11, en el módulo m0 (hay que guardar el mismo vector, 
A). ¿Cómo se encuentra en ese momento ese módulo? La instrucción LV está 
en ejecución, y mantiene ocupados varios módulos. Primeramente debemos 
calcular qué módulo va a acceder LV en ese ciclo, para lo que basta con 
saber cuántos ciclos lleva ya en memoria y de qué módulo partió. En este 
ejemplo, la distancia en ciclos es de 10 – 3 = 7, y dado que partió del módulo 
m0 (y que s = 1), en el ciclo 11 irá a utilizar el módulo m7. Ese módulo, por 
tanto, no estará disponible. 
Pero habrá más módulos ocupados, ya que todavía estarán ejecutándose 
accesos que comenzaron en ciclos anteriores. Si la latencia de la memoria es 
tm, se mantiene ocupados tm–1 módulos anteriores. En el ejemplo tm = 3, 
por lo que tendremos dos módulos ocupados, m6 y m5. Utilizando el mismo 
razonamiento, es necesario dejar libres por delante otros tm–1 módulos, para 
que la instrucción LV pueda seguir ejecutándose sin interferencias; en el 
ejemplo, los módulos m0 y m1 (si no, LV “chocaría” con SV en el siguiente 
ciclo). 
Así pues, en este ejemplo en el ciclo 11 están ocupados o reservados los 
módulos <m5 – m6 – m7 – m0 – m1>. Si alguna instrucción quiere utilizar 
esos módulos, deberá esperar a que se liberen. Ése es el caso de la 
instrucción SV, que tiene que utilizar m0, y que tendrá que esperar. 
¿Cuántos ciclos? Tantos como la posición que ocupa el módulo a utilizar en 
la lista de módulos ocupados. En el ejemplo, 4 ciclos. En el ciclo 11 están 
ocupados los módulos m5-...-m1; en el siguiente ciclo, por tanto, los 
módulos m6-...-m2; en el siguiente, m7-...-m3, y, en el siguiente, m0-...-m4. 
Finalmente, en el siguiente ciclo se liberará m0, que podrá ser utilizado por 
la instrucción SV para comenzar la escritura del vector A. 
En resumen, para analizar los conflictos en memoria entre las 
instrucciones j y k, el procedimiento es el siguiente (todas las operaciones son 
módulo nm, siendo nm el número de módulos de memoria): 
 
a. Se calcula qué módulo va a comenzar a utilizar la instrucción j cuando 
la instrucción k quiere acceder a memoria: 
 
 (inik – inij) + módulo_inij (ini = ciclo inicio en memoria) 
 
b. Se crea la lista de módulos ocupados, añadiendo tm–1 módulos por 
delante y por detrás al módulo anterior (tm, latencia de la memoria). 
 
 < tm–1 módulos | (inik – inij) + módulo_inij | tm–1 módulos> 
▪ 28 ▪ Capítulo 1: COMPUTADORES VECTORIALES 
c. Si el primer módulo de memoria que va a utilizar la instrucción k está 
ocupado, se calcula el tiempo de espera, que habrá que añadir al 
tiempo de inicio de la instrucción (antes de la UF). 
 
El procedimiento anterior se puede generalizar para el caso de acceso a vectores con 
paso s, siempre que los pasos de las instrucciones que están accediendo a memoria 
sean iguales. En este caso, dado que en cada paso se avanzan s módulos, por un 
lado, habrá que hacer (inik – inij) × s + módulo_inij y luego habrá que contar tm–1 
módulos de s en s. En caso de que no coincida el paso de todas las instrucciones a 
memoria el análisis es más complejo y, normalmente, en función de la máquina, no 
se comenzará a ejecutar la segunda instrucción hasta que haya terminado la primera. 
 
Repitamos el ejercicio anterior, pero teniendo en cuenta los conflictos en 
memoria. Tal y como se muestra en la tabla, la instrucción SV quiere realizar 
un encadenamiento en el ciclo 10. Dado que la instrucción LV está aún en 
memoria, no podrá utilizar los siguientes módulos: el módulo (10 – 3) + 0 = 
7, los dos anteriores, 6 y 5, y los dos siguientes, 0 y 1. Como necesita 
acceder al módulo 0, el tiempo de espera será de 4 ciclos. Tras ese tiempo, 
ciclo 14, el encadenamiento no se podrá realizar directamente del sumador, 
sino que habrá que realizarlo desde el registro (si esto no fuera posible, 
habría que esperar a que la suma terminara de escribir en el registro V2). 
 
 2 buses / encadenamiento 
A = A + 1 inic. mod. ocup. t. esp. lat. UF dato 1 dato N 
LV V1,A(R1) 3 - - 3 6+1 6+N 
ADDVI V2,V1,#1 [7] - - 2 9+1 9+N 
SV A(R1),V2 [10] ?? 5 / 6 –7– 0 / 1 +4 3 17+1 17+N 
 
En general, para calcular el número de ciclos que hay que esperar para 
utilizar la memoria, hay que hacer el análisis con todas las instrucciones que 
estén en memoria, ya que cada una de ellas ocupará tm módulos de memoria. 
Como consecuencia de ello, no se pueden permitir más de nm div tm 
operaciones de memoria simultáneamente, ya que con ese número de 
instrucciones se ocupan todos los módulos de memoria. Por ejemplo, para el 
anterior caso (nm = 8 y tm = 3) no se pueden procesar simultáneamente más 
de 8 div 3 = 2; estaría de sobra, por tanto, un hipotético tercer bus a 
memoria. 
1.3 DEPENDENCIAS ESTRUCTURALES ▪ 29 ▪ 
De los párrafos anteriores se pueden deducir dos consecuencias 
importantes: por un lado, se necesita que el nivel de entrelazado del sistema 
de memoria sea grande, para que se

Continuar navegando