Claudio Gheller Gruppo Supercalcolo Settore Sistemi ad Alte Prestazioni [email protected] CINECA...
-
Upload
palmiro-basso -
Category
Documents
-
view
215 -
download
0
Transcript of Claudio Gheller Gruppo Supercalcolo Settore Sistemi ad Alte Prestazioni [email protected] CINECA...
Claudio GhellerGruppo Supercalcolo
Settore Sistemi ad Alte Prestazioni
CINECA 5–16 Luglio 20046–17 Settembre 2004
COMMUNICATOR e TOPOLOGIE
Topologie – MPI2 Remote Memory Access
Claudio Gheller
2
Communicators e Topologie
Communicator: insieme di processi che possono comunicare reciprocamente attraverso lo scambio di messaggi
Topologia: struttura imposta sui processi che fanno parte di un communicator al fine di indirizzare specifici pattern di comunicazione
Topologie – MPI2 Remote Memory Access
Claudio Gheller
3
Case study 1: moltiplicazione di matrici
A, B, C matrici NxN
C = A x B cij = aikbkj
Npes = 4
Pe0 Pe1
Pe3
A
Pe2
Pe0 Pe1
Pe3 Pe2
B
Topologie – MPI2 Remote Memory Access
Claudio Gheller
4
Case study 1: moltiplicazione di matrici
Algoritmo di Fox:
1. Per ogni colonna invio ciascun sottoblocco di A a tutti i processori della riga di appartenenza
2. Ciascun sottoblocco effettua la moltiplicazione3. Sommo i sottoblocchi per colonna
Pe0 Pe1
Pe3
A
Pe2
Pe0 Pe1
Pe3 Pe2
B
Queste operazioni richiedono delle send da un processore a tutti gli altri su una riga (fase 1) o su una colonna (fase 2).
Assomigliano molto a broadcast o a reduce “parziali”, ovvero su un sottoinsieme di processi.
som
ma
Topologie – MPI2 Remote Memory Access
Claudio Gheller
5
Communicator
Questo però è possibile ridefinendo il communicator, spezzandolo in una serie di communicator “più piccoli”
Ad esempio, per il passo 1, e’ comodo avere un communicator per ciascuna riga di sottoblocchi.
A quel punto ogni riga “vede” soltanto i processi che appartengono alla riga stessa e si possono utilizzare le operazioni collettive per effettuare la moltiplicazione parziale.
Analogo per la fase 3, con communicator definiti per colonne.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
6
Communicator: implementazione
MPI_group MPI_GROUP_WORLDMPI_group first_row_groupMPI_Comm first_row_commInteger row_sizeParameter(row_size=2)Integer process_ranks(row_size)
Do i = 1, row_size process_ranks(i) = i-1Enddo
Call MPI_COMM_GROUP(MPI_COMM_WORLD, MPI_GROUP_WORLD, ierr)
Call MPI_GROUP_INCL(MPI_GROUP_WORLD, row_size, process_ranks, first_row_group, ierr)
Call MPI_COMM_CREATE(MPI_COMM_WORLD, first_row_group, first_row_comm)
Definisco il gruppo di default associato all’intero communicator di partenza.
Definisco il nuovo gruppo a partire da quello preesistente
Definisco il nuovo communicator
OPERAZIONI LOCALI
OPERAZIONE COLLETTIVA
HANDLE
HANDLE
Topologie – MPI2 Remote Memory Access
Claudio Gheller
7
Case Study 2: parallelizzazione di un problema su griglia regolare.
E’ il caso di un problema descritto da una (o più) variabili rappresentate sui nodi di una griglia regolare. E’ uno dei casi più semplici, ma è estremamente comune. Ad esempio è tipico di molte applicazioni di fluidodinamica.
A(i , j)
A(i-1, j)A(i , j-1)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
8
Case Study 2.
Spesso i problemi numerici su griglia sono caratterizzati dalla località della soluzione. In altri termini il valore della grandezza nel punto (i, j) è influenzato solo dalle celle immediatamente circostanti.
Ricadono in questa categoria i problemi di fluidodinamica classica. Sono invece esempi opposti quelli forniti dal calcolo del campo gravitazionale o coulombiano e dalla fisica dei plasmi.
A(i , j)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
9
Case Study 2. Parallelizzazione del problema su griglia: distribuzione a piani paralleli
Si può dividere il dominio computazionale a “bande”.
Data la località della soluzione il processo N ha bisogno di conoscere SOLO la prima riga di dati dei processi N-1 e N+1
PE N+1
PE N
PE N-1
L’array contenente la variabile viene definito con 2 righe in più, contenenti le “Ghost Regions”. La comunicazione coinvolge esclusivamente le ghost regions e i bordi. Il resto del calcolo è completamente locale.
Ghost Region
Ghost Region
Topologie – MPI2 Remote Memory Access
Claudio Gheller
10
Case Study. Parallelizzazione del problema su griglia: distribuzione a griglia cartesiana
Si può dividere il dominio computazionale a “blocchi”.
Questo tipo di suddivisione del dominio computazionale è preferibile perché:
•E’ compatibile con la geometria del problema
•Permette una maggiore granularità
•Riduce la comunicazione
Però è più complessa da trattare !!!
Chi sono i vicini di ciascun processore ???
Cosa devo comunicare ai processori vicini ???
…
PE N+1
PE N+3
PE N+2
PE N
Topologie – MPI2 Remote Memory Access
Claudio Gheller
11
Introduzione
• La topologia di comunicazione identifica i pattern (principali) di comunicazione che avvengono in un codice parallelo
• Le “MPI virtual topologies” sono uno strumento utile per:– risparmiare tempo– evitare errori– strutturare il codice
• Di default, MPI assegna a ciascun processo in un gruppo un rank da 0 a n-1: topologia lineare.
• Con adeguate funzioni MPI supporta anche topologie cartesiane e in generale a grafo.
• Ridefinizione del communicator• Utili quando il/i pattern di comunicazione seguono una o più strutture
precise
Topologie – MPI2 Remote Memory Access
Claudio Gheller
12
Topologia cartesiana
• I processori sono sui vertici di una griglia N-dimensionale. Caratteristiche di questa topologia sono:– numero di dimensioni– numero di processori in ogni dimensione– periodicità o meno nelle varie dimensioni
Topologie – MPI2 Remote Memory Access
Claudio Gheller
13
MPI_CART_CREATE
MPI_CART_CREATE(comm_old, ndims, dims, periods, reorder, comm_cart)
[ IN comm_old] input communicator (handle)
[ IN ndims] number of dimensions of cartesian grid (integer)
[ IN dims] integer array of size ndims specifying the number of
processes in each dimension
[ IN periods] logical array of size ndims specifying whether the grid is
periodic ( true) or not ( false) in each dimension
[ IN reorder] ranking may be reordered ( true) or not ( false) (logical)
[ OUT comm_cart] communicator with new cartesian topology
(handle)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
14
Esempio
integer :: comm_cartinteger :: ierrinteger :: dims(3)logical :: periods(3)
dims(1) = NprocXdims(2) = NprocYdims(3) = NprocZperiods = .true.
call MPI_CART_CREATE (MPI_COMM_WORLD, 3, dims, periods, & .true. , comm_cart,ierr)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
15
reorder
0 1 2 3 4 5
reorder=false
0 1 2
3 4 5
processor grid 3x2
0 1 2 3 4 5
reorder=true
0 1 2
3 4 5
processor grid 3x2
Topologie – MPI2 Remote Memory Access
Claudio Gheller
16
Funzioni di supporto
MPI_CARTDIM_GET(COMM, NDIMS, IERROR)INTEGER COMM, NDIMS, IERROR
MPI_CART_GET(COMM, MAXDIMS, DIMS, PERIODS, COORDS, IERROR)INTEGER COMM, MAXDIMS, DIMS(*), COORDS(*), IERROR LOGICAL PERIODS(*)
Date le coordinate nella “process grid”, determina il rank
MPI_CART_RANK(COMM, COORDS, RANK, IERROR)INTEGER COMM, COORDS(*), RANK, IERROR
Dato il rank del processo, determina le coordinate:
MPI_CART_COORDS(COMM, RANK, MAXDIMS, COORDS, IERROR)INTEGER COMM, RANK, MAXDIMS, COORDS(*), IERROR
out
in
in
in
in
in
in
in
in
out
out
out
out
out
Topologie – MPI2 Remote Memory Access
Claudio Gheller
17
SHIFT
Determina chi sono i processi di destra e sinistra (sopra, sotto, avanti, dietro, …)
MPI_CART_SHIFT(comm, direction, disp, rank_source, rank_dest)
[ IN comm] communicator with cartesian structure (handle)
[ IN direction] coordinate dimension of shift (integer)
[ IN disp] displacement (integer)
[ OUT rank_source] rank of source process (integer)
[ OUT rank_dest] rank of destination process (integer)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
18
Esempio
rank da chiedere nuovamente se reorder=truecall MPI_COMM_RANK (comm_cart,me,ierr)
identifica i primi vicinicall MPI_CART_SHIFT(comm_cart,0,1,left,right,ierr)call MPI_CART_SHIFT(comm_cart,1,1,front,rear,ierr)call MPI_CART_SHIFT(comm_cart,2,1,down,up,ierr)
identifica le coordinate del processore nella processor gridcall MPI_CART_COORDS(comm_cart,me,3,coords,ierr) Xproc = coords(1)Yproc = coords(2)Zproc = coords(3)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
19
Esempio
leftright
up
down
front
rear
x (0)
y (1)
z (2)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
20
Comunicazioni circolari (“shift”)
right to left !call MPI_SENDRECV(snd_buffer, N, MPI_REAL, right, sndtag,& rcv_buffer, N, MPI_REAL, left , rcvtag, & comm_cart, istatus, ierr)
left to right !call MPI_SENDRECV (snd_buffer, N, MPI_REAL, left, sndtag,& rcv_buffer, N, MPI_REAL, right , rcvtag, & comm_cart, istatus, ierr)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
21
Periodicità
0 1 2 3periods(1)=.true.left0=3right3=0
0 1 2 3periods(1)=.false.left0=MPI_PROC_NULLright3=MPI_PROC_NULL
MPI gestisce i bordi implicitamente: le comunicazioni a/da MPI_PROC_NULL non danno errore, non vengono eseguite e non danno tempi di attesa.
Non è necessario infarcire i codici di “IF”!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
22
Esempio: Topologia 2D su matrice
0 (0,0)
ROW (cresce l’indice di colonna)
CO
LUM
N (
c res c
e l’indic
e d
i ri
ga)
L’indicizzamento è sempre:
PROC(row,column)
La coordinata “0” è la row, la “1” è la column.
La coordinata che incrementa più rapidamente è la riga, ovvero è l’indice di colonna.
La dimensione della griglia di processori è Nrow x Ncol
1 (0,1)
2 (1,0) 3 (1,1)
4 (2,0) 5 (2,1)
6 (3,0) 7 (3,1)
matrice 4x2
process grid
rowcolu
mn
Topologie – MPI2 Remote Memory Access
Claudio Gheller
23
Suggerimenti
• Mantenere per i processori un layout analogo a quello dei dati.
• Evitare (se possibile!) di affidarsi alla numerazione dei processori: usare il processore “0” per operazioni particolari, gli altri in maniera uniforme.
• usare MPI_CART_SHIFT() per stabilire quali sono i processori vicini.
• La numerazione diventa critica nel momento in cui dobbiamo estrarre la configurazione globale dall’unione delle partizione locali, esempio nell’I/O.
• MPI_TYPE_DARRAY usa lo stesso ordine (row-major) delle topologie cartesiane: usarla per l’I/O
Topologie – MPI2 Remote Memory Access
Claudio Gheller
24
Suddividere una “processor grid”
crea sotto-griglie di dimensionalità inferiore a quella originale (solo le dimensioni “true” vengono mantenute):
MPI_CART_SUB(comm, remain_dims, newcomm)
[ IN comm] communicator with cartesian structure (handle)
[ IN remain_dims] the ith entry of remain_dims specifies whether
the
ith dimension is kept in the subgrid ( true) or is dropped ( false)
(logical vector)
[ OUT newcomm] communicator containing the subgrid that
includes the calling process (handle)
Ciascuna sotto-griglia viene identificata da un comunicatore NEWCOMM differente.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
25
Esempio
comm=2x3x4
6 x
REMAIN_DIMS=(false,false,true)
REMAIN_DIMS=(true,true,false)4 x
newcomm=4
newcomm=2x3
Topologie – MPI2 Remote Memory Access
Claudio Gheller
26
Topologia Grafo
• Con uno o più grafi è possibile descrivere qualunque topologia (inclusa quella cartesiana)
• Un grafo è costituito da un insieme di nodi (nodes) e un insieme di segmenti (edges) che li collegano
Topologie – MPI2 Remote Memory Access
Claudio Gheller
27
Topologia a grafo
Pe0
Pe0 Pe
3
Pe1
Pe2
Process Neighbours
0 1,3
1 0
2 3
3 0,2
Topologie – MPI2 Remote Memory Access
Claudio Gheller
28
Topologia a grafo
MPI_GRAPH_CREATE(comm_old, nnodes, index, edges, reorder, comm_graph)
[ IN comm_old] input communicator (handle) [ IN nnodes] number of nodes in graph (integer) [ IN index] array of integers describing node degrees (see below) [ IN edges] array of integers describing graph edges (see below) [ IN reorder] ranking may be reordered ( true) or not ( false) (logical) [ OUT comm_graph] communicator with graph topology added (handle)
Nel nostro esempio:nnodes = 4
index = 2, 3, 4, 6edges = 1, 3, 0, 3, 0, 2
Claudio GhellerGruppo Supercalcolo
Settore Sistemi ad Alte Prestazioni
CINECA 5–16 Luglio 20046–17 Settembre 2004 MPI-2
Topologie – MPI2 Remote Memory Access
Claudio Gheller
30
MPI: message passing standard
Cos’è MPI 2 ???
MPI2: estensione di MPI
Vengono introdotte 3 nuove famiglie di funzionalità:
•Parallel I/O
•Remote Memory Operations
•Dynamic Process management
Inoltre, vengono introdotte alcune funzionalità per rendere MPI (1+2) più robusto e facilmente utilizzabile, come:
•Supporto per C++ e F90
•Supporto per i threads
•Programmazione mista
Ci focalizzeremo su:
•Parallel I/O
•Remote Memory Operations
Topologie – MPI2 Remote Memory Access
Claudio Gheller
31
MPI 2 al CINECA
La libreria MPI 2 attualmente è presente esclusivamente sul sitema IBM SP4
Per compilare:mpxlf90_r -o mycode mycode.fmpcc_r -o mycode mycode.cmpCC_r -o mycode mycode.cxx
Per eseguirepoe mycode -procs 2 -tasks_per_node 2
Oppure attraverso load leveler con comandi standard (già utilizzati per MPI)
Topologie – MPI2 Remote Memory Access
Claudio Gheller
32
Remote Memory Operations
Scambio di informazioni tra processi. Esistono 2 approcci principali:
Message Passing MPI 1
Accesso Diretto MPI 2
Message Passing:
Cooperativo.
Un processo invia ed uno riceve.
Solo quando la riceive è completa il dato è disponibile
Vantaggi
•Completo controllo della memoria (solo i buffer specificati possono essere modificati)
•Completo controllo del momento in cui la comunicazione può avvenire
Limiti
•“Facilità” di programmazione
•Performance
In linea di principio si può (quasi) sempre paral-lelizzare con il message passing. In pratica questo a volte è difficile e rende il codice macchinoso e complesso…
Topologie – MPI2 Remote Memory Access
Claudio Gheller
33
Case Study: contatore parallelo
A volte, per ragioni di bilanciamento del carico di lavoro, è utile distribuire i dati in modo dinamico.
Solo una frazione dei dati viene distribuita inizialmente tra i processori. Il processore che per primo finisce il proprio lavoro, carica un nuovo blocco di dati e prosegue.
Pe0N-3
Pe1N-2
Pe2N-1
Pe3N
Pe ?N+1
Il primo blocco di dati libero è identificato da un indice (N+1) determinato da un contatore GLOBALE, al quale devono accedere TUTTI i processori sia in lettura (per vedere qual è il blocco disponibile) che in scrittura (per aggiornare il blocco stesso)
Ma questa operazione e’ ASINCRONA e non è possibile (in modo semplice) con MPI
Claudio GhellerGruppo Supercalcolo
Settore Sistemi ad Alte Prestazioni
CINECA 5–16 Luglio 20046–17 Settembre 2004 MPI-2 RMA
Topologie – MPI2 Remote Memory Access
Claudio Gheller
35
Remote Memory Operations
MPI 2 introduce il modello di programmazione
Remote Memory Access (RMA)
che elimina i problemi del message passing, conservandone però molti dei vantaggi.
Lo scambio di dati è gestito da un unico processo, che specifica sia l’origine che la destinazione dei dati stessi (one-side communication)
Attenzione: MPI 2 NON è shared memory
L’approccio Shared Memory è più “naturale” (esiste un unico spazio degli indirizzi) MA richiede hardware specifico.
MPI 2 (e più in generale MPI) lavora su “qualsiasi” sistema parallelo più o meno accoppiato, a memoria distributia o condivisa !!!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
36
PE0 PE1
Riassumendo…
Message Passing
PE0 PE1 Shared Memory
PE0 PE1 Remote Memory Access
Memory
Topologie – MPI2 Remote Memory Access
Claudio Gheller
37
RMA: basics
L’approccio RMA prevede 3 step fondamentali:
1. Definire la memoria accessibile attraverso operazioni RMA. Questa è detta MEMORY WINDOW ed è creata attraverso il comando MPI_WIN_CREATE
2. Specificare quali dati devono essere comunicati e a chi. Si usano le routine MPI_PUT, MPI_GET, MPI_ACCUMULATE
3. Specificare quando il dato è accessibile, corrispondente alla finalizzazione di una receive. Definire la sincronizzazione dei processi.
Questo si può realizzare in più modi, in base a considerazioni di implementazione e performance.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
38
Comparing MPI and MPI 2: an example.
MPI 2
MPI
Topologie – MPI2 Remote Memory Access
Claudio Gheller
39
Memory Windows
La Memory Window è lo spazio di memoria complessivo reso disponibile ad operazioni RMA
Non tutta la memoria locale è accessibile via RMA. Solo la parte definita nella Memory Window.
Fisicamente è una sezione di memoria contigua descritta da un indirizzo base più una dimensione in bytes.
Creazione:
MPI_WIN_CREATE(base, size, disp_unit, info, comm, win, ierr)Distruzione:
MPI_WIN_FREE(win, ierr)
PE0 memory
Win
PE 1
IN base = indirizzo di partenza
IN Size = dimensione in bytes
IN Disp_unit = unità di conteggio dei dati (bytes, sizeof()). Essenziale per la portabilità
IN Info = legata alle performance (vedi in seguito). MPI_INFO_NULL sempre OK
IN Comm = communicator
OUT Win = nome della finestra
Topologie – MPI2 Remote Memory Access
Claudio Gheller
40
Altri approcci:
La Memory Window serve ad individuare univocamente dove sono i dati che si possono comunicare e a proteggere le zone di memoria che non entrano in gioco nella parallelizzazione.
Altre librerie seguono approcci simili.
Le LAPI, implementate da IBM allocano una parte di memoria espressamente per operazioni di RMA. Tale operazione è realizzata da una funzione analoga alla MPI_WIN_CREATE.
Le Shmem, implementate da SGI (e, originariamente da CRAY) usano la convenzione che le variabili accessibili via RMA devono essere allocate staticamente su ciascun processore e occupano gli stessi indirizzi di memoria.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
41
Comunicazione delle informazioni
Scrittura su memoria remota:
MPI_PUT (origin_ad, origin_count, origin_type, target_rank, target_disp, target_count, target_datatype, win, ierr)
origin_ad, origin_count, origin_type = caratterizzano i dati che devono essere comunicati. NON DEVONO NECESSARIAMENTE ESSERE NELLA MEMORY WINDOW.
target_rank = processore di destinazione
target_disp = è l’offset della locazione di memoria in cui scrive la put IN UNITA’ della DISP_UNIT definita per la Window
target_count = numero di elementi
target_datatype = tipo dei dati
win = nome della Memory Window
MPI_PUT può essere pensata come una coppia di send e receive non bloccanti. Quest’ultima caratteristica è fondamentale per le prestazioni…
Non esiste nessuna versione bloccante di funzioni RMA. Comunicazione e Sincronizzazione sono SEMPRE separate !!!
I TARGET DEVONO ESSERE NECESSARIAMENTE NELLA MEMORY WINDOW !!!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
42
Comunicazione delle informazioni
Lettura da memoria remota:
MPI_GET( origin_ad, origin_count, origin_type, target_rank, target_disp, target_count, target_datatype, win, ierr )
origin_ad, origin_count, origin_type = caratterizzano i buffer che devono essere caricati. NON DEVONO NECESSARIAMENTE ESSERE NELLA MEMORY WINDOW.
target_rank = processore di destinazione
target_disp = è l’offset della locazione di memoria in cui scrive la put IN UNITA’ della DISP_UNIT definita per la Window
target_count = numero di elementi
target_datatype = tipo dei dati
win = nome della Memory Window
I TARGET DEVONO ESSERE NECESSARIAMENTE NELLA MEMORY WINDOW !!!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
43
Process 0
Process 1
A(10)
B(20)
A(10)
B(20)
C(4)
Get
Put
MEMORY
MEMORY
MPI WIN
Topologie – MPI2 Remote Memory Access
Claudio Gheller
44
Comunicazione delle informazioni
Combinazione di comunicazione e calcolo:
MPI_ACCUMULATE( origin_ad, origin_count, origin_type, target_rank, target_disp, target_count, target_datatype, OP, win, ierr)
OP = operazione sui dati che vengono comunicati. Ad esempio
MPI_SUM, somma i termini d’origine sul target
MPI_REPLACE, sostituisce il valore di target con quello d’origine
MPI_ACCUMULATE corrisponde ad una Reduce di MPI, anche se non è altrettanto generale (ad es. non consente l’uso di operazioni definite dall’utente)
(…anche in questo caso) I TARGET DEVONO ESSERE NECESSARIAMENTE NELLA MEMORY WINDOW !!!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
45
Completamento della comunicazione
In MPI 1 l’impostazione della comunicazione può essere disaccoppiata dal suo completamento.
Questo permette di migliorare le performance.
Infatti, la finalizzazione porta via tempo !!!
In MPI 2 comunicazione e sincronizzazione sono disaccoppiate
MPI 2 permette di finalizzare con un’unica chiamata (quindi con un’unica operazione) tutte le comunicazioni impostate su una stessa window !!!
HIGH PERFOMANCE
La finalizzazione si può ottenere in vari modi:
MPI_WIN_FENCE
MPI_WIN_LOCK
MPI_WIN_POST
Topologie – MPI2 Remote Memory Access
Claudio Gheller
46
Completamento della comunicazione
La FENCE è la procedura più comune per finalizzare la comunicazione. Si può pensare come una specie di barriera.
Una FENCE finalizza tutti i processi RMA impostati da una precedente chiamata alla FENCE stessa.
La FENCE è collettiva e coinvolge tutti i processi della window (active target synchronization)
Fino alla chiamata di una FENCE non c’è nessuna garanzia che:
•Le operazioni di RMA siano concluse
•I dati locali siano disponibili alla Memory Window
MPI_WIN_FENCE(assert, win, ierr)
il parametro assert indica sempre una possibile ottimizzazione: 0 va bene sempre
Regola Generale
La FENCE separa zone di codice in cui avvengono accessi (in scrittura) alla memoria locale da zone in cui avvengono accessi (in scrittura) alla memoria remota.
In pratica:
PUT e ACCUMULATE non stanno mai nella stessa zona di load/store locali e GET
Topologie – MPI2 Remote Memory Access
Claudio Gheller
47
Completamento della comunicazione: Fence
All’interno di una sezione FENCE
NON modificare MAI con un’operazione di PUT per più di una volta una variabile
La stessa cosa non vale per l’ACCUMULATE.
Anzi, l’operazione e’ ottimizzata per accessi concorrenti !!!
Attenzione all’utilizzo di ACCUMULATE con operazioni non commutative (es. mischiare somme e prodotti) in modo concorrente dato che l’ordine di esecuzione non è garantito.
Ad esempio:
MPI_Accumulate(a, 2, … , MPI_REPLACE)
a(0) potrebbe avere il valore che proviene dal processo 0 e a(1) quello che viene dal processo 1 (o viceversa)!!
Topologie – MPI2 Remote Memory Access
Claudio Gheller
48
Riassumendo:
FENCE
PUT
ACCUMULATE
GET e load locali su variabili non soggette
a precedenti PUT e ACCUMULATE
FENCE
GET
Load/store locali
FENCE
WIN_CREATE
WIN_FREE
Topologie – MPI2 Remote Memory Access
Claudio Gheller
49
Completamento della comunicazione
La LOCK provvede una sincronizzazione di tipo Passive Target.
LOCK e UNLOCK definiscono la “access epoch” durante la quale la window remota può essere acceduta da uno specifico processo
Il target non sa nulla della comunicazione. Vera e propria one side communication
La LOCK non è collettiva .
MPI_WIN_LOCK(lock_type, rank, assert, win, ierr)
MPI_WIN_UNLOCK(rank, win, ierr)
Il parametro rank definisce il target della RMA
Il parametro lock_type può essere:
•MPI_LOCK_SHARED: più operazioni possono operare su una window
•MPI_LOCK_EXCLUSIVE: accesso atomico alla window
Il LOCK su una window locale impedisce l’accesso in RMA da altri processi (altrimenti non è possibile evitare l’accesso passivo !!!). Anche sulle variabili locali, si deve operare con lock, put e get.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
50
LOCK: esempio
La sincronizzazione passiva permette di definire, ad esempio, una PUT bloccante:
Subroutine MPE_Blocking_put ( target_rank, win, …parametri della PUT… )
Call MPI_WIN_LOCK ( MPI_LOCK_SHARED, target_rank, 0, win, ierr )
Call MPI_PUT (…)
Call MPI_WIN_UNLOCK ( target_rank, win, ierr)
return
La stessa cosa non avrebbe avuto senso con una FENCE dato che questa è un’operazione collettiva che non permette una sincronizzazione di singoli processi.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
51
Completamento della comunicazione
POST e START definiscono una sincronizzazione attiva, analoga alla FENCE ma limitata ai processi che effettivamente concorrono alla comunicazione.
In questo modo si ottiene una migliore scalabilità
MPI_WIN_POST(from_group, assert, win, ierr)
MPI_WIN_WAIT(win, ierr)
MPI_WIN_START(to_group, assert, win, ierr)
MPI_WIN_COMPLETE(win, ierr)
POST apre la local window ai processi che fanno parte del gruppo from_group, per un periodo detto “exposure epoch”.
WAIT chiude la exposure ephoc.
START inizializza la comunicazione di un gruppo verso una window aperta dal POST
COMPLETE finalizza la comunicazione
Sono necessari
e entrambe
MPI_WIN_FENCE
Codice
MPI_WIN_FENCE
MPI_WIN_POST
MPI_WIN_START
Codice
MPI_WIN_ COMPLETE
MPI_WIN_WAIT
Topologie – MPI2 Remote Memory Access
Claudio Gheller
52
Case Study. Implementazione Fortran MPI 1 per piani paralleli
Subroutine exchang1(a, nx, s, e, comm1d, bottom_nbr, top_nbr)
use mpi
integer nx, s, e
double precision a(0:nx+1, s-1:e+1)
integer comm1d, bottom_nbr, top_nbr
integer status_array(MPI_STATUS_SIZE, 4), ierr, req(4)
call MPI_IRECV (a(1,s-1), nx, MPI_DOUBLE_PRECISION, bottom_nbr, 0, comm1d, req(1), ierr)
call MPI_ISEND (a(1,e), nx, MPI_DOUBLE_PRECISION, top_nbr, 0, comm1d, req(3), ierr
call MPI_IRECV (a(1,e+1), nx, MPI_DOUBLE_PRECISION, top_nbr, 1, comm1d, req(2), ierr)
call MPI_ISEND (a(1,s), nx, MPI_DOUBLE_PRECISION, bottom_nbr, 1, comm1d, req(4), ierr
call MPI_WAITALL (4, req, status_array, ierr)
return
end
Nota la necessità di utilizzare comunicazioni NON bloccanti per evitare deadlock
Topologie – MPI2 Remote Memory Access
Claudio Gheller
53
Case Study. Implementazione Fortran MPI 2
integer sizedouble, ierr, win
double precision a(0:nx+1, s-1:e+1)
call MPI_TYPE_SIZE (MPI_DOUBLE_PRECISION, sizedouble, ierr)
call MPI_WIN_CREATE (a, (nx+2)*(e-s+3)*sizedouble, sizedouble, MPI_INFO_NULL, MPI_COMM_WORLD, win, ierr)
…
Subroutine exchang1(a, nx, s, e, win, bottom_nbr, top_nbr)
use mpi
integer nx, s, e, ierr, win, bottom_nbr, top_nbr, bottom_ghost_disp, top_ghost_disp
double precision a(0:nx+1, s-1:e+1)
call MPI_FENCE (0, win,ierr)
top_ghost_disp=1+(nx+2)*(e-s+2)
bottom_ghost_disp=1
call MPI_PUT (a(1,s), nx, MPI_DOUBLE_PRECISION, bottom_nbr, top_ghost_disp, nx, MPI_DOUBLE_PRECISION &
win, ierr)
call MPI_PUT (a(1,e), nx, MPI_DOUBLE_PRECISION, top_nbr, bottom_ghost_disp, nx, MPI_DOUBLE_PRECISION &
win, ierr)
call MPI_FENCE (0, win,ierr)
return
end
Il displacement è in unità di sizedouble, con offset di 1 per evitare di comunicare i boundary laterali
Possiamo trascrivere il codice in MPI 2 ottenendo una versione esattamente equivalente alla precedente. Con MPI 2 però si deve inizializzare la memory window.
Nota la presenza del Fence anche prima che la comunicazione inizi
La dimensione della window è in BYTES
MPI_TYPE_SIZE è il corrispondente di sizeof per il Fortran
Nella stessa zona di Fence possono convivere due PUT in quanto modificano aree di memoria diverse
Topologie – MPI2 Remote Memory Access
Claudio Gheller
54
Case Study.
Osservazioni
•Le due versioni MPI 1 e MPI 2 del codice sono equivalenti nel funzionamento.
•Nella versione MPI 2 tuttavia non è necessaria la presenza di send e corrispondenti receive.
•Il processo origine può scrivere liberamente nella memoria esposta dalla window del processo target.
•La sincronizzazione si verifica solo alla chiamata del FENCE quando TUTTE le comunicazioni sono già state impostate
•Eventuali store locali sulle aree ghost avrebbero dovuto essere situate in una diversa zona FENCE !!!
Problema
nel calcolo del displacement assumiamo che i parametri e ed s siano gli stessi per TUTTI i processi. Ma questo potrebbe non essere vero !!! In tal caso è necessario comunicare preliminarmente il corretto displacement remoto !!!
OPPURE …
Topologie – MPI2 Remote Memory Access
Claudio Gheller
55
Case Study.
…OPPURE:
modifico la routine exchang1 come segue:
Subroutine exchang1(a, nx, s, e, win, bottom_nbr, top_nbr)
use mpi
integer nx, s, e, ierr, win, bottom_nbr, top_nbr, bottom_ghost_disp, top_ghost_disp
double precision a(0:nx+1, s-1:e+1)
top_nbr = nx + 2
bottom_nbr = 1
call MPI_FENCE (0, win,ierr)
call MPI_GET ( a(1,e+1), nx, MPI_DOUBLE_PRECISION, top_nbr, nx+1, nx, MPI_DOUBLE_PRECISION, win, ierr)
call MPI_PUT ( a(1,e), nx, MPI_DOUBLE_PRECISION, bottom_nbr, 1, nx, MPI_DOUBLE_PRECISION, win, ierr)
call MPI_FENCE (0, win,ierr)
return
end
Anche in questo caso, nella stessa zona di Fence possono convivere PUT e GET in quanto accedono ad aree di memoria diverse
Topologie – MPI2 Remote Memory Access
Claudio Gheller
56
Case Study.
Nota conclusiva:
nel precedente esempio l’unità di displacement è stata scelta pari alla dimensione di un double.
Tuttavia questa è solo una delle possibili scelte.
La si sarebbe potuta fissare pari alla lunghezza di una riga:
(nx+2) * sizedouble
in tal caso l’offset della put sarebbe semplicemente il numero della riga.
In tal caso però comunicheremmo più dati, dato che verrebbero comunicate anch e le celle di bordo delle regioni ghost.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
57
Case Study: contatore parallelo, soluzione 1
call MPI_WIN_LOCK( MPI_LOCK_EXCLUSIVE, 0, 0, win, ierr)
call MPI_GET(ix,1,MPI_INTEGER, 0,0,1,MPI_INTEGER,win,ierr)
call MPI_ACCUMULATE(1,1,MPI_INTEGER,0,0,1,MPI_INTEGER,MPI_SUM,win,ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
NON FUNZIONA!!!
1. Lo standard MPI proibisce esplicitamente l’accesso e l’update della stessa locazione di memoria nella medesima “access epoch”
2. MPI_GET è asincrona: abbiamo la certezza che “ix” è up-to-date solo al termine del periodo di sincronizzazione, sia in remoto che in locale: solo dopo l’unlock. Potrebbe quindi avvenire prima l’accumulate e poi il get !!!
Recupera il valore attuale del contatore
Aggiorna il contatore
Topologie – MPI2 Remote Memory Access
Claudio Gheller
58
Case Study: contatore parallelo, soluzione 2
call MPI_WIN_LOCK( MPI_LOCK_SHARED, 0, 0, win, ierr)
call MPI_GET(ix,1,MPI_INTEGER, 0,0,1,MPI_INTEGER,win,ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
call MPI_WIN_LOCK( MPI_LOCK_SHARED, 0, 0, win, ierr)
call MPI_ACCUMULATE(1,1,MPI_INTEGER,0,0,1,MPI_INTEGER,MPI_SUM,win,ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
NON FUNZIONA!!!
Così abbiamo reso sincrone sia la MPI_GET che la MPI_ACCUMULATE, quindi localmente non abbiamo più problemi, ma tra il primo unlock ed il secondo lock, un altro processo può inserirsi e leggere il valore non incrementato.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
59
Case Study: contatore parallelo, soluzione ideale
call MPI_WIN_LOCK( MPI_LOCK_EXCLUSIVE, 0, 0, win, ierr)
call MPI_WIN_LOCK( MPI_LOCK_SHARED, 0, 0, win, ierr)
call MPI_GET(ix,1,MPI_INTEGER, 0,0,1,MPI_INTEGER,win,ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
call MPI_WIN_LOCK( MPI_LOCK_SHARED, 0, 0, win, ierr)
call MPI_ACCUMULATE(1,1,MPI_INTEGER,0,0,1,MPI_INTEGER,MPI_SUM,win,ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
call MPI_WIN_UNLOCK(0, win, ierr)
nidificare i lock, esclusivo all’esterno per evitare che altri processi si “inseriscano” e shared all’interno per rendere sincrone le chiamate sarebbe l’ideale, ma
NON E’ POSSIBILE!!!
MPI non lo permette.
Topologie – MPI2 Remote Memory Access
Claudio Gheller
60
Case Study: contatore parallelo, soluzione pratica
Separo la locazione di memoria da incrementare da quella da ottenere con la get. In pratica:
1. Definisco sul pe 0 un array di dimensione pari al numero di processori.
L’array contiene l’incremento specifico per ogni processore.
2. Il processore M istanzia un lock exclusive sul pe 0
3. Il processore M preleva tutti gli elementi dell’array (get) tranne l’M-
esimo
4. Incremento di 1 dell’M-esimo elemento sul processore 0
5. Unlock della window
6. Aggiornamento del contatore locale sul processore M-esimo
7. Calcolo del valore del contatore sul processore M-esimo come somma
di tutti i termini dell’array più il contatore locale
Topologie – MPI2 Remote Memory Access
Claudio Gheller
61
Implementazione
Integer count_array(Npes)…CALL MPI_WIN_LOCK(MPI_LOCK_EXCLUSIVE, 0, 0, counter_win, ierr)Do i= 1, Npes if (i -1 = mype) then CALL MPI_ACCUMULATE(one, 1, MPI_INT, 0, i, 1, MPI_INT, counter_win,
ierr) else CALL MPI_GET(count_array(i), 1, MPI_INT, 0, i, 1, MPI_INT, counter_win,
ierr) endifEnddoCALL MPI_WIN_UNLOCK(0, counter_win)Myval = Myval + 1count_array(mype+1) = Myval
tot_count = 0Do i= 1, Npes tot_count=tot_count + count_array(i)enddo