Introducci - PowerPoint PPT Presentation

About This Presentation
Title:

Introducci

Description:

Title: Configuraci dels sistemes de informaci Last modified by: jvc Document presentation format: Presentaci n en pantalla Other titles: Times New Roman Tahoma ... – PowerPoint PPT presentation

Number of Views:29
Avg rating:3.0/5.0
Slides: 98
Provided by: uvEsvijo
Category:

less

Transcript and Presenter's Notes

Title: Introducci


1
Introducción a la programación HPC
  • Josep Vidal Canet
  • Alejandro Soriano
  • Universitat de València

2
Objetivos
  • Conocer los principios básicos que rigen la
    programación de altas prestaciones (HPC)
  • Hardware
  • Software
  • Conocer las tecnologías más utilizadas para
    implementar algoritmos paralelos
  • Posix Threads
  • MPI
  • OpenMP (Alex)
  • Las tendencias en el campo de HPC
  • Reducir el tiempo de ejecución

3
Motivación
  • Hay problemas que no se pueden resolver con un
    algorítmo secuencial
  • Predicción meteorológica
  • Hardware roadmap
  • Imposible seguir aumentando la velocidad del
    reloj a causa de la disipación de calor
  • Para aumentar el rendimiento -gt aumentar el
    número de cores y threads per core
  • Configuración PCs actuales 4 cores
  • Existen PCs (orientado segmento mercado
    profesional) con 8 cores (2 socket)
  • La tendencia del Hardware implica rediseñar el
    software para poder aprovechar toda la potencia
    del hardware
  • Pasar de aplicaciones secuenciales mono-hilo a
    paralelas multi-hilo
  • Actualmente existe software multihilo -gt
    servidores web, J2EE, BBDD, etc
  • En definitiva, paralelismo masivo en la era del
    paralelismo para las masas

4
Una nueva era en el diseño de sistemas
  • Los sistemas altamente paralelos construidos con
    múltiples procesadores pequeños, están ocupando
    un segmento cada vez mayor del mercado de
    servidores
  • 41,995.00 por 1 servidor con 32 cores basado en
    AMD
  • Generalmente, caracterizados por un rendimiento
    modesto en aplicaciones mono-hilo, buen
    rendimiento a nivel d chip (N cores) y excelente
    relación entre consumo/rendimiento
  • La tecnología de paralelismo, anteriormente
    utilizada en HPC (High Performance Computing) se
    está convirtiendo de uso generalizado en toda la
    pila de software.

5
Evolución numero de transistores en los
Microprocesadores
  • La litografía permitirá seguir escalando nº de
    transistores por chip (densidad)

dual-core Power6 tiene 790 millones
6
Tendencia en la frecuencia de reloj de los
procesadores
La disipación de calor limita el incremento en
las velocidades del reloj
7
Chip Power Density
La disipación de calor está limitando el aumento
de la frecuencia de los relojes, dando lugar a
la emergencia de chips multicore con menor
consumo de energía
Low power multicores replacing single high-power
cores
8
Tendencia en procesadores multicore
Cell 9 cores, 10 threads
9
Crecimiento del número de threads por procesador
Estamos entrando en la era de la computación
masivamente multithread
1 Ejemplo Sun Niagara 1 chip 8 cores x 8
threads/core 64 threads
10
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

11
Ejemplo Arquitectura Software/Hardware escalable
(webges)
Servidors Aplicacions
Fonts Dades
Servidors WEB
WAS Grid
webges01
Switch Level 4 / pound Balanceig Càrrega
jdbc ctg
db2jd
Webges..
FireWall PIX Cisco
webges11
AIX pseries 4 cores, 8 threads (power 5)
RACF
CICS SERVER
pugin-cfg.xml
OS/390 Z890
THREAD LIMIT AUTOMAT
Soporta d 500 peticiones x segundo
12
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

13
Un ejemplo
javac MyThread.java java Xmx 512 MyThread
public class MyThread extends Thread static
final int CPU5,N100000000 private int
Anew intN private int Bnew intN
SynchronizedCounter varnew 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 lt
((roll1)(N/CPU))i) if ((i
1000000) 0) System.out.println("roll
"roll" i"i" \n") Bii
AiBii public
static void main(String args) for
(int i0iltCPUi) MyThread workernew
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

14
Modificación concurrente de datos compartidos
  • 2 threads intentando incrementar el valor de la
    variable i1 (i)
  • Th 1 i (i2)
  • Th 2 i (i3)
  • Thread 1 load value of i into a register on
    processor 1 (lets call it r1) i1, r11
  • Thread 2 load value of i into a register on
    processor 2 (lets call it r2) i1, r11, r21
  • Thread 1 increment r1 by 1 i1, r12, r21
  • Thread 2 increment r2 by 1 i1, r12, r22
  • Thread 1 store value in r1 back into i i2,
    r12, r22
  • Thread 2 store value in r1 back into i i2,
    r12, r22
  • Problema Cuando graben el valor en memoria i2,
    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

15
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

16
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

17
Taxonomía Flynn
SISD Computador secuencial SIMD Computadores
vectoriales (NEC, Fujitsu, Cray), procesadores
con instrucciones de extensión multimedia (SSE3,
Altivec), GPUs MIMD Multiprocesadores,
clusters, multi-core
18
Arquitecturas de memoria compartida
Espacio de memoria global para todos los
procesadores
Tipos UMA Uniform Memory Access NUMA
Non-Uniform Memory Access cc-NUMA Cache Coherent
NUMA
Ventajas fácil programación Desventajas
escalabilidad, precio
19
NUMA
  • Acceder de la CPU0 a la memoria d la
  • CPU0Muy rápido
  • CPU1rápido
  • CPU2 rápido
  • CPU3 Menos rápido (2 saltos)

20
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
21
Arq. Híbridas Distributed-Shared Memory
Combinación de los dos modelos
Ejemplos Multivac, Tirant
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
22
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

23
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

24
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

25
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

26
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 pidf
ork() if (pid 0) printf(Child\n)elseprint
f(Master\n)
27
Single Program Multiple Data
28
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

29
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

30
Maestro-esclavo con fork()
  • include ltstdio.hgt
  • define N 10
  • int main()
  • int pid,i0 / identificador del proceso /
  • pid fork()
  • while (i lt N)
  • if ( pid lt 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
    PIDd\n",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
31
Ejemplo Maestro-esclavo Aplicar 1 transformación
a 1000 matrices d 1000x20
sub transform() my i0 while ( i lt
f ) I want to create N slaves
(childs) to parallelize the work my
pidfork() if (pid 0 )
We are the child do_work(i)
exit 0 else
i nchilds if (
nchilds lt CPUS ) next If
there are less childs than CPU, we continue
else If the number
of childs is equal to the number of CPUS -gt 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
32
Trabajo a realizar x cada esclavo
sub do_work my ishift my aux0
my T"txt"."/T"."i" open(FILE,"ltT")
T"mod_txt"."/T"."i" open(FILEMOD,"gtT")
while (ltFILEgt) my line _
chomp line my _at_FIELDS split('
') foreach my field (_at_FIELDS)
Apply transformation Matrix x Scalar
auxfield10 print FILEMOD
aux." " print FILEMOD "\n"
ltFILEgt close(FILE)
close(FILEMOD)
33
Inicialización Construcción d las 1000 matrices
d 1000x20 (T0 ..T999)
  • sub build_dataset()
  • my i0, j0 , k0
  • create auxiliary directories.
  • rm -r txt rm -r mod_txt
  • mkdir -p txt mkdir -p mod_txt
  • while (i lt f)
  • my T"txt"."/T"."i"
  • open(FILE,"gtT")
  • j0
  • while (j lt n)
  • k0
  • while(k lt m)
  • print FILE j." "
  • k
  • k
  • print FILE "\n"
  • j
  • j
  • close(FILE)

34
Maestro-esclavo Transformación 1000 matrices
Análisis temporal
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
Suponiendo q cada transformación sobrela tabla
(matriz) tarde 30 segundos
35
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/pr
ojects-00/risc/pipelining/pipelining1.mov
36
Problema transformación matrices
  • Número Tablas 24 , T10.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)
37
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
38
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

myproc-gtstart(\matrix_X_scalar)
myproc-gtstart(\rand_matrix)
sort_matrix_rows
39
maestro-esclavo con segmentación
sub sort_matrix_rows() my i0 my
aux0 my nchilds0 rm -r
inorder_txt mkdir -p inorder_txt
while ( i lt f ) I am the master. I
want to create N slaves (childs) to parallelize
the work my pidfork() if
(pid 0 ) We are the child.
Barrier to wait until rand_matrix step finishes
with table Ti auxi1
if ((aux lt 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 lt CPUS ) next
else Wai t until a
child ends. This is, we stop forking until a
child ends its work. wait
nchilds--
f
40
Problema matrices combinar maestro-esclavo con
segmentación
  • Necesitaremos 2 barreras

myproc-gtstart(\matrix_X_scalar)
myproc-gtstart(\rand_matrix)
Barrier to wait until matrix_X_scalar step
finishes with table Ti auxi1
if ((aux lt f ) (rand_matrix_finished
0)) while (! -e "random_txt"."/T"."aux"
) sleep(1)
myproc-gtstart(\sort_matrix)
Barrier to wait until rand_matrix step
finishes with table Ti auxi1
if ((aux lt f ) (rand_matrix_finished
0)) while (! -e "random_txt"."/T"."aux"
) sleep(1)
41
Problema matrices combinar maestro-esclavo con
segmentación
  • Número Tablas 24 , T10.000 s S1 S2 S3
  • Versión Secuencial 120.000 s

Maestro-esclavo segmentado 120.000 / 4
30.000 / 3 10.000 6666 10666 (teórico)
42
(No Transcript)
43
Replica Versión secuencial
Tiempo
t0
t1
  • 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 -gt
    Net , Load, Unload -gt I/O, Index Statistics -gt
    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!!!

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

45
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

46
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

47
Monohilo versus Multihilo
48
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)
49
Ventajas threads -gt 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

50
Ventajas threads -gt 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

51
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

52
Utilización de pthreads
  • Siempre incluir la libreria include ltpthread.hgt
  • 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

53
Un ejemplo
N, CPU
include ltstdio.hgt / standard I/O routines
/ include ltpthread.hgt /
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
(i0iltNi) printf("Hello World from
Threadd\n",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
threadCPU / thread's structure
/ / create a new thread that will
execute 'do_work(). / for (i0iltCPUi)
thr_id pthread_create(threadi, NULL,
do_work, (void)i) / Waint until all threads
had finished / for (i0iltCPUi)
pthread_join(threadi,status) return 0
proceso
54
array.c
include ltstdio.hgt / standard I/O routines
/ include ltstdlib.hgt include
ltpthread.hgt / pthread functions and data
structures / define __HPC__ define CPU 10
unsigned long long N(18000000000) unsigned
long long M10000000 unsigned long long j0
unsigned long long c,array void do_work(void
data) long long roll((long long)data)
unsigned long long i,j0,begin,end,slices
begin(roll(N/CPU)) end((roll1)(N/CPU))
printf("rolllld\n",roll) ifdef __HPC__
slicesend/M while (jltslices) endif for
(ibegin i lt end i) ifndef __HPC__ if
((i (unsigned long long) M ) 0)
printf("rolllld illd\n",roll,i)
fflush(stdout) endif arrayii
ifdef __HPC__ j beginjslices end(j1)s
lices printf("rolllld illd\n",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
threadCPU / 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 (j0jltCPUj)
thr_id pthread_create(threadj, NULL,
do_work, (long long )j) else
printf("Problem with malloc cannot reserve
memory \n") for (j0jltCPUj)
pthread_join(threadj,status) / NOT REACHED
/ return 0
  • Inicializa en paralelo un vector de enteros. Cada
    thread inicializa su trozo del vector
  • Desde roll(N/CPU)
  • Hasta (roll1)(N/CPU)
  • Para el caso d N100 y CPU4
  • Th00 .. 24, Th125 .. 49,
  • Th250 .. 74, Th375 .. 99

55
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 localmaxCPU
  • El main, debe esperar a q todos los hijos acaben,
    para calcular máximo global de todos los máximos
    locales

56
Aplicar una transformación a 1000 matrices de
1000x1000
  • Estructuras de datos
  • define N 1000 //1k
  • define M 1000 //1k
  • typedef double matrixNN //Array of M matrix
    of NxN
  • matrix amatM
  • Reserva de memoria
  • for (i0iltMi) amati (matrix )malloc(
    N N sizeof(double) )
  • Acceder al elemento j,k de la matrix i
    (amati)jk
  • Observad q amati equivale a la dirección dl
    puntero. Mientras q (amati) es su contenido
    (dirección apuntada por este). En este caso
    equivale a la posición 0,0 d la matriz i
  • Transformación
  • (amati)jk(amati)jksin((float)k)ra
    nd()atan(rand())
  • Ejercicio Testear el algoritmo, variando el
    número de CPUs y midiendo tiempos. Disminuir N i
    M.

57
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.

58
Mutex example
Distintos threads modificando la variable
compartida i
include ltstdio.hgt / standard I/O routines
/ include ltpthread.hgt /
pthread functions and data structures / define
CPU 4 long long N1000000, c,array,i0 pthread_
mutex_t mutex void do_work(void data) long
long roll((long long)data)
printf("rolld\n",roll) pthread_mutex_lock(
mutex) for (i0 i lt Ni) if ((i
(N/10)) 0) printf("rolld arraylldlld
\n",roll,i,arrayi) arrayi
pthread_mutex_unlock( mutex)
pthread_exit(NULL) / terminate the thread
/ int main(int argc, char argv) int
thr_id pthread_t threadCPU void status
long long i0 array (long long )malloc( N
sizeof(long long) ) memset(array,0,Nsizeof(lon
g long)) if ( array ) for
(i0iltCPUi) thr_id pthread_create(threadi
, NULL, do_work, (void)i) else
printf("Problem with malloc cannot reserve
memory \n") for (i0iltCPUi)
pthread_join(threadi,status) for (i0 i lt
Ni) if (arrayi ! CPU ) printf("Wrong
result arraylldlld ! d \n",i,arrayi,CPU)
return 0
Serializar el acceso
59
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 max0
  • 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

60
Ejercicio Multiplicación de matrices cuadradas
  • Pistas
  • Definición de matrices
  • define SIZE 10
  • int ASIZESIZE, BSIZESIZE, CSIZESIZE
  • 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 (ifrom iltto i) for (j0 jltSIZE
j) Cij0 for (k0 kltSIZE
k) Cij AikBkj
61
Estadísticashttp//www.top500.org/stats
62
Familia de procesadores
Supervivientes x86 (AMD,intel), power, Itanic
63
Número de procesadores
64
Redes de interconexión
65
Sistemas Operativos
66
Lenguajes de programación
67
Inhibidores de paralelismo
68
Mercado
69
(No Transcript)
70
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.

71
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.

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

73
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

74
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.

75
MPI Funciones básicas
  • Funciones básicas
  • MPI_Init gt Inicialización de MPI.
  • MPI_Finalize gt Termina MPI.
  • MPI_Comm_size gt Para averiguar el número de
    procesos.
  • MPI_Comm_rank gt Identifica el proceso.
  • MPI_Send gt Envía un mensaje.
  • MPI_Recv gt 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

76
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 ltstdio.hgt int main(
int argc, char argv ) MPI_Init( argc,
argv ) printf( "Hola Mundo\n" )
MPI_Finalize() return 0
77
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

78
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

79
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)

80
Hello.c (II)
Averiguaremos desde el programa el número de
procesos que participan y la identificación de
cada uno.
include ltstdio.hgt include ltmpi.hgt 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 d\n", rank, size )
MPI_Finalize() return 0
Ejecutar este ejemplo gcc lmpi hello.c mpirun
-np 2 ./a.out
81
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

82
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

83
Envio de mensajes N hijos enviando saludos al
padre
include ltstdio.hgt include ltstring.hgt include
"mpi.h" main(int argc, charargv) int
myrank, p, source, dest, tag 0 char
message100 MPI_Status status MPI_Init(argc,a
rgv) MPI_Comm_rank(MPI_COMM_WORLD,myrank) MPI_C
omm_size(MPI_COMM_WORLD,p)
if (myrank ! 0) printf("Processor d of
d\n",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(source1 source lt p source)
MPI_Recv(message,100, MPI_CHAR, source,
tag, MPI_COMM_WORLD, status)
printf("s\n",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
84
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.

85
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

86
Broadcast
include ltstdio.hgt include "mpi.h" define N
10 int arrayN 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 (i0iltNi)
arrayii MPI_Bcast( array , N,
MPI_INT , 0, MPI_COMM_WORLD ) for
(i0iltNi) printf("rankd
arraydd\n ",rank,i,arrayi)
//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)
  1. start puntero a los datos a enviar
  2. count número de elementos a enviar
  3. datatype tipo de dato
  4. root identificación del proceso origen
  5. comm Identificación del comunicador

87
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(Nsizeof(double)) for (i0iltNi)
arrayi(double)i//rand() porcio(dou
ble )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)
88
MPI_Gatther
 
  • MPI_Gather - obtener datos de todos los procesos.
    MPI_Scatter

. max_array(double )malloc(nprocssizeof(double
)) double maximum-1 for (i0iltN/nprocsi
) printf("Valor actualf, Valor
maxf, en id\n",porcioi,maximum,i)
maximummax(maximum,porcioi)
printf("Local maximum f from rankd\n",maximum,
rank) MPI_Gather(maximum,1,MPI_DOUBLE,max_arra
y,1,MPI_DOUBLE,0,MPI_COMM_WORLD) //En la
variable max_array recibimos todos los máximos
locales de todas las tareas .
89
Calcular el máximo de una array con MPI
include ltstdio.hgt include "mpi.h" define N
10 define max(a,b) (agtb ? 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(Nsizeof(double)) if (array
NULL) printf("Can't allocate memory\n")
return -1 for (i0iltNi)
arrayi(double)i//rand()
max_array(double )malloc(nprocssizeof(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
(i0iltN/nprocsi) printf("Valor
actualf, Valor maxf, en id\n",porcioi,maxi
mum,i) maximummax(maximum,porcioi)
printf("Local maximum f from
rankd\n",maximum,rank) MPI_Gather(maximum,1,
MPI_DOUBLE,max_array,1,MPI_DOUBLE,0, MPI_COMM_WORL
D) if(rank0) for
(i1iltnprocsi) maximummax(maximum
,max_arrayi) printf("Maximumf\n",maxi
mum) MPI_Finalize( ) return 0
90
Repartir M matrices entre N procesos
include ltstdio.hgt include ltmpi.hgt include
ltstdlib.hgt include ltmath.hgt define N
10 define M 10 int CPU0 typedef double
matrixNN //Array d M matrices d NxN matrix
amatM define print_matrix(slice_mat,i,M,N,my
rank,j,k,nprocs) do \ printf(
"Received matrix d of d. My rankd. Proceding
to print it!\n ,i,M,myrank) \ for
(j0jltNj) \ printf("\n\t ")
\ for (k0kltNk) \
printf("Mddf ",j,k,(slice_mati/nproc
s)jk) \ printf("") \
\ while (0)
91
Repartir M matrices entre N procesos
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)
CPUnprocs matrix slice_matM/CPU
printf("Rankd nprocs d\n",myrank,nprocs)
fflush(stdout) for (i0iltMi) if
(myrank 0) // master
amati (double )malloc( N N sizeof(double)
) for (j0jltNj)
for(k0kltNk)
(amati)jki MPI_Send(amati,
NN, MPI_DOUBLE,inprocs,i ,MPI_COMM_WORLD)

if (myrank(inprocs)) printf(
"Receiving matrix d of d. My rankd\n",
i,M,myrank) slice_mati/nprocs
(double )malloc( N N sizeof(double) )
MPI_Recv(slice_mati/nprocs,NN,MPI_DOUBLE,0,
i,MPI_COMM_WORLD,status)
print_matrix(slice_mat,i,M,N,myrank,j,k,nprocs)
MPI_Finalize() return 0
92
Aplicar una transformación a 1000 matrices de
1000x1000 usando MPI
  • Estructuras de datos
  • define N 1000 //1k
  • define M 1000 //1k
  • typedef double matrixNN //Array of M matrix
    of NxN
  • matrix amatM
  • Transformación
  • (amati)jk(amati)jksin((float)k)ra
    nd()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.

93
Variables Trabajo a realizar por cada hijo
include ltstdio.hgt include ltmpi.hgt include
ltstdlib.hgt include ltmalloc.hgt include
ltmath.hgt define N 10 //1M define M 10
//1K typedef double matrixNN //Array d M
matrices d NxN matrix amatM int CPU0 void
do_work(int roll, matrix slice_mat)
int i,j,k,m,n double max0
printf("rolld\n",roll) fflush(stdout)
for (i0 i lt (M/CPU)i) for (j0
jltNj) for (k0kltNk)
(slice_mati)jk(slice_mati)jk
sin((float)k) rand() atan(rand())
for (m0 mltN m) for (n0 nltN
n) if ((slice_mati)mn gt
max ) max(slice_mati)mn
printf("Max f\n",max) fflush(stdout)
94
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)
  • CPUnprocs
  • matrix slice_matM/CPU
  • printf("Rankd nprocs d\n",myrank,nprocs)
  • fflush(stdout)
  • for (i0iltMi)
  • if (myrank 0)
  • // master
  • amati (matrix )malloc( N N
    sizeof(double) )
  • auxamati
  • prand()
  • for (j0jltNNj) auxjp
  • MPI_Send((amati), NN,
    MPI_DOUBLE,inprocs,i ,MPI_COMM_WORLD)

if (myrank(inprocs)) printf(
"Receiving matrix d of d. My rankd\n",
i,M,myrank) slice_mati/nprocs
(double )malloc( N N sizeof(double) )
MPI_Recv((slice_mati/nprocs),NN,MPI_DOUBLE
,0,i, MPI_COMM_WORLD,status)
for (i0iltM/CPUi)
do_work(i,slice_mat) //TODO Send back results
to master MPI_Finalize() return 0
Ejercicio Enviar los datos de vuelta al maestro.
95
MPI_Allgather
96
MPI_Reduce
97
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.
Write a Comment
User Comments (0)
About PowerShow.com