Está en la página 1de 10

Tipos de

Paralelismo

Algoritmos
Concurrentes y
Paralelos

1
1. Tipos de paralelismo
El hardware en los uniprocesadores incorporan algunos mecanismos con el
objetivo de explotar el paralelismo a nivel de instrucción, a nivel de thread
y a nivel de datos.

Algunos de estos mecanismos hardware permiten explotar el paralelismo sin


necesidad de esfuerzo por parte del programador o del compilador. Otros
mecanismos, en cambio, precisan del programador o del compilador para
poder explotarlos.

De esta manera, la segmentación y los procesadores superescalares


permiten, de forma transparente, explotar el paralelismo a nivel de
instrucción. Por otro lado, en el caso de los procesadores very long
instruction word (VLIW), que también tienen como objetivo explotar el
paralelismo a nivel de instrucción, precisan del compilador para explotar
adecuadamente este paralelismo.

En el caso de querer explotar el paralelismo a nivel de datos o a nivel de


threads, también es necesario que el compilador o el programador generen
un binario o desarrollen el programa, respectivamente.

1.1. Paralelismo a nivel de instrucción


El pipeline es una Se conoce como paralelismo a nivel de instrucción cuando las instrucciones
técnica para de un programa son reordenadas y combinadas en grupos para ejecutarse
implementar el en paralelo sin que se produzcan cambios en el resultado del programa.
paralelismo a nivel de Entre 1980 y 1990, los avances en el paralelismo a nivel de instrucción
instrucciones dentro
de un solo procesador.
predominaron en la arquitectura de las computadoras.
Pipelining intenta
mantener ocupada a
Un procesador segmentado es un tipo de procesador más moderno que
cada parte del
procesador, dividiendo usan pipeline de instrucciones de varias etapas. A cada etapa del pipeline le
las instrucciones corresponde una acción diferente que el procesador realiza en la instrucción
entrantes en una serie correspondiente a la etapa. La segmentación reside en la separación de la
de pasos secuenciales. ejecución de cada instrucción en varias etapas para poder procesar una
Se realizan por
instrucción diferente en cada una de las etapas y ejecutar múltiples
diferentes unidades
del procesador que instrucciones en forma simultánea. Si el procesador usa un pipeline de N
trabajan de forma etapas, puede realizar hasta n instrucciones diferentes en diferentes etapas
simultánea. Aumenta de finalización. Es exclusivo el uso de un hardware determinado del
el rendimiento de la procesador por cada una de las etapas de la instrucción. El ejemplo de un
CPU a una velocidad
procesador segmentado es un procesador RISC (Reduced instruction set
de reloj determinada,
aunque puede computing), con cinco etapas: pedir instrucción, decodificar, ejecutar,
aumentar la latencia acceso a la memoria y escritura.
debido a la sobrecarga
adicional del proceso
de pipeline en sí.
2
Con la segmentación de la ejecución de las instrucciones se consigue
aumentar el ratio de ejecución, es decir, el número medio de instrucciones
que acaban por ciclo (IPC, esto es, instructions per cycle). El aumento de ratio
es gracias a que se solapan las etapas de ejecución de más de una
instrucción. De esta forma, podemos estar ejecutando en paralelo tantas
instrucciones como número de etapas tenga la ejecución de las instrucciones
y así, después de rellenar todas las etapas con tantas instrucciones como
etapas haya en la segmentación, conseguiremos finalizar una instrucción por
ciclo.

Los procesadores superescalares son aquellos que pueden ejecutar más de


una instrucción a la vez. En este caso, las instrucciones pueden agruparse
solo si no hay dependencia de datos entre ellas. Para implementar la
ejecución fuera de orden y la paralelización a nivel de instrucción, las
técnicas que se usan son scoreboarding y el algoritmo de Tomasulo. Este es
similar a scoreboarding, pero hace uso del renombre de registros. Se trata,
en suma, de dos de las técnicas más comunes.

El término de procesador superescalar apareció por primera vez en 1987, en


el sentido de que el procesador tenía unidades funcionales duplicadas y, por
consiguiente, podía lanzar más de una instrucción a la vez. Cuarenta años
antes, el computador CDC 6600 ya tenía 10 unidades funcionales en las que
podía estar ejecutando varias instrucciones. Sin embargo, este procesador
no podía realizar el lanzamiento de más de una instrucción a la vez y, por tal
motivo, no se lo considera un procesador superescalar.

En los procesadores VLIM (very long instruction), la arquitectura de CPU


implementa una forma de paralelismo a nivel de instrucción. Para lograr ese
paralelismo, como en las arquitecturas superescalares, usa varias unidades
funcionales, como por ejemplo, varias ALU (del inglés arithmetic logic unit,
esto es, unidad aritmética lógica), varios multiplicadores, etcétera.

Su característica principal es la de tener juegos de instrucciones muy simples


considerando el número de instrucciones diferentes, pero muy grandes en
cuanto al tamaño de cada instrucción, tal como su nombre lo indica. En cada
instrucción se incluye el estado de la totalidad de las unidades funcionales
del sistema, con el objetivo de simplificar el diseño del hardware, dejando
todo el trabajo de planificar el código en manos del programador o
compilador. Opera de forma diferente a un procesador superescalar, en el
que es el hardware en tiempo de ejecución el que planifica las instrucciones.
Un ejemplo de este tipo de procesador es el microprocesador IA-64.

3
Las ventajas de los VLIW son que hace más simple la arquitectura del
hardware, al no tener que planificar el código, y requiere menor potencia,
por lo cual disminuye el consumo.

Por su parte, los inconvenientes son que los compiladores que precisa son
mucho más complejos, además de que se debe cambiar el juego de
instrucciones para cualquier mejora en la arquitectura del hardware
(compatibilidad hacia atrás nula).

Aunque son de importancia en las computadoras de propósito general, estos


inconvenientes son irrelevantes en computación embebida. El menor
consumo y bajo coste del hardware los hace apropiados para dichos
sistemas. Es por esto que se pueden encontrar VLIW en televisores de alta
definición, discos duros multimedia, reproductores Blu-ray, etcétera.

1.2. Paralelismo a nivel de threads


El paralelismo a nivel de instrucción (ILP), en sus diversas formas, se pierde
en el momento de hallar fallos en accesos a los diversos niveles de memoria
caché. Esto se debe a que el procesador debe parar la ejecución de nuevas
instrucciones hasta recibir el dato (línea de caché). Una alternativa de
solución es darle la posibilidad de ejecutar otro programa o thread
enmascarando esta situación de bloqueo. A esto se lo conoce, en inglés,
como on-chip multithreading.

El paralelismo a nivel de thread mantiene lo mejor del paralelismo a nivel de


instrucción, pero oculta los fallos de acceso a memoria.

Hay varias aproximaciones al on-chip multithreading:

 Multithreading de grano fino: se le asigna un número fijo de ciclos a


un thread detrás de otro. A esta política de asignación de ciclos del
procesador se la denomina round-robin.
Este tipo de paralelismo a nivel de threads trata de ocultar los
bloqueos del procesador realizando una ejecución en round-robin de
las instrucciones de threads diferentes, en ciclos consecutivos. De
esta forma, se puede reducir la probabilidad de que el procesador se
quede sin hacer nada en esos ciclos, cuando se tienen tantos threads
ejecutándose como ciclos de bloqueo, los cuales precisan, por
ejemplo, de un fallo de acceso a la memoria.

 Multithreading de grano grueso: se puede ejecutar más de una


instrucción de un thread en ciclos consecutivos. Habitualmente, un

4
thread continúa la ejecución de instrucciones hasta que se produce
un bloqueo causado por un salto, un conflicto de datos, etcétera.
En un procesador con soporte multithreading de grano grueso, los
threads se pueden ejecutar en más de un ciclo consecutivo. Esto hace
que se reduzca la necesidad de múltiples bancos de registros.

De este modo, no son necesarios tantos threads activos para


aprovechar al máximo el procesador, como es con el caso del
multithreading de grano fino, aunque se perderán los ciclos que se
necesiten para darse cuenta del bloqueo y cambiar de thread, dado
que se espera que haya un bloqueo para realizar el cambio. Por otro
lado, si se tiene un número suficiente de threads activos, se podrá
conseguir un mejor rendimiento que con el grano fino.

Otra opción es realizar el cambio de thread cada vez que una


instrucción pueda provocar un bloqueo, en lugar de esperar que este
se produzca. Esto reduce aún más el número de ciclos en los que el
procesador está bloqueado.

También se puede vaciar el pipeline cada vez que cambiemos de


thread. De esta manera, no es necesario tener la información sobre
qué banco de registros se tiene que usar a lo largo de toda la
ejecución de una instrucción.

 Simultaneous multithreading: los procesadores con simultaneous


multithreading permiten que dos threads diferentes se puedan
ejecutar en el mismo ciclo de procesador; de este modo, logran
reducir el desaprovechamiento horizontal de las unidades
funcionales.

En los procesadores superescalares con multithreading, a esto se lo


denomina reducción del horizontal waste. Se lo puede ver como un
refinamiento del grano grueso, debido a que, si en un ciclo del
procesador una instrucción de un thread se bloquea, una instrucción
de otro thread se puede usar para mantener el procesador y, así,
ocupar todas sus unidades funcionales. Es posible que una
instrucción de un thread quede bloqueada porque hay un número
limitado de unidades funcionales de un tipo. En este caso, también
se puede tomar una instrucción de otro thread.

1.3. Paralelismo a nivel de datos


El paralelismo a nivel de datos se trata de la posibilidad de trabajar sobre
dos o más datos con una única instrucción, de allí su nombre en inglés single
instruction multiple data (SIMD). Un uniprocesador con instrucciones SIMD
puede realizar la misma operación, en paralelo, con más de un dato a la vez.

5
El paralelismo de datos está relacionado con programas con ciclos que hacen
foco en la distribución entre los diferentes nodos de los datos que se tratan
en paralelo. Es común observar paralelismo de datos en aplicaciones
científicas y de ingeniería.

Para poder ejecutar instrucciones SIMD se requiere tener un hardware que


soporte registros más grandes, buses hacia memoria que permitan el acceso
a datos del tamaño de los registros y unidades funcionales que soporten
operar con más de un dato a la vez. Dependiendo de la semántica de la
instrucción, será posible operar con mayor o menor número de operandos.
Para un tamaño del registro de 128 y 256 bits, los elementos que indique la
semántica de la instrucción hace que se reparta equitativamente el registro
entre estos elementos.

Se denomina dependencia de terminación de ciclo a la dependencia de una


iteración de un ciclo en la salida de una o más iteraciones anteriores. Estas
evitan la paralelización de ciclos.

6
2. Ley de Amdahl y ley
Gustafson
La aceleración óptima aplicando la paralelización es lineal, o sea, al duplicar
el número de elementos de procesamiento se debería disminuir a la mitad
el tiempo de ejecución. Si se duplica nuevamente, debe reducir el tiempo a
la mitad por segunda vez, pero pocos algoritmos paralelos se acercan a los
resultados de esta aceleración óptima. La mayoría de los algoritmos logran
para pocos elementos de procesamiento una aceleración casi lineal y para
un gran número de elementos de procesamiento pasa a ser constante.

Gene Amdahl en la década de los 60 planteó el cálculo de la aceleración


potencial de un algoritmo en una plataforma de cómputo en paralelo,
conocida como ley de Amdahl. Esta ley plantea que la aceleración que se
consigue con la paralelización estará restringida por la parte del programa
que no pueda paralelizarse. Los programas que resuelven problemas
matemáticos o de ingeniería se separan en varias partes, algunas
paralelizables y otras partes no paralelizables (o secuenciales).

Si llamamos 𝜶 a la fracción de tiempo que un programa utiliza en partes no


1 1
paralelizables, consideramos S = α = limP→∞ (1−α ) a la máxima

P
aceleración que se puede alcanzar con la paralelización del programa. Si la
parte no paralelizable o secuencial del programa utiliza el 10 % del tiempo
de ejecución, se puede obtener no más de 10× de aceleración, siendo
independiente de la cantidad de procesadores que se añadan. Esto
puntualiza un límite superior a la utilidad de añadir más unidades de
ejecución paralelas.

En la Figura 1 se muestra la representación gráfica de la Ley de Amdahl. Esta


ley plantea que la mejora en la velocidad de ejecución de un programa a
partir de la paralelización está restringida por la proporción del programa
que se puede paralelizar.

7
Figura 1: Ley de Amdahl

Fuente: Dvd.darias, 29 de diciembre de 2012, https://goo.gl/saby2j

Otra ley que trata la relación entre el aumento de velocidad y la cantidad de


procesadores es la ley de Gustafson, muy relacionada también con la ley
Amdahl. La Ley de Gustafson plantea que el aumento de velocidad con P
procesadores está dada por la siguiente expresión:

𝑆ሺ𝑃ሻ = 𝑃 − 𝛼ሺ𝑃 − 1ሻ = 𝛼 + 𝑃ሺ1 − 𝛼ሻ

Las dos leyes coinciden en consideración al tiempo de funcionamiento de la


parte secuencial del programa como independiente del número de
procesadores, pero difieren en cómo consideran el tamaño del trabajo que
se realizará en paralelo. La ley de Gustafson considera que la cantidad total
de trabajo que se hará en paralelo varía linealmente con el número de
procesadores. En cambio, la ley de Amdahl considera que todo el problema
tiene tamaño fijo y, por lo tanto, la cantidad total de trabajo que se hará en
paralelo es independiente del número de procesadores.

Es fundamental en la implementación de algoritmos paralelos comprender


la dependencia de datos.

Un programa no puede ejecutarse en menor tiempo que el necesario para


la cadena más larga de cálculos dependientes, o sea que la ruta crítica,

8
debido a que debe respetarse el orden de los cálculos que dependen de
cálculos previos. Gran parte de los algoritmos tienen la posibilidad de
ejecutar cálculos independientes en paralelo sin tener largas cadenas de
cálculos dependientes.

Las condiciones de Bernstein describen cuándo dos segmentos son


independientes y pueden ejecutarse en paralelo.
Se considera que Pi y Pj son dos segmentos del programa.
Si para Pi, son Ii y Oi son todas las variables de entrada y las variables
de salida respectivamente y del mismo modo para Pj.

Entonces Pi y Pj son independientes si satisfacen las siguientes


condiciones:

 Primera condición: 𝐼𝑗 ∩ 𝑂𝑖 = ∅
 Segunda condición: 𝐼𝑖 ∩ 𝑂𝑗 = ∅
 Tercera condición: 𝑂𝑖 ∩ 𝑂𝑗 = ∅

Así, entonces, podemos concluir que la primera condición se ocupa de una


dependencia de flujo, correspondiente al primer segmento que produce un
resultado utilizado por el segundo segmento. La segunda condición
caracteriza una antidependencia, cuando el segundo segmento (Pj) produce
una variable que necesita el primer segmento (Pi). La tercera y última
condición se ocupan de una dependencia de salida: cuando dos segmentos
escriben en el mismo lugar, el resultado viene del último segmento
ejecutado.

Las condiciones de Bernstein no permiten que los diferentes procesos


compartan la memoria entre ellos. Por tal motivo, surge la necesidad de que
algunos medios asignen el orden entre los accesos, como semáforos,
barreras o algún otro método de sincronización.

9
Referencias
Dvd.darias. (29 de diciembre de 2012). [Imagen sin título sobre ley de
Amadahl]. Recuperada de
https://commons.wikimedia.org/wiki/File:AmdahlsLaw-es.svg

10

También podría gustarte