Monografias.com > Sin categoría
Descargar Imprimir Comentar Ver trabajos relacionados

Introducción a la programación HPC (página 2)




Enviado por Pablo Turmero



Partes: 1, 2

Monografias.com

Tendencias en el software que complementan las del Hardware
Las aplicaciones cada vez son + escalables
Muchas nuevas aplicaciones son inherentemente escalables
Aplicaciones de búsqueda
Minería de datos
Ejemplos
Servidores de aplicaciones, web, BBDD
Google
Minería de contenidos multimedia
Muchas aplicaciones existentes, middleware y SO están siendo modificadas para ser + escalables:
Oracle y apache, pasaron de un modelo basado en procesos a hilos

Monografias.com

Ejemplo Arquitectura Software/Hardware escalable (webges)
(Gp:)

DB2 UDBMaxappls

CICS
SERVER

jdbc + ctg
db2jd
(Gp:)

DB2
OS/390

(Gp:)
power 6
16 cores
32 threads
ORACLE

Fonts Dades
Servidors Aplicacions
Servidors WEB
THREAD
LIMIT
AUTOMAT
(Gp:)
LDAP
server2

Switch Level 4 / pound
Balanceig Càrrega
(Gp:)

LDAP
server1

pugin-cfg.xml
RACF
OS/390 Z890
FireWall PIX Cisco
(Gp:)

(Gp:) Explica

(Gp:)

DB2
persistencia
sessions

(Gp:) JVMn
(Gp:) JMVx
(Gp:) JVM1, JVMx
(Gp:) JVMm

AIX pseries
4 cores, 8 threads
(power 5)
WAS Grid
(Gp:)
Cluster
servidors web
Linux/Apache
Dual-core AMD

webges01

webges11

Webges..

Soporta + d 500 peticiones x segundo

Monografias.com

Programación paralela
Según la wikipedia:
es una técnica de programación basada en la ejecución simultánea, bien sea en un mismo ordenador (con uno o varios procesadores) o en un cluster de ordenadores, en cuyo caso se denomina computación distribuida. Al contrario que en la programación concurrente, esta técnica enfatiza la verdadera simultaneidad en el tiempo de la ejecución de las tareas.
Los sistemas con multiprocesador y multicomputadores consiguen un aumento del rendimiento si se utilizan estas técnicas. En los sistemas monoprocesador el beneficio en rendimiento no es tan evidente, ya que la CPU es compartida por múltiples procesos en el tiempo, lo que se denomina multiplexación o multiprogramación.
El mayor problema de la computación paralela radica en la complejidad de sincronizar unas tareas con otras, ya sea mediante secciones críticas, semáforos o paso de mensajes, para garantizar la exclusión mutua en las zonas del código en las que sea necesario.
Objetivo: reducir el tiempo de ejecución

Monografias.com

Un ejemplo
public class MyThread extends Thread{
static final int CPU=5,N=100000000;
private int[] A=new int[N];
private int[] B=new int[N];
SynchronizedCounter var=new SynchronizedCounter();
public void run(){
int roll= var.readANDadd(); //Atomic. Avoid condition race with mutex
System.out.println("roll="+roll+" n");
for (int i=(roll*(N/CPU)); i < ((roll+1)*(N/CPU));i++){
if ((i % 1000000) == 0) System.out.println("roll= "+roll+" i="+i+" n");
B[i]=i; A[i]=B[i]*i;
}
}
public static void main(String[] args) {
for (int i=0;i< CPU;i++) { MyThread worker=new MyThread(); worker.start(); }
}
public static class SynchronizedCounter { //Binary Object lock
private static int c;
public synchronized int readANDadd(){ //Not concurrent code.
return c++; //First return current value, then increment
}
}
}
javac MyThread.java
java –Xmx 512 MyThread

Monografias.com

Modificación concurrente de datos compartidos
Thread 1: load value of i into a register on processor 1 (lets call it r1) [i=1, r1=1]
Thread 2: load value of i into a register on processor 2 (lets call it r2) [i=1, r1=1, r2=1]
Thread 1: increment r1 by 1 [i=1, r1=2, r2=1]
Thread 2: increment r2 by 1 [i=1, r1=2, r2=2]
Thread 1: store value in r1 back into i [i=2, r1=2, r2=2]
Thread 2: store value in r1 back into i [i=2, r1=2, r2=2]

2 threads intentando incrementar el valor de la variable i=1 (i++)
Th 1 i++; (i=2)
Th 2 i++; (i=3)
Problema: Cuando graben el valor en memoria i=2, cuando tendría q valer 3 !
Solución: Crear una sección crítica de manera q la operación d lectura y incremento sea atómica.
¿Cómo? Mediante semáforos

Monografias.com

Solución: Serializar acceso a datos compartidos
Cuando N threads modifican los mismos datos en paralelo, el resultado es impredecible
Solución: Pasar de ejecución paralela a secuencial con un semáforo
Como norma general, los N threads se ejecutaran en paralelo cuando modifiquen “su parte” d datos del problema y en secuencial cuando modifiquen datos compartidos

Monografias.com

¿ Para qué sirve la computación paralela ?
2 motivos principales
Reducir el tiempo de ejecución
Resolver problemas cada vez mas grandes y complejos
Otros
Utilizar recursos remotos – utilizando recursos disponibles en WAN
Reducción de costos – utilizando muchos nodos baratos en vez de un supercomputador caro
Salvar las restricciones de memoria – 1 servidor tiene recursos de memoria finitos. Para problemas grandes, utilizando la memoria de N servidores ayuda a superar este obstáculo

Monografias.com

Taxonomía Flynn
SISD Computador secuencial
SIMD Computadores vectoriales (NEC, Fujitsu, Cray),
procesadores con instrucciones de extensión
multimedia (SSE3, Altivec), GPU’s
MIMD Multiprocesadores, clusters, multi-core

Monografias.com

Arquitecturas de memoria compartida
Espacio de memoria global para todos los procesadores

Ventajas: fácil programación; Desventajas: escalabilidad, precio

Tipos:
UMA: Uniform Memory Access
NUMA: Non-Uniform Memory Access
cc-NUMA: Cache Coherent NUMA

Monografias.com

NUMA
Acceder de la CPU0 a la memoria d la:
CPU0:Muy rápido
CPU1:rápido
CPU2: rápido
CPU3: Menos rápido (2 saltos)

Monografias.com

Arquitecturas de Memoria Distribuida
Se requiere una red de comunicación para que los procesadores
puedan acceder a la memoria no local

Características
No existe el concepto de memoria global
Procesadores independientes (no coherencia)
El programador explicita el intercambio de datos
Ventajas: escalabilidad, precio; Desventajas: programación

Monografias.com

Arq. Híbridas: Distributed-Shared Memory
Combinación de los dos modelos:

Características
Cada nodo es un multiprocesador (p.e. cc-NUMA)
Comunicación para mover datos de un nodo a otro
Actualmente, los supercomputadores suelen seguir este modelo
Ejemplos:
Multivac, Tirant

Monografias.com

Paradigmas de Programación Paralela
Principales paradigmas o modelos de programación paralela:
Hilos (threads)
Paso de mensajes
Características:
Son una abstracción sobre la arquitectura
No hay una relación directa con la arquitectura (p.e. paso de mensajes sobre memoria compartida)
cesar.uv.es
En debian: apt-cache search mpich-shmem-bin
mpich-shmem-bin – MPI parallel computing system implementation, SHMEM version

No se puede hablar de “el mejor paradigma”

Monografias.com

Paradigmas de programación paralela
Hilos
Un proceso puede tener múltiples caminos de ejecución
Todos los hilos comparten el mismo espacio de memoria
Necesidad de sincronizar el acceso a la memoria mediante semáforos
Se utilizan normalmente en arquitecturas de memoria compartida
Estándares:
Posix Threads: + flexible
OpenMP: + sencillo
Paso mensajes
Un conjunto de tareas que utilizan su propia memoria local para cálculos
Diversas tareas pueden residir en la misma máquina física, así como también en un número arbitrario de máquinas distintas (clusters)
Las tareas intercambian datos mediante el paso de mensajes
Estándares: PVM y MPI

Monografias.com

Hilos vs Paso de mensajes
Hilos
No hay necesidad de comunicación explícita
Todos acceden al espacio de datos del problema (memoria compartida)
1 proceso, se encarga de crear los hilos necesarios para balancear la computación necesaria para resolver el problema
Paso mensajes
1 proceso se encarga de distribuir (enviando mensajes) los datos del problema a los restantes N-1 procesos remotos
Cuando los procesos terminan la computación necesaria para resolver su parte del problema, envían los resultados de vuelta

Monografias.com

Metodologías de Programación Paralela
Los paradigmas se pueden abordar con diferentes metodologías
Paralelización automática (compilador paralelizante)
Paralelización semi-automática (directivas de compilador)
Lenguajes de programación nuevos
Extensión de lenguajes estándar
Librerías de subrutinas o funciones (API)
Ejemplos
OpenMP está basado en directivas
MPI y Posix Threads están basados en librerías de funciones

Monografias.com

Single/Multiple Program Multiple Data
Son modelos de programación de más alto nivel, aplicables a cualesquiera de los paradigmas descritos
SPMD: el mismo
programa se ejecuta
por todas las tareas
MPMD: cada tarea
puede tener un
programa distinto
Los programas SPMD son más fáciles de mantener
Suelen instrucciones condicionales
pid=fork(); if (pid ==0) {printf(“Childn”);}else{printf(“Mastern”);}

Monografias.com

Single Program Multiple Data

Monografias.com

Esquemas de Programación Paralela
La paralelización (manual) suele implicar:
Particionado (de datos y/o tareas)
Comunicación y/o sincronización
En la práctica, hay algunos esquemas de paralelización que aparecen recurrentemente
Granja de tareas (maestro-trabajadores)
Segmentación (pipelining)
Divide y vencerás (encontrar máximo)
Otros: Ramificación y poda, algoritmos genéticos, autómatas celulares

Monografias.com

Granja de tareas (maestro-trabajadores)
Esquema + habitual en prog. paralela
Particionado: Repartir el espacio de datos del problema entre N trabajadores
Cada uno normalmente ejecuta el mismo código pero sobre su parte de los datos

El maestro se encarga del particionado y la planificación de los trabajadores
En memoria compartida no se requiere comunicación para el particionado
Necesidad de sincronizar el acceso a la memoria compartida
Necesidad de balancear y sincronizar correctamente la ejecución de tareas

Monografias.com

Maestro-esclavo con fork()
#include < stdio.h>
#define N 10
int main(){
int pid,i=0; /* identificador del proceso */
pid = fork();
while (i++ < N){
if ( pid < 0 ) { printf("Cannot fork !!n"); exit(1); }
if ( pid == 0 ) {
/* Proceso hijo */
printf("I am child number %d n",i);
fflush(stdout);
} else {
/* Proceso padre */
printf("I am the father with PID:%dn",pid);
fflush(stdout);
}
}
return 0;
}

Para optimizar la llamadaal sistema fork() linux utiliza la técnica d copy_on_write
Añadir un sleep(1); para q los mensajes se intercalen

Monografias.com

Ejemplo Maestro-esclavo: Aplicar 1 transformación a 1000 matrices d 1000×20
sub transform() {
my $i=0;

while ( $i < $f ){
# I want to create N slaves (childs) to parallelize the work
my $pid=fork();

if ($pid == 0 ){
# We are the child
do_work($i);
exit 0 ;

} else {
$i++;
$nchilds++ ;
if ( $nchilds < $CPUS ){
next ; # If there are less childs than CPU, we continue
} else {
# If the number of childs is equal to the number of CPUS -> we must wait,
# until a child ends. This is, we stop forking until a child ends its work.
wait ;
$nchilds–;
}
}
} #f
}

El maestro se encarga d la creación y planificación d esclavos
Para cada matriz, se crea un esclavo (hilo) para transformarla
Se permiten hasta un máximo d N threads, donde N es igual al numero d CPUs

Monografias.com

Trabajo a realizar x cada esclavo
sub do_work {
my $i=shift;
my $aux=0;
my $T="$txt"."/T"."$i" ;
open(FILE,"< $T");
$T="$mod_txt"."/T"."$i" ;
open(FILEMOD,">$T");

while (< FILE>) {
my $line = $_;
chomp $line;
my @FIELDS = split(' ');

foreach my $field (@FIELDS){
# Apply transformation: Matrix x Scalar
$aux=$field*10;
print FILEMOD $aux." ";
}
print FILEMOD "n" ;

} # < FILE>

close(FILE);
close(FILEMOD);
}

Monografias.com

Inicialización: Construcción d las 1000 matrices d 1000×20 (T0 ..T999)
sub build_dataset() {
my $i=0, $j=0 , $k=0;
#create auxiliary directories.
`rm -r $txt ` ; `rm -r $mod_txt ` ;
`mkdir -p $txt` ; `mkdir -p $mod_txt` ;
while ($i < $f){
my $T="$txt"."/T"."$i" ;
open(FILE,">$T");
$j=0 ;
while ($j < $n){
$k=0 ;
while($k < $m){
print FILE $j." " ;
$k++ ;
} # k
print FILE "n" ;
$j++ ;
} # j
close(FILE);
$i++ ;
} # i
}

Monografias.com

Maestro-esclavo: Transformación 1000 matrices
(Gp:) T0
(Gp:) T1
(Gp:) T2
(Gp:) …………
(Gp:) T999

(Gp:) T0
(Gp:) T4
(Gp:) T8
(Gp:) …………
(Gp:) T996
(Gp:) T1
(Gp:) T5
(Gp:) T9
(Gp:) …………
(Gp:) T997
(Gp:) T2
(Gp:) T6
(Gp:) T10
(Gp:) …………
(Gp:) T998
(Gp:) T3
(Gp:) T7
(Gp:) T11
(Gp:) …………
(Gp:) T999

Suponiendo q cada transformación sobrela tabla (matriz) tarde 30 segundos
Versión secuencial: 1000 x 30 = 30000 s.
Tiempo total= 8 h y 20 minutos
Versión paralela para 4 CPUs:
30000 / 4 =7500 segundos
Tiempo total= 2 horas y 5 minutos
Análisis temporal:

Monografias.com

Segmentación
Técnica originalmente utilizada en el diseño de procesadores
Consiste en dividir un trabajo en N etapas
Existe una relación de orden:
Una etapa no puede empezar hasta q no termine la predecesora

Versión secuencial:
2 instrucciones en 15 ciclos
Versión segmentada:
5 instrucciones terminadas enlos mismos ciclos de reloj
http://cse.stanford.edu/class/sophomore-college/projects-00/risc/pipelining/pipelining1.mov

Monografias.com

Problema transformación matrices
Número Tablas = 24 , T=10.000 s = S1 + S2 + S3 (3 Etapas)
Step 1: matrix por escalar
Step 2: Transformar la matriz en aleatoria
Step 3: Ordenar las filas d la matriz

Versión Secuencial = 240.000 s
Versión segmentada = 240.000 / 3 = 80.000 + 6666 = 86666 (teórico)

(Gp:) T0/s1
(Gp:) T1/s1
(Gp:) T2/s1
(Gp:) …………
(Gp:) T23/s1
(Gp:) T0/s2
(Gp:) T1/s2
(Gp:) T2/s2
(Gp:) …………
(Gp:) T23/s1
(Gp:) T0/s3
(Gp:) T1/s3
(Gp:) T2/s3
(Gp:) …………
(Gp:) T23/s3

Monografias.com

Segmentación + superescalar
HW: Lanzar N instrucciones en cada ciclo de reloj
SW: Lanzar N hilos, cada uno de ellos segmentado
Versión segmentada:
10 instrucciones terminadas enlos mismos ciclos de reloj

Monografias.com

Problema matrices: combinar maestro-esclavo con segmentación
Solución algorítmica
Crear tantos procedimientos maestro – esclavos como etapas
Cada procedimiento maestro-esclavo se encargará de realizar la transformación correspondiente
Cada procedimiento lanzará a su vez N (4 en el ejemplo) trabajadores
Programaremos barreras para garantizar el orden de las transformaciones
evitar q una etapa se ejecute antes q su predecesora
(Gp:) T0/s1
(Gp:) T4/s1
(Gp:) T8/s1
(Gp:) …………
(Gp:) T20/s1
(Gp:) T1/s1
(Gp:) T5/s1
(Gp:) T9/s1
(Gp:) …………
(Gp:) T21/s1
(Gp:) T2/s1
(Gp:) T6/s1
(Gp:) T10/s1
(Gp:) …………
(Gp:) T22/s1
(Gp:) T3/s1
(Gp:) T7/s1
(Gp:) T11/s1
(Gp:) …………
(Gp:) T23/s1
(Gp:) T0/s2
(Gp:) T4/s2
(Gp:) T8/s2
(Gp:) …………
(Gp:) T20/s2
(Gp:) T1/s2
(Gp:) T5/s2
(Gp:) T9/s2
(Gp:) …………
(Gp:) T21/s2
(Gp:) T2/s2
(Gp:) T6/s2
(Gp:) T10/s2
(Gp:) …………
(Gp:) T22/s2
(Gp:) T3/s2
(Gp:) T7/s2
(Gp:) T11/s2
(Gp:) …………
(Gp:) T23/s2
(Gp:) T0/s3
(Gp:) T4/s3
(Gp:) T8/s3
(Gp:) …………
(Gp:) T20/s3
(Gp:) T1/s3
(Gp:) T5/s3
(Gp:) T9/s3
(Gp:) …………
(Gp:) T21/s3
(Gp:) T2/s3
(Gp:) T6/s3
(Gp:) T10/s3
(Gp:) …………
(Gp:) T22/s3
(Gp:) T3/s3
(Gp:) T7/s3
(Gp:) T11/s3
(Gp:) …………
(Gp:) T23/s3

$myproc->start(&matrix_X_scalar);

$myproc->start(&rand_matrix);

sort_matrix_rows;

Monografias.com

maestro-esclavo con segmentación
sub sort_matrix_rows(){
my $i=0; my $aux=0; my $nchilds=0 ;
`rm -r $inorder_txt`; `mkdir -p $inorder_txt`;
while ( $i < $f ){
# I am the master. I want to create N slaves (childs) to parallelize the work
my $pid=fork();
if ($pid == 0 ){
# We are the child. Barrier to wait until rand_matrix step finishes with table Ti
$aux=$i+1;
if (($aux < $f ) && ($rand_matrix_finished == 0)) { while (! -e "$random_txt"."/T"."$aux" ) { sleep(1); } }
do_sort_matrix_rows_work($i);
exit 0 ;
} else {
$i++;
$nchilds++ ;
if ( $nchilds < $CPUS ){
next ;
} else {
# Wai t until a child ends. This is, we stop forking until a child ends its work.
wait ;
$nchilds–;
}
}
} #f
}

Monografias.com

Problema matrices: combinar maestro-esclavo con segmentación
(Gp:) T0/s1
(Gp:) T4/s1
(Gp:) T8/s1
(Gp:) …………
(Gp:) T20/s1
(Gp:) T1/s1
(Gp:) T5/s1
(Gp:) T9/s1
(Gp:) …………
(Gp:) T21/s1
(Gp:) T2/s1
(Gp:) T6/s1
(Gp:) T10/s1
(Gp:) …………
(Gp:) T22/s1
(Gp:) T3/s1
(Gp:) T7/s1
(Gp:) T11/s1
(Gp:) …………
(Gp:) T23/s1
(Gp:) T0/s2
(Gp:) T4/s2
(Gp:) T8/s2
(Gp:) …………
(Gp:) T20/s2
(Gp:) T1/s2
(Gp:) T5/s2
(Gp:) T9/s2
(Gp:) …………
(Gp:) T21/s2
(Gp:) T2/s2
(Gp:) T6/s2
(Gp:) T10/s2
(Gp:) …………
(Gp:) T22/s2
(Gp:) T3/s2
(Gp:) T7/s2
(Gp:) T11/s2
(Gp:) …………
(Gp:) T23/s2
(Gp:) T0/s3
(Gp:) T4/s3
(Gp:) T8/s3
(Gp:) …………
(Gp:) T20/s3
(Gp:) T1/s3
(Gp:) T5/s3
(Gp:) T9/s3
(Gp:) …………
(Gp:) T21/s3
(Gp:) T2/s3
(Gp:) T6/s3
(Gp:) T10/s3
(Gp:) …………
(Gp:) T22/s3
(Gp:) T3/s3
(Gp:) T7/s3
(Gp:) T11/s3
(Gp:) …………
(Gp:) T23/s3

$myproc->start(&matrix_X_scalar);

$myproc->start(&rand_matrix);

# Barrier to wait until rand_matrix step finishes with table Ti
$aux=$i+1;
if (($aux < $f ) && ($rand_matrix_finished == 0)) {
while (! -e "$random_txt"."/T"."$aux" ) { sleep(1);}
}

Necesitaremos 2 barreras
# Barrier to wait until matrix_X_scalar step finishes with table Ti
$aux=$i+1;
if (($aux < $f ) && ($rand_matrix_finished == 0)) {
while (! -e "$random_txt"."/T"."$aux" ) { sleep(1); }
}
$myproc->start(&sort_matrix);

Monografias.com

Problema matrices: combinar maestro-esclavo con segmentación
Número Tablas = 24 , T=10.000 s = S1 + S2 + S3
Versión Secuencial = 120.000 s
(Gp:) T0/s1
(Gp:) T4/s1
(Gp:) T8/s1
(Gp:) …………
(Gp:) T20/s1
(Gp:) T1/s1
(Gp:) T5/s1
(Gp:) T9/s1
(Gp:) …………
(Gp:) T21/s1
(Gp:) T2/s1
(Gp:) T6/s1
(Gp:) T10/s1
(Gp:) …………
(Gp:) T22/s1
(Gp:) T3/s1
(Gp:) T7/s1
(Gp:) T11/s1
(Gp:) …………
(Gp:) T23/s1

(Gp:) T0/s2
(Gp:) T4/s2
(Gp:) T8/s2
(Gp:) …………
(Gp:) T20/s2
(Gp:) T1/s2
(Gp:) T5/s2
(Gp:) T9/s2
(Gp:) …………
(Gp:) T21/s2
(Gp:) T2/s2
(Gp:) T6/s2
(Gp:) T10/s2
(Gp:) …………
(Gp:) T22/s2
(Gp:) T3/s2
(Gp:) T7/s2
(Gp:) T11/s2
(Gp:) …………
(Gp:) T23/s2

(Gp:) T0/s3
(Gp:) T4/s3
(Gp:) T8/s3
(Gp:) …………
(Gp:) T20/s3
(Gp:) T1/s3
(Gp:) T5/s3
(Gp:) T9/s3
(Gp:) …………
(Gp:) T21/s3
(Gp:) T2/s3
(Gp:) T6/s3
(Gp:) T10/s3
(Gp:) …………
(Gp:) T22/s3
(Gp:) T3/s3
(Gp:) T7/s3
(Gp:) T11/s3
(Gp:) …………
(Gp:) T23/s3

Maestro-esclavo segmentado
= 120.000 / 4 = 30.000 / 3 = 10.000 + 6666 = 10666 (teórico)

Monografias.com

Monografias.com

Replica – Versión secuencial
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics

(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics

t0
t1
Tiempo
Solamente se ejecuta un proceso, en un determinado instante de tiempo
En este espacio de tiempo, hemos conseguido procesar casi 2 tablas
Sin embargo, cada transformación (etapa) consume un determinado tipo de recurso : Export IXF -> Net , Load, Unload -> I/O, Index + Statistics -> CPU
Por ejemplo mientras descargamos los datos del origen (Export IXF), consumimos ancho de banda de la red, pero las CPUs y el I/O están ociosos.
Es decir, estamos desperdiciando recursos!!!

Monografias.com

Replica – Versión paralela
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics
(Gp:) Export
IXF
(Gp:) Load
IXF
(Gp:) Unload
TXT
(Gp:) Load
Target DB
(Gp:) INDEX
(Gp:) Statistics

t0
t1
t2
t3
t4
t5
t6
t7
Tiempo
En este espacio de tiempo, hemos conseguido procesar 10 tablas (teóricamente)

Monografias.com

Posix Threads
Objetivos
Comprender las ventajas de desarrollar aplicaciones paralelas basadas en hilos
Estudiar el estandard POSIX para hilos, llamado Pthreads
Estudiar las primitivas de control de threads: creación, terminación, join, sincronización, concurrencia, etc ..
Aprender a diseñar aplicaciones multi-hilo

Monografias.com

Threads
Un thread es una unidad de trabajo para la CPU
Consiste en un flujo de instrucciones y un estado (pila, contador de programa y conjunto de registros).
Los procesos tradicionales de UNIX están basados en 1 hilo q tiene la posesión de toda la memoria y recursos del proceso
Los threads contenidos en un proceso pueden ser ejecutados y planificados independientemente
Muchos threads comparten el mismo espacio de memória
Además de para desarrollar aplicaciones HPC, se utilizan en otro SW: BBDD, servidores Web y de aplicaciones

Monografias.com

Monohilo versus Multihilo

Monografias.com

Planificación de threads
Los threads son ejecutados y planificados independientemente

Processor affinity
Modificación al planificador d Linux q permite indicar el procesador preferido para una tarea (proceso o thread)

Monografias.com

Ventajas threads -> rendimiento
El cambio de contexto es muy pesado (ineficiente) en el caso de procesos

Hay q guardarla memoria del proceso y su estado a disco
Leer el estado de disco del siguiente y ponerlo en memoria para q se pueda ejecutar
I/O mucho + lenta q CPU

Monografias.com

Ventajas threads -> rendimiento
Cambio de contexto mucho más eficiente
Simplemente hay q cambiar el estado del thread ( conjunto de registros + puntero d pila)
Como la memoria es común a los 2 threads no hay q guardarla en disco cuando cambiamos de contexto

Monografias.com

Librería de Pthreads
Una API estándar POSIX (IEEE 1003.1c), para la creación y sincronización de hilos
La API especifica el comportamiento de la librería de hilos
La implementación es responsabilidad del desarrollador
Portable: Corre en todos los UNIX: Linux, Solaris, z/os UNIX Services, etc ..
Simplemente una colección de funciones en C

Monografias.com

Utilización de pthreads
Siempre incluir la libreria: #include < pthread.h>
Compilar: gcc program.c -lpthread
int pthread_create (pthread_t *tp, const pthread_attr_t * attr, void *(* start_routine)(void *), void *arg);
Crea un nuevo hilo de ejecución que acaba llamando a la función start_routine
Retorna 0, si todo ha ido bien. En la variable tp, retorna el identificador dl thread.
Attr es para modificar los atributos del nuevo thread. Si le pasamos NULL, se utilizan los atributos por defecto
Arg, sirve para pasar los argumentos a la función (staart_routine) a ejecutar por el thread
Ejemplo: pthread_create(&thread, NULL, do_work, (void*)&i);
int pthread_join(pthread_t thid, void ** status);
Se espera hasta q el thread (thid) termine
Suspende la ejecución del thread actual, hasta q el thread indicado en thid no termine su ejecución
Ejemplo: pthread_join(thread, &status);
void pthread_exit(void * status);
Termina la ejecución del thread actual
No es obligatorio

Monografias.com

Un ejemplo
#include < stdio.h> /* standard I/O routines */
#include < pthread.h> /* pthread functions and data structures */

/* Shared memory */
#define CPU 3
#define N 100

void *do_work(void *data){
int roll=*((int *)data),i ; /* Private data */
for (i=0;i< N;i++){
printf("Hello World from Thread=%dn",roll);
sleep(1);
}
pthread_exit(NULL); /* terminate the thread */
}
/* like any C program, program's execution begins in main */
int main(){
int thr_id,i; /* thread ID for the newly created thread */
void * status;
pthread_t thread[CPU]; /* thread's structure */
/* create a new thread that will execute 'do_work(). */
for (i=0;i< CPU;i++)
thr_id = pthread_create(&thread[i], NULL, do_work, (void*)&i);
/* Waint until all threads had finished */
for (i=0;i< CPU;i++) pthread_join(thread[i],&status);
return 0;
}

N, CPU
proceso

Monografias.com

array.c
#include < stdio.h> /* standard I/O routines */
#include < stdlib.h>
#include < pthread.h> /* pthread functions and data structures */
#define __HPC__
#define CPU 10
unsigned long long N=(18000000000); unsigned long long M=10000000 ; unsigned long long j=0; unsigned long long c,*array;
void *do_work(void *data){
long long roll=*((long long*)data); unsigned long long i,j=0,begin,end,slices;
begin=(roll*(N/CPU)); end=((roll+1)*(N/CPU)); printf("roll=%lldn",roll);
#ifdef __HPC__
slices=end/M; while (j< slices) {
#endif
for (i=begin; i < end ;i++){
#ifndef __HPC__
if ((i % (unsigned long long) M ) == 0) { printf("roll=%lld i=%lldn",roll,i); fflush(stdout); }
#endif
array[i]=i;
}
#ifdef __HPC__
j++; begin=j*slices; end=(j+1)*slices; printf("roll=%lld i=%lldn",roll,i); fflush(stdout) ;
}
#endif
/* terminate the thread */
pthread_exit(NULL);
}

/* like any C program, program's execution begins in main */
int main(int argc, char* argv[]){
int thr_id; /* thread ID for the newly created thread */
void * status;
pthread_t thread[CPU]; /* thread's structure */
array = (unsigned long long *)malloc( N * sizeof(unsigned long long) );
if ( array ) {
/* create a new thread that will execute 'do_work()' */
for (j=0;j< CPU;j++)
thr_id = pthread_create(&thread[j], NULL, do_work, (long long *)&j);
} else { printf("Problem with malloc: cannot reserve memory n"); }
for (j=0;j< CPU;j++)
pthread_join(thread[j],&status);
/* NOT REACHED */
return 0;
}
Inicializa en paralelo un vector de enteros. Cada thread inicializa su trozo del vector
Desde roll*(N/CPU)
Hasta (roll+1)*(N/CPU)
Para el caso d N=100 y CPU=4
Th0=0 .. 24, Th1=25 .. 49,
Th2=50 .. 74, Th3=75 .. 99

Monografias.com

Ejercicio: Calcular el máximo de un array (I)
Pistas:
Utilizar como base el código array.c
Cada thread debe encontrar el máximo local (de su parte dl array)
Cada thread debe pasar su máximo local a main
Por ejemplo, guardándolo en otro array:
int localmax[CPU];
El main, debe esperar a q todos los hijos acaben, para calcular máximo global de todos los máximos locales

Monografias.com

Aplicar una transformación a 1000 matrices de 1000×1000
Estructuras de datos
#define N 1000 //1k
#define M 1000 //1k
typedef double matrix[N][N]; //Array of M matrix of NxN
matrix *amat[M];
Reserva de memoria
for (i=0;i< M;i++) amat[i]= (matrix *)malloc( N * N *sizeof(double) );
Acceder al elemento j,k de la matrix i: (*amat[i])[j][k]
Observad q amat[i] equivale a la dirección dl puntero. Mientras q (*amat[i]) es su contenido (dirección apuntada por este). En este caso equivale a la posición 0,0 d la matriz i
Transformación:
(*amat[i])[j][k]=(*amat[i])[j][k]*sin((float)k)*rand()*atan(rand()) ;
Ejercicio: Testear el algoritmo, variando el número de CPUs y midiendo tiempos. Disminuir N i M.

Monografias.com

Acceso a memoria compartida
El programador es responsible de sincronizar el acceso (proteger) a la memoria global compartida
¿Cómo?
Serializando el acceso mediante semáforos
La idea es evitar q 2 o +threads modifiquen una variable concurrentemente

Las variables declaradas dentrode la función del thread se llamandatos locales.
Son ubicados en la pila de cada thread. Por tanto, se mantienen allímientras dura la ejecución de este.

Monografias.com

Mutex example
#include < stdio.h> /* standard I/O routines */
#include < pthread.h> /* pthread functions and data structures */
#define CPU 4
long long N=1000000, c,*array,i=0;
pthread_mutex_t mutex;

void *do_work(void *data){
long long roll=*((long long*)data);
printf("roll=%dn",roll);
pthread_mutex_lock(& mutex);
for (i=0; i < N;i++){
if ((i % (N/10)) == 0) printf("roll=%d array[%lld]=%lld n",roll,i,array[i]);
array[i]++;
}
pthread_mutex_unlock(& mutex);
pthread_exit(NULL); /* terminate the thread */
}
int main(int argc, char* argv[]){
int thr_id; pthread_t thread[CPU]; void * status; long long i=0;
array = (long long *)malloc( N * sizeof(long long) ); memset(array,0,N*sizeof(long long));
if ( array ) {
for (i=0;i< CPU;i++) thr_id = pthread_create(&thread[i], NULL, do_work, (void*)&i);
} else { printf("Problem with malloc: cannot reserve memory n"); }
for (i=0;i< CPU;i++) pthread_join(thread[i],&status);
for (i=0; i < N;i++) if (array[i] != CPU ) printf("Wrong result array[%lld]=%lld != %d n",i,array[i],CPU);
return 0;
}

Distintos threads modificando
la variable compartida i
Serializar el acceso

Monografias.com

Ejercicio: Calcular el máximo de un array (II)
Pistas:
Utilizar como base el código array.c
Cada thread debe encontrar el máximo local (de su parte dl array)
Cada thread debe pasar su máximo local a main a través de una variable global
int max=0;
Si el máximo local es mayor q el global lo escribiremos en la variable max
Hay q proteger la comparación y la posible escritura del nuevo máximo para q sea “thread safe”
El main, debe esperar a q todos los hijos acaben, para después imprimir el valor de max

Monografias.com

Ejercicio: Multiplicación de matrices cuadradas
Pistas:
Definición de matrices:
#define SIZE 10
int A[SIZE][SIZE], B[SIZE][SIZE], C[SIZE][SIZE];
Particionado
Cada thread debe ejecutar el algoritmo sobre su parte de el problema (el nº de filas q le toquen)
Algoritmo a ejecutar x cada thread (do_work):

for (i=from; i< to; i++)
for (j=0; j< SIZE; j++) {
C[i][j]=0;
for (k=0; k< SIZE; k++)
C[i][j] += A[i][k]*B[k][j];
}

Monografias.com

Estadísticashttp://www.top500.org/stats

Monografias.com

Familia de procesadores
Supervivientes: x86 (AMD,intel), power, Itanic

Monografias.com

Número de procesadores

Monografias.com

Redes de interconexión

Monografias.com

Sistemas Operativos

Monografias.com

Lenguajes de programación

Monografias.com

Inhibidores de paralelismo

Monografias.com

Mercado:

Monografias.com

Monografias.com

MPI
Previamente PVM: Parallel Virtual Machine.
MPI: Message Passing Interface.
Una especificación para paso de mansajes.
La primera librería de paso de mensajes estándar y portable.
Por consenso MPI Forum. Participantes de unas 40 organizaciones.

Monografias.com

Paradigma de paso de mensajes
Probablemente más extendido hoy día en programación de aplicaciones paralelas.
Consiste en una serie de procesos que interactúan por medio de mensajes.
Cada proceso puede ejecutar código distinto y sobre diferentes datos.
El modelo de paso de mensajes es valido tanto para sistemas de memoria compartida como para sistemas de memoria distribuida (cluster & grid computing).
El intercambio de mensajes es cooperativo: los datos deben ser tanto enviados como recibidos explícitamente.
Esto supone una ventaja en cuanto a que la modificación en la memoria del proceso es conocida por este.

Monografias.com

MPI
Estandarización.
Portabilidad: multiprocesadores, multicomputadores, redes, heterogéneos, …
Buenas prestaciones, …, si están disponibles para el sistema.
Amplia funcionalidad.
Implementaciones libres (mpich, lam, …)

Monografias.com

Comunicaciones básicas en MPI
Los datos son transferidos de un procesador a otro
Un procesador envía datos
Otro recibe los datos
Síncrona
La llamada no retorna hasta q el mensaje no es enviado o recibido
Asíncrono
La llamada indica el comienzo del envío o de la recepción
Hay q realizar una llamada adicional para determinar si la comunicación ha terminado

Monografias.com

Tipos de comunicaciones
La comunicación MPI entre procesos puede ser de dos tipos:
Punto a punto: el proceso “origen” conoce el identificador del proceso “destino” y envía un mensaje dirigido solo a él. Se usan las funciones MPI_Send y MPI_Recv.
Típicamente un master envía la parte correspondiente de los datos del problema a sus esclavos.
Colectiva: Operaciones en las que participan todos los procesos de un operador. Ejemplo:
“Broadcast”: El proceso origen manda el mensaje a todos los demás (que pertenezcan al mismo comunicador). Esto es típico de un esquema “master-slave”. Se usa la función MPI_Bcast.
Típicamente un master envía los mismos datos a sus esclavos.

Las funciones MPI de recepción de datos son por lo general “bloqueantes”, es decir, un proceso que debe recibir un mensaje espera hasta que de hecho lo ha recibido completo.

Monografias.com

MPI: Funciones básicas
Funciones básicas:
MPI_Init => Inicialización de MPI.
MPI_Finalize => Termina MPI.
MPI_Comm_size => Para averiguar el número de procesos.
MPI_Comm_rank => Identifica el proceso.
MPI_Send => Envía un mensaje.
MPI_Recv => Recibe un mensaje.
Referencia del estándar en
http://www-unix.mcs.anl.gov/mpi/
Con estas 6 funciones se puede hacer casi cualquier programa

Monografias.com

Escribiendo programas en MPI
De las 6 funciones básicas que mencionamos antes MPI_Init y MPI_Finalize son imprescindibles para que haya un programa MPI.
Veamos un ejemplo trivial

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

int main( int argc, char **argv )
{
MPI_Init( &argc, &argv );
printf( "Hola Mundon" );
MPI_Finalize();
return 0;
}

Monografias.com

Corriendo programas en MPI
El programa anterior solo inicializa y termina el entorno MPI. Entre tanto cada proceso imprime un mensaje por pantalla.
Compilación
Para un programa pequeño como este podemos hacer una llamada directamente al comando de compilación:
mpicc o gcc –lmpi o icc –lmpi (para programas C)
mpif77 (Fortran 77)
mpif90 (Fortran 90)
Para aplicaciones más complicadas conviene usar un Makefile.
En nuestro caso anterior (fichero hello.c):
icc -lmpi hello.c
gcc –lmpi hello.c

Monografias.com

Corriendo programas en MPI
Ejecución
El modelo de ejecución de MPI sigue un esquema de creación (spawn) simultánea de procesos al lanzar la aplicación
La ejecución de una aplicación suele hacerse con:
mpirun -np p programa [opciones]
-np N: N indica el número de procesos que se quiere en la ejecución del programa.
Ejemplo: mpirun -np 2 ./a.out
Al ejecutar una aplicación:
Se lanzan p copias del mismo ejecutable (p.e. con ssh)
Se crea un comunicador MPI_COMM_WORLD que engloba a todos los procesos

Monografias.com

Modelo de Programación – Comunicadores
Un comunicador es una abstracción que engloba los siguientes conceptos:
Grupo: conjunto de procesos
Contexto: para evitar interferencias entre mensajes distintos
Un comunicador agrupa a p procesos
int MPI_Comm_size(MPI_Comm comm, int *size)
Cada proceso tiene un identificador (rango), un número entre 0 y p – 1
int MPI_Comm_rank(MPI_Comm comm, int *rank)

Monografias.com

Hello.c (II)
#include < stdio.h>
#include < mpi.h>
int main (argc, argv)
int argc;
char *argv[]; {
int rank, size;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
printf( "Hello world from process %d of %dn", rank, size );
MPI_Finalize();
return 0;
}
Ejecutar este ejemplo:
gcc –lmpi hello.c
mpirun -np 2 ./a.out
Averiguaremos desde el programa el número de procesos que participan y la identificación de cada uno.

Monografias.com

MPI_Send
La operación básica de envío (bloqueante) es:
MPI_Send( start, count, datatype, dest, tag, comm )
start: puntero a los datos a enviar
count: número de elementos a enviar
datatype: tipo de dato
dest: Identificación del proceso destino
tag: etiqueta de la comunicación
comm: Identificación del comunicador

Monografias.com

MPI_Recv
La operación básica de recepción correspondiente:
MPI_Recv(start, count, datatype, source, tag, comm, status)
start: puntero para la recepción de los datos
count: número de elementos
datatype: tipo de dato
source: Identificación del proceso origen
tag: etiqueta de la comunicación
comm: Identificación del comunicador
status: puntero para acceso a información sobre mensaje

Monografias.com

Envio de mensajes: N hijos enviando saludos al padre

#include < stdio.h>
#include < string.h>
#include "mpi.h"
main(int argc, char*argv[]) {

int myrank, p, source, dest, tag = 0;
char message[100];
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
MPI_Comm_size(MPI_COMM_WORLD,&p);

if (myrank != 0) {
printf("Processor %d of %dn",myrank, p);
sprintf(message,"greetings from process %d!",
myrank);
dest = 0;
MPI_Send(message, strlen(message)+1,
MPI_CHAR, dest, tag,
MPI_COMM_WORLD);
} else {
printf("processor 0, p = %d ",p);
for(source=1; source < p; source++) {
MPI_Recv(message,100, MPI_CHAR, source,
tag, MPI_COMM_WORLD, &status);
printf("%sn",message);
}
}
MPI_Finalize();
}
Processor 2 of 4
Processor 3 of 4
Processor 1 of 4
processor 0, p = 4 greetings from process 1!
greetings from process 2!
greetings from process 3!

mpicc -o hello hello.c
mpirun -np 4 hello

Monografias.com

Tipos de datos MPI
Se definen los siguientes tipos de datos MPI:
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED
MPI_UNSIGNED_LONG
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
MPI_BYTE
MPI_PACKED
Corresponde a los de C, pero se añaden el tipo byte, y el empaquetado, que permite enviar simultáneamente datos de distintos tipos.

Monografias.com

Programación paralela con MPI
Típicamente se utiliza el modelo maestro-trabajadores
El maestro distribuye a cada trabajador su parte del problema MPI_Send
Los hijos reciben su parte d datos dl problema MPI_Recv
Los hijos hacen transformaciones sobre la parte de datos q les ha enviado el maestro
Posteriormente, los trabajadores le envían el resultado de las transformaciones al maestro
Es similar al maestro-trabajadores de memoria compartida, con las comunicaciones se hacen de manera explícita ya q no tenemos acceso a la memoria compartida

Monografias.com

Broadcast
start: puntero a los datos a enviar
count: número de elementos a enviar
datatype: tipo de dato
root: identificación del proceso origen
comm: Identificación del comunicador
#include < stdio.h>
#include "mpi.h"

#define N 10
int array[N];

int main() {
int rank,i;

MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
if (rank == 0 ) {
//Only master performs array initialitation
for (i=0;i< N;i++) array[i]=i;
}
MPI_Bcast( array , N, MPI_INT , 0, MPI_COMM_WORLD );
for (i=0;i< N;i++) {
printf("rank:%d array[%d]=%dn ",rank,i,array[i]);
//Until all threads arrive at this point, we will wait!
MPI_Barrier(MPI_COMM_WORLD);
}
MPI_Finalize( );
return 0;
}
MPI_Bcast(start, count, datatype, root, comm)

Monografias.com

MPI Scatter
Repartir datos sobre todos los procesos
Calcular max array:
El master reparte con MPI_Scatter, la porción correspondiente del array a cada esclavo
if (rank == 0 ) {
//Only master performs array initialitation
array=(double *)malloc(N*sizeof(double));
for (i=0;i< N;i++)
array[i]=(double)i;//rand();
porcio=(double *)malloc((N/nprocs)*sizeof(double));
MPI_Scatter(array, N/nprocs, MPI_DOUBLE, porcio, N/nprocs, MPI_DOUBLE, 0, MPI_COMM_WORLD);
// En la variable porcio, todas las tareas reciben su parte del array (N/procs elementos)

Monografias.com

MPI_Gatther
MPI_Gather – obtener datos de todos los procesos. MPI_Scatter
….
max_array=(double *)malloc(nprocs*sizeof(double));
double maximum=-1;
for (i=0;i< N/nprocs;i++) {
printf("Valor actual:%f, Valor max:%f, en i=%dn",porcio[i],maximum,i);
maximum=max(maximum,porcio[i]);
}
printf("Local maximum: %f from rank:%dn",maximum,rank); MPI_Gather(&maximum,1,MPI_DOUBLE,max_array,1,MPI_DOUBLE,0,MPI_COMM_WORLD);
//En la variable max_array recibimos todos los máximos locales de todas las tareas
….

Monografias.com

Calcular el máximo de una array con MPI
#include < stdio.h>
#include "mpi.h"

#define N 10
#define max(a,b) (a>b ? a : b)

int main(int argc,char *argv[]) {
int rank,i,nprocs;
double *array, *porcio, *max_array;

MPI_Init( &argc, &argv );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &nprocs);

if (rank == 0 ) {
//Only master performs array initialitation
array=(double *)malloc(N*sizeof(double));
if (array == NULL) { printf("Can't allocate memoryn");
return -1;}
for (i=0;i< N;i++)
array[i]=(double)i;//rand();

max_array=(double *)malloc(nprocs*sizeof(double));
}

// All processes in communicator
porcio=(double *)malloc((N/nprocs)*sizeof(double));

MPI_Scatter(array, N/nprocs, MPI_DOUBLE, porcio, N/nprocs, MPI_DOUBLE, 0, MPI_COMM_WORLD);

double maximum=-1;
for (i=0;i< N/nprocs;i++) {
printf("Valor actual:%f, Valor max:%f, en i=%dn",porcio[i],maximum,i);
maximum=max(maximum,porcio[i]);
}
printf("Local maximum: %f from rank:%dn",maximum,rank); MPI_Gather(&maximum,1,MPI_DOUBLE,max_array,1,MPI_DOUBLE,0,
MPI_COMM_WORLD);

if(rank==0){
for (i=1;i< nprocs;i++)
maximum=max(maximum,max_array[i]);
printf("Maximum:%fn",maximum);
}

MPI_Finalize( );
return 0;
}

Monografias.com

Repartir M matrices entre N procesos
#include < stdio.h>
#include < mpi.h>
#include < stdlib.h>
#include < math.h>
#define N 10
#define M 10
int CPU=0;
typedef double matrix[N][N]; //Array d M matrices d NxN
matrix *amat[M];

#define print_matrix(slice_mat,i,M,N,myrank,j,k,nprocs) do {
printf( "Received matrix %d of %d. My rank:%d. Proceding to print it!n“
,i,M,myrank);
for (j=0;j< N;j++){
printf("nt| ");
for (k=0;k< N;k++)
printf("M[%d][%d]=%f ",j,k,(*slice_mat[i/nprocs])[j][k]);
printf("|");
}
} while (0)

Monografias.com

Repartir M matrices entre N procesos

if (myrank==(i%nprocs)) {
printf( "Receiving matrix %d of %d. My rank:%dn", i,M,myrank);
slice_mat[i/nprocs]= (double *)malloc( N * N *sizeof(double) );
MPI_Recv(slice_mat[i/nprocs],N*N,MPI_DOUBLE,0,i,MPI_COMM_WORLD,&status);
print_matrix(slice_mat,i,M,N,myrank,j,k,nprocs);
}
}

MPI_Finalize();
return 0;
}
int main (argc, argv)
int argc;
char *argv[];
{
int myrank, nprocs,i,j,k;
MPI_Status status;
double p,*aux;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &myrank); MPI_Comm_size (MPI_COMM_WORLD, &nprocs); CPU=nprocs;
matrix *slice_mat[M/CPU];
printf("Rank:%d nprocs %dn",myrank,nprocs);
fflush(stdout);
for (i=0;i< M;i++) {
if (myrank == 0) {
// master
amat[i]= (double *)malloc( N * N *sizeof(double) );
for (j=0;j< N;j++)
for(k=0;k< N;k++)
(*amat[i])[j][k]=i;

MPI_Send(amat[i], N*N, MPI_DOUBLE,i%nprocs,i ,MPI_COMM_WORLD);
}

Monografias.com

Aplicar una transformación a 1000 matrices de 1000×1000 usando MPI
Estructuras de datos
#define N 1000 //1k
#define M 1000 //1k
typedef double matrix[N][N]; //Array of M matrix of NxN
matrix *amat[M];
Transformación:
(*amat[i])[j][k]=(*amat[i])[j][k]*sin((float)k)*rand()*atan(rand()) ;
Adaptaremos el código desarrollado en Posix Threads para ejecutarlo en MPI
Simplemente necesitamos añadir la parte de comunicación explícita, mediante el envio de mensajes
Ejercicio: Testear el algoritmo, variando el número de CPUs y midiendo tiempos. Disminuir N i M.

Monografias.com

Variables + Trabajo a realizar por cada hijo
#include < stdio.h>
#include < mpi.h>
#include < stdlib.h>
#include < malloc.h>
#include < math.h>
#define N 10 //1M
#define M 10 //1K
typedef double matrix[N][N]; //Array d M matrices d NxN
matrix *amat[M];
int CPU=0;

void * do_work(int roll, matrix *slice_mat[]) {
int i,j,k,m,n;
double max=0 ;
printf("roll=%dn",roll);
fflush(stdout);
for (i=0; i < (M/CPU);i++){
for (j=0; j< N;j++)
for (k=0;k< N;k++)
(*slice_mat[i])[j][k]=(*slice_mat[i])[j][k] * sin((float)k) * rand() * atan(rand()) ;
for (m=0; m< N ; m++)
for (n=0; n< N; n++)
if ((*slice_mat[i])[m][n] > max ) max=(*slice_mat[i])[m][n];
}
printf("Max= %fn",max);
fflush(stdout);
}

Monografias.com

Comunicaciones + transformaciones
int main (argc, argv) int argc; char *argv[]; {
int myrank, nprocs,i,j; MPI_Status status; double p,* aux;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &myrank);
MPI_Comm_size (MPI_COMM_WORLD, &nprocs);
CPU=nprocs;
matrix *slice_mat[M/CPU];
printf("Rank:%d nprocs %dn",myrank,nprocs);
fflush(stdout);
for (i=0;i< M;i++) {
if (myrank == 0) {
// master
amat[i]= (matrix *)malloc( N * N *sizeof(double) );
aux=amat[i];
p=rand();
for (j=0;j< N*N;j++) aux[j]=p;
MPI_Send((*amat[i]), N*N, MPI_DOUBLE,i%nprocs,i ,MPI_COMM_WORLD);
}

if (myrank==(i%nprocs)) {
printf( "Receiving matrix %d of %d. My rank:%dn",
i,M,myrank);
slice_mat[i/nprocs]= (double *)malloc( N * N *sizeof(double) );
MPI_Recv((*slice_mat[i/nprocs]),N*N,MPI_DOUBLE,0,i,
MPI_COMM_WORLD,&status);
}
}
for (i=0;i< M/CPU;i++)
do_work(i,slice_mat);
//TODO: Send back results to master
MPI_Finalize();
return 0;
}
Ejercicio: Enviar los datos de vuelta al maestro.

Monografias.com

MPI_Allgather

Monografias.com

MPI_Reduce

Monografias.com

Bibliografia
Básica:
google
Ian Foster:  Designing and Building Parallel Programs. 1995.
Kumar, Grama, Gupta, Karypis: Introduction to Parallel Computing. Design and Analysis of Algorithms. The Benjamin Cumming Publishing Company. 1994.
Barry Wilkinson, Michael Allen: Parallel programming. Prentice-Hall. 1999.
Complementaria:
Akl: Diseño y análisis de algoritmos paralelos. Ra-ma. 1992.
Andrews: Foundations of Multithreaded, Parallel, and Distributed Programming. Addison-Wesley, 2000
Bertsekas, Tsilikis: Parallel and Distributed Computation. Prentice-Hall. 1989.
Rajkumar Buyya (Editor): High Performance Cluster Computing, Vol 2, Programming and Applications. Prentice Hall. 1999.
Gibbons, Rytter: Efficient Parallel Algorithms. Cambridge University press. 1988.
Ja-Ja: An Introduction to Parallel Algorithms. Addison-Wesley. 1992.
Lester: The art of Parallel Programming. Prentice-Hall. 1993.
Modi: Parallel Algorithms for Matrix Computation. Oxford University Press. 1989.
Quinn: Design of Efficient Algorithms. McGraw-Hill. 1987.

Partes: 1, 2
 Página anterior Volver al principio del trabajoPágina siguiente 

Nota al lector: es posible que esta página no contenga todos los componentes del trabajo original (pies de página, avanzadas formulas matemáticas, esquemas o tablas complejas, etc.). Recuerde que para ver el trabajo en su versión original completa, puede descargarlo desde el menú superior.

Todos los documentos disponibles en este sitio expresan los puntos de vista de sus respectivos autores y no de Monografias.com. El objetivo de Monografias.com es poner el conocimiento a disposición de toda su comunidad. Queda bajo la responsabilidad de cada lector el eventual uso que se le de a esta información. Asimismo, es obligatoria la cita del autor del contenido y de Monografias.com como fuentes de información.

Categorias
Newsletter