You are on page 1of 25

Diseño e implementación de

programas paralelos

Marcelo Arroyo

Universidad Nacional de Río Cuarto


2009
Prólogo
Este trabajo es el resultado del dictado de un curso sobre desarrollo de algoritmos paralelos en
la Universidad Nacional de Río Cuarto. Los contenidos son un compendio de varias fuentes
sobre temas de arquitecturas de computadoras paralelas, técnicas de desarrollo de algoritmos
paralelos, casos de estudio y descripción de algunas herramientas utilizadas en el taller desarro-
llado.

Los avances logrados en el desarrollo de arquitecturas de computadoras, juntamente con la


disminución de los costos del hardware permite que los usuarios demanden soluciones con altos
requerimientos computacionales. Los avances en la computación de alta performance ha permi-
tido el desarrollo de aplicaciones en diversas áreas lo que a veces ha dado nacimiento a nuevas
disciplinas científicas como por ejemplo la bioinformática. Las aplicaciones paralelas corriendo
en sistemas de computación de gran desempeño han permitido el desarrollo de aplicaciones muy
interesantes en áreas de cálculo numérico, simulación, gráficos y animación y otras.

Estas nuevas tecnologías, ahora al alcance de todos ya que una computadora personal es una
arquitectura paralela, requiren que los desarrolladores de software no pueden ignorar los con-
ceptos y técnicas necesarias para el desarrollo de este tipo de sistemas de software que permitan
explotar los sistemas de computación modernos.

Es posible ver a Internet como un gran sistema multiprocesador, lo cual ha permitido el des-
arrollo de aplicaciones cooperativas, explotando el gran poder computacional de la red. Un
ejemplo de esto son los proyectos del tipo SETI (Search for Extra Terrestrial Inteligence) y
algunos proyectos de secuenciación de genes.

3
Parte I

Conceptos y técnicas
Prólogo 7

Esta parte contiene una introducción a las arquitecturas paralelas, clasificación y modelos de
computación paralela. Se describen los conceptos básicos sobre concurrencia, problemas y solu-
ciones para el desarrollo de programas concurrentes. Se repasan conceptos sobre complejidad
computacional y se desarrollan conceptos y técnicas de análisis y diseño de algoritmos paralelos.
Se analizan casos de estudio y se presenta un método de desarrollo de algoritmos paralelos.
Capítulo 1
Introducción
"The complexity for minimum component costs has increased at a rate of roughly a factor of two
per year. Certainly over the short term this rate can be expected to continue, if not to increase.
Over the longer term, the rate of increase is a bit more uncertain, although there is no reason to
believe it will not remain nearly constant for at least 10 years. That means by 1975, the number
of components per integrated circuit for minimum cost will be 65,000." Gordon Moore, 1965.

En los últimos años hemos sido testigos de grandes avances en las tecnolgías aplicadas al des-
arrollo de microprocesadores. Hemos pasado de frecuencias de reloj de 40 Mhz hasta 3 Ghz.
Además del avance en velocidad, los microprocesadores actuales pueden ejecutar múltiples ins-
trucciones en el mismo ciclo. Los increíbles niveles de integración alcanzados han permitido
incorporar diferentes unidades de procesamiento en el mismo chip. Los más recientes avances
son la replicación de unidades de procesamiento en el mismo chip (multicores).
Las capacidades de memoria se han incrementado prácticamente al mismo ritmo que los
avances en velocidad.

Hoy contamos con comptadoras de escritorio con múltiples procesadores, servidores de bajo
costo con hardware redundante y altas capacidades de procesamiento y almacenamiento. Estas
computadoras pueden contener interfaces de red con tasas de transferencia y bajas latencias que
permiten interconectarlas para lograr un sistema multiprocesador en red con altísima capacidad
de procesamiento.

Estos avances en el hardware ha permitido el desarrollo de aplicaciones con una gran


demanda de recursos computacionales. Hoy son común aplicaciones de cálculo numérico o sim-
bólico en diferentes áreas científicas y de ingeniería, servidores que soportan un altísimo número
de transacciones, sistemas de alta confiabilidad, etc.

Actualmente es muy importante para los desarrolladores de software comprender estas arqui-
tecturas y los conceptos y técnicas aplicables al desarrollo de aplicaciones paralelas.

1.1 Los avances en poder computacional


Moore en un análisis de los avances en el desarrollo de circuitos electrónicos digitales desde 1975,
estableció que cada 18 meses se duplicaba la complejidad de los circuitos. Esta proyección se
conoce como la ley de Moore. De una manera increíble, la ley de Moore se ha mantenido hasta
nuestros días.

Inicialmente los incrementos del paralelismo en hardware se produjo a nivel de bits. Hemos
pasado de microprocesadores de 4 a 8, 16, 32 y actualmente 64 bits. Estos incrementos permiten
manipular datos de mayor magnitud en una sola instrucción. A partir de mediados de los 90, se
ha incrementado el paralelismo funcional, esto es, incorporando nuevas unidades específicas de
procesamiento (ej: unidades de punto flotante y procesadores vectoriales) las cuales pueden tra-
bajar en paralelo con las demás unidades.

9
10 Introducción

Además se desarrollaron arquitecturas con múltiples unidades funcionales (ej: controladores)


que podían trabajar en paralelo con la CPU. Los controladores DMA (Direct Memory Access)
permitieron acceder en forma simultánea a la memoria dispositivos periféricos (ej: discos) y la
CPU. Esto requería que se diseñaran mecanismos de arbitraje de acceso los recursos compar-
tidos como la memoria principal (RAM).

1.2 Aplicaciones de la computación paralela


Los avances en el poder computacional y la baja de los precios del hardware ha permitido la
aparición de nuevos dominios de aplicación en los cuales no necesariamente se requieran una
supercomputadora de alto costo. Los principales dominios de aplicación son:
• Ingeniería y diseño: sistemas con altos requerimientos de cálculo numérico para simula-
ción de sistemas físicos como dinámica de fluidos (ej: aerodinámica), diseño de circuitos
electrónicos, análisis de estructuras, etc.
• Computación científica: aplicaciones en bioinformática como secuenciación de genes,
diseño y análisis de estructuras de genes y proteínas, diseño de drogas, etc. Aplicaciones
en áreas de la física y la química permiten el desarrollo de nuevos materiales. Simula-
ciones de la atmósfera permiten a los meteorólogos realizar predicciones del tiempo.
• Aplicaciones comerciales: los grandes volúmenes de datos y transacciones que requieren
algunas organizaciones, generalmente con aplicaciones en Internet. Ejemplos: Google,
Amazon, etc.
• Ciencias de la Computación: herramientas de análisis de programas, como model-checking
y deducción automática requieren de un gran poder computacional para poder aplicarse a
sistemas reales.
• Entretenimiento: la industria de juegos y realidad virtual desarrollan aplicaciones con
altos requerimientos de procesamiento numérico y gráfico. A menudo exsten requeri-
mientos de tiempo real (ej: animación). La industria del cine animado ha requerido solu-
ciones que sólo pueden ser resueltas por aplicaciones paralelas.

En los capítulos subsiguientes, se estudiarán las características y modelos de plataformas de har-


ware paralelas, modelos de programas paralelos, métodos y técnicas de desarrollo de programas
paralelos y técnicas de desarrollo de algoritmos para problemas numéricos y para algoritmos
sobre estructuras de datos.
Capítulo 2
Arquitecturas paralelas
En éste capítulo se introducen una variedad de arquitecturas paralelas y los modelos de compu-
tación subyacentes.
Los modelos de computación paralelas permitirán hacer análisis de los algoritmos desarro-
llados para poder comparar con otros algoritmos u otros modelos. Uno de los principales obje-
tivos en el desarrollo de algoritmos paralelos es conseguir aceleraciones significativas contra una
solución secuencial.
En las secciones siguientes se describen algunas arquitecturas de hardware y técnicas usadas
para realizar operaciones en paralelo. Las arquitecturas y técnicas descriptas permiten ejecutar
operaciones en paralelo sin intervención o ayuda del software que están ejecutando, por lo que se
conoce como paralelismo implícito.

2.1 Procesadores superescalares


Se denomina procesador superescalar a todos aquellos que son capaces de ejecutar más de una
instrucción por ciclo de ejecución de una instrucción. Generalmente esto se ha logrado mediante
el uso de líneas de procesamiento (pipelines). Un pipeline funciona como una línea de ensable
comúnmente usado en la industria. Una línea de producción de n etapas, la cual insume una
cantidad de tiempo t , permite idealmente producir n unidades de producción en tiempo t.
Un pipeline divide la ejecución de una instrucción en n etapas para lograr ejecutar en un
ciclo de instrucción hasta n instrucciones.

Un procesador puede aumentar el grado de paralelismo si replica el número de pipelines.

A modo de ejemplo, supongamos que un procesador contiene dos pipelines de 5 etapas cada
uno (IF:instruction fetch, ID:instruction decode, OF:operand fetch, IE:instruction decode y
WB:write-back). La figura 2.1 muestra el pipeline y un fragmento de programa que suma 4
números, almacenados en las direcciones de memoria 1000, 1004, 1008 y 100C.

IF1 → ID1 → OF1 → IE1 → WB 1


IF2 → ID2 → OF2 → IE2 → WB 2

1. load R1, @1000


2. load R2, @1008
3. iadd R1, @1004
4. iadd R2, @100C
5. iadd R1, R2
6. store R1, @2000

Figura 2.1. Pipeline de 5 etapas con un programa de ejemplo.

11
12 Arquitecturas paralelas

Consideremos la ejecución del programa dado. Las dos primeras instrucciones pueden ser eje-
cutadas concurrentemente. Lo mismo ocurre con las instrucciones 3 y 4. Las últimas dos ins-
trucciones no pueden ser ejecutadas concurrentemente, ya que la instrucción 6 depende del resul-
tado (R1) de la instrucción 5.

Las dependencias de datos entre las instrucciones hace que los pipelines no puedan utilizarse
al ciento por ciento, ya que se deberán esperar a que se finalicen la instrucciones previas.

Los principales problemas de contención en los pipelines son:


a) dependencia de datos entre las instrucciones: esto puede optimizarse cambiando el
orden de las instrucciones. Puede hacerse estáticamente, como lo hacen algunos compila-
dores o dinámicamente (el procesador lo realiza en tiempo de ejecución). Esto requiere
que se realice un análisis de dependencias de datos (data flow analysis) entre las instruc-
ciones.
b) dependencia de recursos: por ejemplo cuando dos instrucciones deben utilizar la
misma unidad de punto flotante.
c) control de flujo: estas dependencias se deben a las instrucciones de saltos condicionales
(branchs) o incondicionales (invocaciones a procedimientos y goto’s). Los procesadores
generalmente incluyen heurísticas de predicción de saltos condicionales2.1 en la unidad de
pre-fetching de instrucciones (o lookahead caché).

La lógica de control necesaria para determinar las dependencias mencionadas puede ser una
limitante para su incorporación directa en hardware. Por eso muchas optimizaciones pueden
dejarse bajo la responsabilidad de los compiladores, comúnmente llamados compiladores optmi-
zantes. Secuencias de instrucciones que pueden ser ejecutadas en múltiples unidades funcionales
en forma concurrente se empaquetan (o delimitan). Estas secuencias toman la forma de una ins-
trucción de palabra muy larga (very long instruction word ).
La arquitectura IA64 de Intel utiliza esta esta idea.

2.2 Jerarquías de memoria


El rendimiento general de un sistema de computación no sólo depende de la velocidad del proce-
sador. Uno de los principales cuellos de botella es la capacidad de transferencia de datos de la
memoria principal (RAM) hacia y desde el procesador.

El tiempo que tarda la transferencia de una palabra entre la memoria y el procesador se


denomina latencia. El número de bloques de memoria (bytes, words, ...) que se transfieren por
unidad de tiempo se denomina ancho de banda (bandwidth).

Para minimizar la latencia se ha generalizado el uso de memorias de alta velocidad (baja


latencia + gran ancho de banda) entre el procesador y la RAM. Estas memorias se denominan
caches. Estas memorias generalmente se direccionan por contenido en lugar por direcciones
(por eso se denominan memorias asociativas) y actúan como atenuantes (buffers) de las diferen-
cias de velocidad entre el procesador y la RAM.

Los datos necesitados por el procesador se almacenan en la cache. Cada vez que el proce-
sador necesita acceder a una dirección de memoria, la unidad de manejo de la memoria (MMU)
busca los datos requeridos en la cache antes que ir directamente a la RAM.

2.1. Generalmente incluyen selección por una rama (generalmente la verdadera) o ambas ramas (una se inva-
lidará).
2.3 Clasificación de arquitecturas paralelas 13

Si el dato ya estaba en la cache se transfiere directamente desde ella y se denomina un


acierto o hit. Cuando se accede a un mismo dato repetidamente se accederá directamente a la
cache. Esto se basa en la observación que es muy común que los programas accedan repetida-
mente a los mismos datos o instrucciones (ej: en ciclos), lo que se conoce como localidad tem-
poral .
Es posible ver a una memoria RAM como una función que va desde un conjunto de direc-
ciones de memoria en valores de longitud de una palabra.

RAM : {Address} → word

en donde la RAM tiene acceso directo (o constante) a cada dirección.

Una cache puede verse como un dispositivo que implementa una función que va desde un
conjunto de direcciones (tags) en una palabra (en caso de un hit) o falla (miss).

cache: {tag} → {word}


S
{miss}

Actualmente es común encontrar arquitecturas con varios niveles de caches, las cuales se
conocen como L1, L2, etc. Los niveles crecientes de cache generalmente tienen mas capacidad de
almacenamiento pero menos ancho de banda y mayor latencia.
Los procesadores actuales generalmente tienen caches de diferentes tipos (ej: caches de ins-
trucciones y caches de datos) y han alcanzado atísimas capacidades de almacenamiento. A modo
de ejemplo, el Intel Core i7 (2008) tiene una cache L3 de 8MB compartida por todos los núcleos.

La forma de escribir programas (o la generación de código de los compiladores) tendrá mayor


o menor impacto en la velocidad de ejecución si se tienen en cuenta los aspectos de localidad
temporal para poder aprovechar los beneficios del uso de caches. El objetivo es maximizar los
hits.

Uno de los problemas que introduce la incorporación de diferentes niveles o jerarquías de


memoria es mantener la coherencia entre los niveles. Algunos procesadores garantizan la cohe-
rencia por hardware mientras que en otros no ofrecen ningún mecanismo de coherencia, por lo
que confían en el software.

El ancho de banda también es un factor muy importante a considerar para conseguir el


máximo rendimiento (throughput) y el mayor factor de utilización de los componentes de hard-
ware. Los procesadores modernos contienen unidades de pre-carga (pre-fetching) de instruc-
ciones y datos desde la mamoria. Estas unidades se basan en la idea de localidad espacial : es
muy probable que los datos próximos o contiguos al dato accedido actualmente sean referen-
ciados próximamente.
Consideremos un programa que en un ciclo accede a los elementos de un vector o una matriz.
Es común que el programa acceda a los elementos en forma creciente en cuanto a su índice del
vector. En el caso de las matrices, cobra importancia el conocimiento de cómo se almacena en
mamoria. Por ejemplo, comúnmente los compiladores FORTRAN almacenan las matrices por
columnas (column major order ), pero los compiladores C lo hacen por filas.
El conocer el orden de los elementos de una matriz en la memoria puede contribuir a mejorar
el rendimiento de un programa, tratando de aprovechar el buen uso de pre-fetching y la caché.

2.3 Clasificación de arquitecturas paralelas


En 1966, Flynn propuso una clasificación de arquitecturas de computadoras:
S=Single, I=Instruction (o programa), M=Multiple, D=Data stream (secuencia de datos)
• SIMD: corresponde a uniprocesadores
• SIMD: instrucciones o programas que se aplican simultáneamente a muchos datos. Ejem-
plos son procesadores vectoriales y Graphical Processing Units (GPUs).
14 Arquitecturas paralelas

• MISD: diferentes instrucciones operan sobre los mismos datos en paralelo. Arquitecturas
no muy comunes. Usadas generalmente para proveer redundancia por de hardware para
aumentar la confiabilidad. Ejemplos: computadora del transbordador espacial.
• MIMD: diferentes instrucciones actuando simultáneamente sobre diferentes datos. Esta es
la arquitectura típica de un multiprocesador.

La principal diferencia entre los procesadores vectoriales y los multiprocesadores es que un


procesador vectorial tiene una única unidad de control la cual es la encargada de decodificar las
instrucciones y habilitar o deshabilitar las diferentes unidades de procesamiento que controla.

PE CU

Interconection

Interconection
+
PE

Network

Network
PE CU
CU +
PE
... ...
CU
PE +
PE

a) SIMD b) MIMD

Figura 2.2.

La figura 2.2 muestra las diferencias de los modelos SIMD y MIMD (CU=Control Unit,
PE=Processing Element).

2.4 Modelos de comunicación


Los procesadores pueden comunicarse de diferentes formas. Los modelos mas usados son:
a) Memoria compartida (shared-memory): todos los procesadores acceden a una memoria
común por lo cual se reusan los mecanismos que se encuentran en un uniprocesador.
Los procesadores además pueden tener memoria local , es decir una memoria privada
para cada procesador. La memoria compartida por todos los procesadores generalmente
se denomina memoria global .
Una arquitectura con tiempos de acceso uniforme a cualquier memoria se conoce como
UMA (Uniform Memory Access). En otro caso (por ejemplo la memoria local puede tener
un tiempo o costo de acceso menor que la global), se denomina NUMA (Non-Uniform
Memory Access).
b) Pasaje de mensajes (message passing): existe un mecanismo de comunicación entre proce-
sadores. Este mecanismo generalmente toma la forma de instruciones del tipo send y
receive. Estas instrucciones requieren de algunas otras adicionales como por ejemplo iden-
tificación unívoca de procesadores y del número de procesadores existentes.

En un modelo de memoria compartida,varios accesos de lectura a un mismo dato no causaría


problemas lógicos, pero accesos de escritura sí, por lo que se deberá definir una política de
acceso simultáneo a los datos por diferentes unidades de procesamiento.
Estas políticas de acceso se implementan por medio de mecanismos de sincronización. Una
de las políticas comúnmente usada es la de acceso exclusivo, es decir se le da acceso sólo a un
procesador y los demás deberán esperar al próximo ciclo de ejecución. El mecanismo debería
asegurar progreso, es decir que eventualmente un procesador podrá ejecutar su instrucción. En
otras palabras, ningún procesador debería quedar relegado indefinidamente.
2.5 Topologías de interconexión 15

Los mecanismos de comunicación (operaciones send y receive) podrán tener las siguientes
características:
a) Sincrónico: la operación deberá esperar (bloquearse) hasta que se complete. Es muy
común usar receive en forma sincrónica.
b) Asincrónica: se continúa inmediatamente con la instrucción siguiente. Es común el uso de
send en esta forma, lo que permite aumentar el paralelismo (realizar simultáneamente
comunicación con ejecución).

2.5 Topologías de interconexión


La forma en que se interconectan los procesadores da lugar a la topología de interconexión. Hay
varias formas de interconectar los procesasdores entre sí o los procesadores con diferentes
módulos de memoria (en el caso de un modelo de memoria compartida).
• Bus: todos los procesadores se conectan a un bus común de comunicación. El acceso al
bus deberá ser controlado por algún mecanismo de arbitraje ya que el bus puede ser
usado por un único procesador para enviar un mensaje.
• Cross bar switch: todos los procesadores están contectados con todos los módulos de
memoria.
• Redes de multiestado: un esquema general de interconexión de p procesadores con m
módulos de memoria es el siguiente:
La red contiene log p estados:
a) cada estado conecta p procesadores con p módulos de memoria
b) existe una conexión
 (link) entre el procesador i y el módulo de memoria j si se
2i, 0 6 i 6 p/2 − 1
cumple que j =
2i + 1 − p, p/2 6 i 6 p − 1

• Redes completamente conectadas: existe una conexión entre cada para de procesadores.
• Redes estrella: existe un procesador intermedio que rutea los mensajes entre cualquier par
de procesadores.
• Arreglos: lineales (ej: pipelines), bidimensionales (matrices), cubos, hipercubos, etc.
• Árboles: sistemas de interconexión jerárquicos.
• Hipercubos.

La figura 2.3 muestra diferentes topologías de interconexión entre procesadores y memorias.

m1 m2 ... mk P1 m1
Compartida
Memoria

estado 1

estado 2

estado s

P1
... ...

...
Pn
... mk
P1 Pn Pn

a) Bus b) Cross−bar switch c) Multi−estado

Figura 2.3. Topologías de interconeción entre procesadores y memorias.

Un sistema de interconexión puede ser:


• Estático: no cambia durante la ejecución
16 Arquitecturas paralelas

• Dinámico o reconfigurable

2.5.1 Análisis de redes de interconexión


Cada red de interconexión puede ser analizada para determinar sus costos de interconexión y
transmisión de mensajes.

Definición 2.1. El diámetro de una red de interconexión es el máximo de los caminos (paths)
mínimo entre dos nodos cualesquiera de procesamiento.

Por ejemplo, el diámetro de una topología en estrella es 2.

Definición 2.2. La conectividad es una medida de multiplicidad (número) de caminos entre


dos nodos cualesquiera. Generalmente la medida usada es el mínimo de caminos.

Por ejemplo, en una topología en estrella es 1.

Definición 2.3. El ancho de bisección es el número mínimo de links que pueden ser remo-
vidos para particionar una red en dos partes iguales.

Definición 2.4. El ancho de un link o canal es el número de bits que éste puede transmitir
simultáneamente.

Definición 2.5. La tasa (o velocidad) de transferencia de un canal es el número de bits


que puede transmitir por unidad de tiempo.

Definición 2.6. El ancho de banda (bandwidth) es el ancho del canal por la tasa de trans-
ferencia.

2.6 Ejercicios
1. Dado el modelo de procesador y el programa de la figura 2.1 mostrar una ejecución del
programa describiendo los estados de cada etapa de los pipelines en cada ciclo de reloj.
Asuma que en cada ciclo de reloj se ejecuta una etapa del pipeline.
2. Supogamos un procesador operando a 1 GHz (clock de 1 ns) con dos unidades de punto
flotante y es capaz de ejecutar hasta 4 instrucciones por ciclo, conectado a una DRAM
operando a 100 ns (tamaño de bloque de transferencia = 1 word), sin caché. El proce-
sador tiene un rendimiento de hasta 4 GFLOPS2.2. Supongamos una operación de pro-
ducto de dos vectores de reales. ¿Qué tasa de rendimiento alcanza el procesador?
3. Suponiendo que dado el mismo sistema que el ejercicio anterior al que adicionamos una
caché de 32KB con una latencia de 1 ns (igual velocidad que el procesador). Un pro-
grama realiza el producto de dos vectores de 1024 valores en punto flotante cada uno.
¿Qué rendimiento alcanzará el procesador en términos de FLOPS? Asuma que la
memoria cache no sobreescribe valores mientras tenga capacidad libre.
4. Idem al ejercicio anterior pero el programa debe multiplicar dos matrices de 32x32.
5. Suponga que se quiere escribir un programa que sume los elementos de cada columna de
una matriz dejando los resultados correspondientes en un vector. Suponga que las
matrices se almacenan por filas (row-major order).
a) Dar un programa (en pseudo-código) que resuelva el problema.
b) Suponiendo que el vector de resultados entra en la caché: ¿Cómo podría lograr
otra versión del programa que aprovechara mejor la caché?

2.2. Floating Point Operations.


2.6 Ejercicios 17

c) Analice las diferencias de rendimiento de las dos versiones anteriores.


6. Determinar el diámetro y la conectividad de la siguientes topologías:
a) árbol binario (completo)
b) hipercubo
Capítulo 3
Diseño de algoritmos paralelos
En este capítulo se describe un método de desarrollo de algortimos paralelos a partir de una ver-
sión secuencial. El método consiste en cuatro etapas. En este capítulo se describen las etapas y
se analizan varios ejemplos.

3.1 Un método de diseño


Par el desarrollo de algoritmos paralelos, generalmente se parte desde un algortimo secuencial,
sobre el cual se realizan diferentes tipos de descomposiciones, para luego llegar a hacer un
análisis del algoritmo obtenido y tratar de estimar la aceleración alcanzada.

El método mas comúnmente usado en el proceso de desarrollo de algoritmos paralelos se basa


en la realización de los siguientes cuatro pasos:
1. Descomposición: particionado del algoritmo secuencial en diferentes piezas o tareas.
2. Comunicación: definición de cómo serán los patrones de comunicación entre las tareas.
3. Aglomeración: combinación de tareas en tareas compuestas con el objetivo de minimizar
la comunicación y lograr un mayor rendimiento.
4. Mapping: asignación de tareas a procesos o procesadores del sistema de computación.
A continuación se desarrollan mas en profundidad cada uno de estos conceptos.

3.2 Técnicas de descomposición


El particionado o descomposición de un algoritmo secuencial en varias tareas colaborativas mas
simples puede hacerse desde diferentes estrategias.

3.2.1 Descomposición del dominio


En este enfoque el problema se ataca descomponiendo los datos sobre los que el algoritmo opera.
Hay varias formas de realizar esta descomposición.

3.2.2 Descomposición funcional

3.2.3 Otras técnicas de descomposición


Descomposición de

19
Capítulo 4
Análisis de Algoritmos Paralelos
Así como generalmente es posible hacer análisis de rendimiento de programas secuenciales, es
necesario tener métricas para programas paralelos.
A continuación se presentarán algunas definiciones útiles de medidas de rendimiento que
podrán ser usadas para hacer un análisis de rendimiento teórico en el proceso de desarrollo o
análisis de programas paralelos.

4.1 Métricas de análisis de programas paralelos


Definición 4.1. Tiempo de ejecución de un programa: es el intervalo de tiempo desde que el
programa se inicia hasta que finaliza. En el caso de programas paralelos un programa comienza
(finaliza) a partir que la primera (última) tarea comienza (finaliza).

Se denotará el tiempo de ejecución de un programa secuencial como TS y el tiempo de un


programa paralelo como TP .

Para hacer un análisis teórico de algoritmos e independizarse de tiempos de ejecución espe-


cíficos de una instancia de ejecución de programas en un sistema de computación en particular,
comúnmente los tiempos de ejecución se reemplazan por funciones de estimación de tiempo que
establecen el máximo número de pasos de ejecución o función de cota superior de la estimación
del tiempo de procesamiento. Es común utilizar la notación O de complejidad computacional
(big O notation).

Definición 4.2. Un algoritmo tiene una complejidad temporal O(f (n)) si para cualquier
entrada de tamaño n y dadas las constantes n0 y c tal que n > n0 , el algoritmo no puede eje-
cutar mas pasos que c × f (n).

Esta medida de tiempo de ejecución teórica de un algoritmo es una estimación del pero caso
de ejecución o análisis asintótico. Frecuentemente también se usa para establecer el caso pro-
medio de ejecución.
Por ejemplo, el peor escenario del quicksort es O(n2), pero su caso promedio es O(n log n).

Definición 4.3. Overhead de un programa paralelo (T0 ):


T0 = pTP − TS

donde p es el número de tareas o procesos del programa paralelo.

El tiempo de ejecución de un programa paralelo comprende tiempos de ejecución, tiempos de


comunicación tareas y tiempos ociosos (esperas por comunicación y/o sincronización) de una
j j j
tarea en particular j, es decir TP = Tcomp + Tcomm + Tidle,

o como la razón de la suma de los tiempos de cada tarea y el número de procesos, es decir

21
22 Análisis de Algoritmos Paralelos

Pp i Pp i Pp i
TP = ( i=1 Tcomp + i=1 Tcomm + i=1 Tidle )/ p

Durante el análisis de un sistema paralelo, uno de los principales parámetros de interés es la


aceleración obtenida mediante el uso de procesadores adicionales con respecto a la solución
secuencial.

Definición 4.4. Aceleración (speedup): S = TS /TP

Teóricamente, la aceleración S nunca puede execee el número de procesos p4.1. La acelera-


ción ideal es p, aunque difícilmente alcanzable en la práctica debido a que las tareas paralelas
realizan computaciones extras o sufren esperas para lograr sicronizarse y/o comunicarse.

Definición 4.5. Eficiencia: E = S/p

La eficiencia es una medida de la fracción de tiempo en la cual es usado útilmente un ele-


mento de procesamiento.
También se puede definir como el radio entre el tiempo de ejecución del algoritmo secuencial
más rápido y el tiempo de ejecución del algoritmo paralelo.

Definición 4.6. El costo de un programa paralelo: C = TP × p.

El costo de un programa paralelo refleja la suma de los tiempos de ejecución de cada unidad
de procesamiento.

Se dice que un programa paralelo tiene costo óptimo si tiene costo computacional igual al
programa secuencial más rápido.

4.2 Escalabilidad

4.1. Raramente puede observarse en algunos experimentos que la aceleración es mayor que p debido a que el
programa secuencial deberá hacer más trabajo que las tareas paralelas, como por ejemplo cuando los datos en la
versión secuencial no pueden aprovechar cachés u otra característica de hardware. Esto se conoce como superli-
near speedup.
Parte II

Herramientas
4.2 Escalabilidad 25

En esta parte se describen algunas herramientas para la implementación de algoritmos para-


lelos. Se describen algunos compiladores paralelizantes, bibiotecas y sistemas de desarrollo, como
MPI (Message Passing Interface) y OpenMP.
Se dedica un capítulo a la instalación y uso de clusters basados en computadoras personales.

You might also like