lunes, 23 de mayo de 2011

Message Passing Interface (MPI)

Que tal amigos el dia de hoy vengo a hablarles un poco sobre el paradigma de programacion paralela de memoria distribuida con MPI. Si estas leyendo este post es por que por lo menos has programado, pienso que no necesitas ser todo un Lord en la programación, para entender por lo menos las ideas basicas de lo que se planteará a continuación.

Recuerda que si existe la posibilidad de que algunas cosas no las entiendas en este momento, pero si quieres puedes consultar con San Google y el te respondera tus peticiones.

MPI 

The Message Passing Interface, o MPI por sus siglas, es una interfaz de paso de mensajes entre procesadores, es uno de los protocolos de comunicación en paralelo más utilizados y principalmente se usa para la programacion paralela con memoria distribuida, aunque también se puede utilizar para programación paralela de memoria compartida.

MPI, es un conjunto de subrutinas y librerias que pueden ser llamadas desde FORTRAN o C/C++.
Nota: ojo no es un lenguaje.
El programador puede realizar su codigo e incluir las llamadas a la libreria de MPI y cuando éste se compile, ya sea con el compilador de FORTRAN o el de C/C++, este hará los vinculos correspondientes con la libreria.

Para dar inicio a tu primer código con MPI, deberas incluir la libreria
#include <mpi.h> /*para C/C++*/  
Y siempre para que MPI se inicie deberas hacer solo una llamada a la rutina MPI_Init. Esta rutina de MPI debe ser llamada antes que cualquier otra y para terminar el procesamiento de MPI, este se termina con una llamada a MPI_Finalize.

Ademas de estas dos importantes rutinas básicas, existen otras dos que nunca deben faltar:
MPI_Comm_size(comm, size)
MPI_Comm_rank(comm, rank)
La primera regresa el número de procesadores y se almacena en la variable size  así como un comunicador por default, comm=MPI_WORLD_COMM, el cual indica el conjunto de todos los procesadores asignados a la ejecución del programa. Posteriormente, el usuario puede definir otros comunicadores para designar subconjuntos de procesadores.
La segunda regresa el número lógico que corresponde a cada procesador. Este valor se almacena en la variable rank y siempre empieza en cero y alcanza un valor máximo igual al número de procesadores menos uno. Este es un esquema de un programa con MPI.
#include <mpi.h>
#include <stdio.h>
int main (int argc,char *argv[])
{int rank,size;
 ...
 MPI_Init(&argc,&argv);
 MPI_Comm_rank(MPI_COMM_WORLD, &rank);    
 MPI_Comm_size(MPI_COMM_WORLD, &size);
 ...
 MPI_Finalize();
 return 0; 

Para compilar y ejecutar es bastante sencillo, solo debes
mpicc -o programa programa.c
mpirun -np N programa
donde \[N\] es el número de procesadores. Si tu codigo esta en c++, deberas
mpic++ -o programa programa.cpp
mpirun -np N programa
donde \[N\] es el número de procesadores.

Ejemplo: HolaMundo.cpp

#include <mpi.h>
#include <iostream>
#include <stdio.h>

using namespace std;

int main (int argc,char *argv[])
{int rank,size;
 MPI_Init(&argc,&argv);
 MPI_Comm_size(MPI_COMM_WORLD, &size);
 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
 printf("Hola Mundo desde procesador %d\n",rank);
 MPI_Finalize();
 return 0;
}
Compilamos y ejecutamos
mpic++ -o Hola HolaMundo.cpp
mpirun -np 4 Hola
Salida
Hola Mundo desde procesador 1
Hola Mundo desde procesador 3
Hola Mundo desde procesador 2
Hola Mundo desde procesador 0
Una cosa debemos tener claro y es que MPI ejecuta el mismo programa en todos los procesadores, es responsabilidad del programador decidir que procesador hara alguna tarea respectiva. Bueno amigos, os dejo hasta aqui, hasta un nuevo post, posiblemente estare explicando algunas funciones basicas osbre MPI.

Ejemplos OpenMP

Amigos aquí les facilito tres códigos muy interesantes para analizar, se tratan sobre el famoso Hola Mundo, y   la aproximación de \[\pi\] mediante el método de rectangulos y de montecarlo.

Hola Mundo 

#include <omp.h>
#include <stdio.h>
 
int main (int argc, char *argv[]) 
{  int p,th_id;
   p=omp_get_num_procs(); 
   omp_set_num_threads(p);
   #pragma omp parallel private(th_id);
   {
     th_id = omp_get_thread_num();
     printf("Hello World from thread %d\n", th_id);
     }
   return 0;
 }

Aproximación de \[\pi\] por el método de rectangulos 

#include  <omp.h >
#include  <stdio.h >
#include  <time.h >
#include  <sys/time.h> 

int main (int argc, char *argv[]) 
{
    double area,x;
    int i,n;
    area = 0.0;
    printf("n="); scanf("%d",&n);
    #pragma omp parallel for private(x) reduction(+:area);
    for (i=0;i<n;i++) 
    {     x=(i+0.5)/n; 
          area += 4.0/(1.0+x*x);
    }
    printf("pi = %lf\n", area/n);
    return 0; 
}

Aproximación de \[\pi\] por el método de montecarlo. 

#include <stdlib.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
 int count;
 int i;
 int local_count;
 int samples;
 int t;
 int tid;
 double x,y;
 unsigned short xi[3];
 samples=atoi(argv[1]);
 omp_set_num_threads(atoi(argv[2]));
 count=0;
 #pragma omp parallel private(xi,t,i,x,y,local_count);
 {
 local_count=0;
 xi[0]=atoi(argv[3]);
 xi[1]=atoi(argv[4]);
 xi[2]=tid=omp_get_thread_num();
 t = omp_get_num_threads();
 for (i=tid;i<samples;i += t){
 x=erand48(xi);
   y=erand48(xi);
   if(x*x + y*y <= 1.0) local_count +=1;
  }
 #pragma omp critical
   count += local_count;
 }
 printf("Estimate of pi: %7.5f\n",4.0*count/samples);
}

domingo, 22 de mayo de 2011

Directivas OpenMP

Hola amigos en el post pasado estuve hablandoles un poco sobre algunas pragmas y mencione algunas clausulas utilizadas en OpenMP. Hoy regreso hablandoles un poco mas sobre ello, con algunos ejemplos y explicando algunas directivas.  Los ejemplos y algunos conceptos fueron tomados de esta fuente, puesto que me gusta mucho como explican y son bastante claros los ejemplos.

Directivas OpenMP

Directivas de reparto
Directiva for
La directiva for especifica que las iteraciones del bucle siguiente inmediatamente se deben ejecutar en paralelo por el grupo de procesadores.

Sintaxis 
#pragma omp for [clausulas]  newline 
                schedule (type ,[chunk]) 
                ordered
                private (list) 
                shared (list) 
                reduction (operator: list) 
               
                bucle for(){}

Ejemplo:
#include 
#define CHUNKSIZE 100
#define N  1000

main ()  
{
int i, chunk;
float a[N], b[N], c[N];

/* Some initializations */
for (i=0; i < N; i++)
  a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;

#pragma omp parallel shared(a,b,c,chunk) private(i)
  {
  #pragma omp for schedule(dynamic,chunk) nowait
  for (i=0; i < N; i++)
    c[i] = a[i] + b[i];
  }  /* end of parallel section */
}

Clausulas

schedule: Decide como se distribuiyen las iteraciones de un bucle entre los hilos la planificación por defecto depende de la implementación.
  • schedule(static,chunk) : distribuye un subconjunto de iteraciones en cada thread de modo circular. El tamaño viene dado por "chunk" si no se especifica chunk, la distribucion es por bloques.
  • schedule(dynamic,chunk) : El valor por defecto de chunk es 1, es casi igual que static, pero los bloques se reparten dinamicamente a medida que los hilos van finalizando.
  • schedule(guided,chunk) :  Con \[N\] iteraciones y \[p\] hilos se distribuye dinamicamente en \[\frac{N}{kp}\] iteraciones en cada hilo, donde \[k\] depende de la iteración.

Directiva sections
La directiva sections nos permite repartir o distribuir trozos de nuestro codigo. Este es un esquema de como trabajaria la diretiva sections.

float A[100];
#pragma omp parallel 
#pragma omp sections shared(A)
{   #pragma omp section
          calculamedia(A);
    #pragma omp section 
          calculamaximo(A);
    #pragma omp section
          calculadesviacion(A);
}

Directiva single
Sirve para que un solo hilo ejecute ese bloque.
#pragma omp single [clausulas]
      {bloque estructurado}

Directiva reduction
Inicialmente las iteraciones del bucle paralelo se distribuirán en bloques de igual tamaño para cada hilo.
Al final del bucle paralelo, todos los hilo compartiran sus valores de "resultado" para actualizar la copia global el hilo maestro

#include <omp.h>
#include <stdio.h>

int main ()  {
int   i, n, chunk;
float a[100], b[100], result;

/* Some initializations */
n = 100;
chunk = 10;
result = 0.0;
for (i=0; i < n; i++)
  {
  a[i] = i * 1.0;
  b[i] = i * 2.0;
  } 
 
#pragma omp parallel for      \  
  default(shared) private(i)  \  
  schedule(static,chunk)      \  
  reduction(+:result)  

  for (i=0; i < n; i++)
    result = result + (a[i] * b[i]);

printf("Final result= %f\n",result);
}


Directivas de sincronización  master, critical, barrier, atomic, ordered.


Directiva master

Para esta directiva el bloque de codigo solo lo hace el maestro y no tiene barreras, los demas hilos saltan el bloque de codigo y continuan la ejecución del programa.
#pragma omp master
      {bloque estructurado} 
Directiva critical
Esta directiva especifica partes criticas del código, que los hilos deben ejecutar todos uno a la vez. A veces sirbe mas que todo para variables compartidas para que no hayan colisiones.
#pragma omp critical [nombre]
      {bloque estructurado} 
Directiva barrier
Esta directiva especifica una barrera en la que todos y cada uno de los hilos debera esperar al otro, una vez todos hayan llegado a la barrera, continuan su trabajo en paralelo.
#pragma omp barrier 

Directiva atomic
Asegura que una locación de memoria especifica, va a ser actualizada de forma atomica, es decir no se van a produsir multiples escrituras desde diferentes hilos. Si notan la diferencia, atomic sincroniza a través de variables compartidas y critical sincroniza a través de instrucciones.
  
#pragma omp atomic
      statement_expression 

Directiva ordered
Se utiliza dentro de bucles para que partes dentro del bucle se realicen en orden. 
#pragma omp for ordered [clauses...]
   (loop region)
#pragma omp ordered  newline
   structured_block
   (endo of loop region) 

Bueno amigos esto es todo por hoy, hasta un nuevo post posiblemente sea una recopilación de algunos códigos que he ejecutado con OpenMP y mas adelante estare hablando sobre MPI hasta una nueva ocasión.

Sumario :

Sintaxis General de Pragmas de OpenMP en C/C++


Que tal amigos, hoy vengo a hablarles un poco sobre algunas pragmas de OpenMP. Esencialmente OpenMP consta de tres elementos.
  1. Control de Paralelismo  
    • Directivas parallel 
    • Directivas de reparto de trabajo. Ejemplo Directiva "for" 
  2.  Control de datos y comunicaciones
    • Variables privadas y compartidas
  3. Sincronización 
    • Para coordinar el acceso a los datos (Barreras, secciones, críticas, etc.)
 La directiva parallel es aquella que define una region paralela. Sintaxis:

//C/C++
#pragma omp parallel[clausulas]
{ //bloque estructurado
}

Una región paralela es un bloque de codigo ejecutado en paralelo por varios hilos. Para las directivas parallel simplemente hay repetición del bloque de codigo, aun no hay repartición de trabajo. 

Clausulas Posibles de : "Parallel[ Clausulas ]"
  • IF(expresion escalar logica)
  • NUM_THREADS(Expresion escalar entera)
  • SHARED(Lista de Variables)
  • PRIVATE(Lista de Variables)
  • DEFAULT(Private|Sharede|None)
  • FIRST PRIVATE(Lista de variables)
  • REDUCTION(operador: Lista de variables)
Ejemplo
Para el siguiente codigo no nesecitamos saber que hace la función Calcula(), los que nos interesa saber que es lo que esta sucediendo al incluir la directiva parallel antes del bloque estructurado.Suponga que tenemos el siguiente bloque de código.
double A[100];
omp_set_num_threads(4);
#pragma omp parallel private(id) shared(A)
{ id = omp_get_thread_num();
  calcula(A,id);
}
printf("\nFinalizado");

La directiva omp_set_num__theads(4)establece el numero de hilos y como se declaro la variable id privada se crean 4 copias para cada hilo, la variable A se declaro compartida, asi que cada procesador podra ver la misma dirección de memoria.

Expliquemos un poco lo que sucede:
  • Al llegar a la región paralela se cream 4 hilos
  • Cada hilo ejecuta el codigo dentro del bloque estructurado
  • Se llama a la funcion calcula() para id=1,2,3 o 4.
 
En OpenMP cuando el hilo maestro encuentra una región paralela este queda identificado con el numero cero (0). En OpenMP tambien se pueden tener hilos anidados es decir cuando un hilo encuentra otra region paralela, en este caso este hilo se convierte en un hilo maestro para este nuevo grupo de hilos, pero no es identificado con cero sino con el mismo identificador que tenia.

Directivas de Reparto de Trabajo

Las directivas do/for, sections, single etc. hacen parte de las directivas de reparto de OpenMP y como su nombre lo dice, reparten y distribuyen el trabajo entre los procesadores. Por ejemplo:
#pragma omp for[clausulas]
for(iteraciones del bucle, se reparten entre hilos)
{}
Las clausulas que soporta son las mismas especificadas anteriormente. Las restricciones para las directivas de reparto es que la variable de control del bucle o lazo debe ser de tipo entero y el bucle debe ser un bloque estructurado y no puede usar algun "exit" o un "goto" o algun "break" para salir del lazo.

Nota: Los indices de control del for siempre son variables privadas.

Hola mundo paralelo.
Aqui les dejo un primer codigo usando OpenMP.
#include 
#include 

 int main (int argc, char *argv[])
{
   int id;
   omp_set_num_threads(4);
   #pragma omp parallel private(id)
   {
     id = omp_get_thread_num();
     printf("Hola Mundo desde id: %d\n", id);
   }
   return 0;
}
Y lo compilan de la siguiente forma:
 g++ -fopenmp Hola.cpp -o Hola
 ./Hola
Hasta una nueva sección amigos, en el nuevo post les seguire hablando mucho mas sobre las variables privadas y compartidas y de algunas directivas de sincronización. Nos vemos...

Programación de Memoria Compartida con OpenMP


Saludos nuevamente estoy por aca... hoy vengo a hablarles un poco sobre un conjunto de directivas que podemos añadir a nuestros codigos en C/C++ o FORTRAM, para paralelizar nuestros algoritmos en un paradigma de memoria compartida, este conjunto de directivas se llama OpenMP.


OpenMP

Como mencione al principio OpenMP, es un conjunto de directivas estandar para la programación paralela de memoria compartida. Existen otras formas de mas bajo nivel como POSIX que sirven para paralelizar, sin embargo POXIS es mucho mas robusto que OpenMP y ademas a pesar de que también se incluyen directivas como OpenMP, al incluirlas en nuestro codigo este no seria portable, es decir solo serviria en maquinas con el mismo sistema operativo.

A diferencia de esto OpenMP si es estandar, es mucho mas sencillo y si responde a la necesidad de portabilidad. se puede correr en cualquier tipo de maquina, incluye menos directivas que otros lenguajes, no modifica el código principal, pues si lo agregamos las directivas como comentarios dentro del archivo, este dejaría el codigo tal y como es. (El Secuencial).  OpenMP es el que las grandes compañias han buscado estandarizar.


Un poco mas sobre OpenMP

La idea clara que debemos tener sobre OpenMP, es que es un conjunto de directivas, librerias y variables de entorno para programar de forma paralela en FORTRAB, C/C++.

Actualmente es el estandar para programación de sistemas de memoria comapartida y sistemas de memoria compartida fisicamente distribuida. OpenMP es diseñada por lo miembros del OpenMP Architecture Review Board (OpenMP ARB). La misión de la ARB es estandarizar las API para el multiprocesamiento de memoria compartida.
Las especificaciones son gratuitas y no requieren licencia.
Historia  
  • 1997 OpenMP 1.0 FORTRAM
  • 1998 OpemMP 1.0 C/C++
  • 1999 OpenMP 1.1 FORTRAM
  • 2002 OpenMP 2.0 C/C++
  • 2005 OpenMP 2.5 F,C/C++
OpenMP utiliza el modelo de programación Fork-Join. Los que saben un poco mas a fondo sobre esto, saben que a nivel de sistema la funcion fork() crea un proceso independiente, por tanto el sistema funcionaria asi:
  1. Un programa comienza su ejecución con un proceso unico (Hilo Maestro)
  2. Cuando se encuentra la primera construcción paralela, crea un conjunto de hilos.
  3. El trabajo se reparte entre todos los hilos incluido el maestro.
  4. Cuando termina la region paralela el solo hilo maestro continua la ejecución.
Modelo Fork-Join
En forma general, normalmente OpenMP se emplea en la paralelización de lazoos y bucles. Es decir se buscan los lazos, computacionalmente mas costosos y se reparten sus iteraciones entre hilos.

En estos momentos no conocemos mucho sobre sus directivas, puesto que hablare de ellas mas adelante en otro post, sin embargo estos son dos breves ejemplos de como seria un codigo secuencial y otro paralelizado con OpenMP.

Solo se detalla la funcion main, buscando enfatizar la directiva que paralelizaria el codigo.

/*Codigo Secuencial*/
int main() 
{ int i; double suma[1000]; 
  for (i=0; i<1000; i++)
  CalculaSuma(Suma(i)); 
}

/*Codigo Paralelizado*/
int main() 
{ int i; double suma[1000]; 
  #pragma omp parallel for  /*Incluimos la directiva pragma*/
  for (i=0; i<1000; i++)
  CalculaSuma(Suma(i)); 
}

Lo que sucede en el primer código es que se ejecuta el bloque en un solo procesador, mientras que en el segundo la directiva #pragma reparte las iteraciones del for entre los hilos que se encuentren disponibles.

Bueno amigos, nos vemos hasta un nuevo post, posiblemente estaré hablando mas sobre OpenMP, algunas directivas, ejemplos y finalmente de como compilamos nuestro código, en otras palabras nuestro primer HOLA MUNDO PARALELIZADO!!! .

Tipos de Arquitecturas Paralelas

Que tal amigos siguiendo el tema sobre High Performance Computing que se comento en el anterior post, hoy vengo a hablarles un poco sobre algunos tipos de arquitecturas paralelas. Siendo un poco sincero con ustedes, de arquitectura de computadoras solo conosco lo básico, pero esto que compartire con ustedes fue lo que aprendi tomando un curso en la universidad y viendo uno que otro curso virtual (Videos, Presentaciones etc.)

Pienso, que seria bueno simplemente explicar o definir que trata cada uno de estos tipos de arquitectura y hablar un poco sobre estos paradigmas de programacion paralela, asi quedaremos con la idea general de lo que tratan exactamente cada uno de ellos.

Como primero vamos con:

MEMORIA COMPARTIDA: Costa de simplemente un memoria unica y global, la cual es accesible desde todos los procesadores, si quieren pueden leer un poco mas acerca de (UMA Uniform Memory Access).
En este esquema cada procesador tiene el mismo tiempo para acceder a una dirección de memoria.

MEMORIA DISTRIBUIDA: Este esquema consta de tantas memorias como procesadores se tenga, en la cual cada procesador accede exactamente a su memoria local.
Para que P1 acceda a M2 lo debe acceder a través de P2 por medio de la comunicación de mensajes entre procesadores.

MEMORIA COMPARTIDA-DISTRIBUIDA: En este caso, la memoria esta fisicamente distribuida pero logicamente compartida.

En este esquema hay Hardware especial para que los procesadores vean a todas las memorias como una sola memoria global, sin embargo la velocidad para acceder a la memoria de otro procesador sera mucho mayor respecto a la memoria local correspondiente.

Bueno ya que tenemos una leve idea de como visualizar estos sistemas y que tanto tiempo se lleva un procesador para acceder a la memoria, hablemos un poco sobre estos paradigmas.

Paradigmas de Programación Paralela

Paradigma Memoria Compartida
  
En este esquema la coordinación y cooperación entre los procesos se realiza a travéz de la lectura y escritura de variables compartidas e a través de variables de sincronización.

  • Ejemplo: En un problema de sumatoria cada proceso debe cooperar compartiendo los datos. Suponga una suma parcial suma1 y otra suma parcial suma2, para obtener la suma global hay un modo de compartir estos dos datos a través de la memoria global, de tal manera que un procesador pueda al final acceder a los dos datos y luego sumarlos. Cuando nos referimos a variables de sincronización, se refiere a la sincronizació en acceso, ya que un procesador no podría sumar las sumas parciales hasta que todos los procesos no hayan culminado. 
 
Paradigma Memoria Distribuida

En este esquema la coordinación y cooperación entre procesos se realiza a través del envio y recepción de mensajes.
P1 conoce la información de M2, a través del envío y recepción de mensajesentre P1 y P2.

Bueno espero que tengan ahora una leve idea sobre estos paradigmas de programación paralela, pueden fortalecer este conocimiento, leyendo acerca de UMA (Uniform Memory Acces) y NUMA (Non Uniform Memory Acces). Hasta un nuevo post, creo que estare hablando sobre Programación de Memoria Compartida con OpenMP. Nos vemos!

sábado, 21 de mayo de 2011

High Performance Computing

Hola nuevamente a toda la comunidad, estaba un poco retirado de blog, la razón es por que he tenido muchisimos compromisos este semestre y no he tenido tiempo de editarlo, sin embargo aqui tienen una nueva entrada, espero que les guste... se trata de High Performance Computing. Iniciemos este post hablando un poco sobre la computación paralela. Una idea bastante general de la computación paralela es producir el mismo resultado de un programa secuencial, pero usando multiples procesadores de tal forma que las instrucciones se puedan repartir entre estos procesadores y asi obtener el mismo resultado, pero esto con un solo objetivo reducir el tiempo de ejecución. Niveles de Paralelismo.
  1. Nivel de aplicación dentro de un Computador.
  2. Nivel de programa o tarea dentro de una aplicación.
  3. Nivel de procedimiento dentro de un programa.
  4. Nivel de lazo dentro de un programa.
Para el primer nivel se produce entre aplicaciones independientes es decir queremos ejecutar varios programas a la vez, entonces podriamos asignar una aplicación a cada procesador, esto seria algo de paralelismo. Para el segundo trata de paralelismo entre tareas distintas que cooperan. Para el tercero son fragmentos de codigo o subrutinas, por ejemplo: Calculo de notas de estudiantes, la media, desviación  etc. Y finalmente para el cuarto corresponde a las iteraciones dentro de un lazo, por ejmplo: dividir las iteraciones entre dos procesadores, un procesador hace las sumas con números pares y otro hace la suma con números impares, se acumulan las sumas en variables como suma1 y suma2 y luego un procesador suma ambas. Con esto el tiempo se reduciria a la mitad, comparandolo con el tiempo que le llevaria hacer esto al secuencial.

MEDIDAS DE RENDIMIENTO DE UN PROGRAMA.

ACELERACION: (Speed up) \[S(p) = \frac{T(1)}{T(p)}\] donde \[T(1)\] es el tiempo secuencial del programa y \[T(p)\] el tiempo que demora con \[p\] procesadores.
EFICIENCIA: \[E(p)=(\frac{S(p)}{p})100\%\].

Ejemplo:
  • Tiempo en 1 cpu = \[100_{seg} = T(1)\].
  • Tiempo en 15 cpu = \[12_{seg} = T(15)\].
Entonces la aceleración será de \[\frac{100}{12} = 8.3_{seg}\] y la eficiencia de \[(\frac{8.3}{15})100\% = 55.3\%\].

Podemos definir a la aceleración como la cantidad de veces mas rápido de un  programa en paralelo al secuencial. El caso ideal: \[S(p)=p\]. Y podemos definir a la eficiencia como aquella que mide que tan bien esta paralelizado nuestro programa, el caso ideal seria \[100\%\]. 

LEY DE AMDAL
"La eficiencia obtenida en una implementación paralela viene limitada por la parte secuencial, la cual es aquella parte del programa que no es paralelizable."

Siempre hay una fracción del programa que no es paralelizable
  1. Ejemplo: Podemos hacer sumas parciales en varios procesadores pero al final, hay un solo procesador el cual hae la suma global. Esta parte seria no paralelizable.
  2. Ejemplo: Suponga que el \[20\%\] de un código es secuencial, entonces \[T(1) = T(paralelo)+T(secuencial) = 80+20 \]. Usando \[p\] procesadores si \[p\rightarrow{}\infty\] entonces como: \[T(p)=\frac{S(p)}{p}+20\ge20\] es decir no pasa de 20. Y como \[S(p)=\frac{T(1)}{T(p)}=\frac{100}{\frac{80}{p} + 20}\leq5\] no pasaria de 5. Y luego \[E(p)=\frac{S(p)}{p}\leq S(p)\] tenderia a 0.

Si queremos obtener ganancias para el paralelismo dado un programa secuencial, hay que disminuir lo mas posible la parte secuencial.





Bueno muchachos los dejo hasta aquí, hasta mi nuevo post que tratara sobre Tipos de Arquitecturas paralelas.