Post on 19-Jun-2015
description
transcript
Parallel sparse Matrix-Vectorand Matrix-Transpose-Vector
multiplication using compressed sparse blocks
Presentazione a cura di:
Marco Cherubini, Andrea De Pirro, David Santucci,Andrea Tersigni, Luca Tracuzzi
A. Buluc, J. T. Fineman, M. Frigo, J. R. Gilbert, C. E. Leiserson
Calcolo Parallelo e DistribuitoAnno Accademico 2009/2010
21 maggio 2010
Sommario
• Formati di memorizzazione convenzionali
• Il nuovo formato CSB
• Moltiplicazione Matrice-Vettore con CSB
• Analisi della complessità
• Sperimentazione
Formati convenzionali: CSR
• Analizziamo alcuni formati di memorizzazione convenzionali
• Consideriamo matrici sparse n×n con nnz elementi non nulli
• CSR - Compressed Sparse Rowso Memorizzazione per righeo Efficiente: memorizza n+nnz indici o puntatori
per matrici sparse n×n con nnz elementi non nullio Adatto per y Axo Non adatto per y ATx
Formati convenzionali: CSR
Ax parallelo con CSR
CSR_SPMV (A, x, y)
1 nA.rows2 for i0 to n−1 in parallel3 do y[i]04 for kA.row_ptr[i] to A.row_ptr[i+1]−15 do y[i]y[i]+A.val[k]·x[A.col_ind[k]]
• val[nnz] : array dei valori non nulli della matrice (ordinati per righe)• col_ind[nnz] : indici di colonna degli elementi nell'array val• row_ptr[n] : puntatori al'inizio della riga n nell'array val
• Nota: ATx con CSC è analogo
Formati convenzionali: CSC
• CSC - Compressed Sparse Columnso Memorizzazione per colonneo Efficiente: memorizza n + nnz indici o puntatori o Adatto per y ATx
risoluzione di problemi di programmazione lineareo Non adatto per y Ax
Formati convenzionali: CSC
Il nuovo formato CSB
• Consideriamo matrici sparse n×n con nnz elementi non nulli
• β = block-size parameter o valore ideale = circa √no per semplicità si assume β potenza di 2
• CSB - Compressed Sparse Blockso Partizionamento della matrice in blocchi quadrati di
dimensione β × βo Numero di blocchi n2 / β 2
o Ordinamento Z-Morton interno ai blocchi o Sostiene y Ax e y ATx
Il nuovo formato CSB
Il nuovo formato CSB
Il nuovo formato CSB
Il nuovo formato CSB
Il nuovo formato CSB
Prod. Matrice-Vettore con CSB
CSB_SPMV (A, x, y)
1 for i0 to n/β−1 in parallel // riga di blocco2 do Initialize a dynamic array Ri
3 Ri[0]0 // Array di indici per // gli ultimi blocchi dei chunk
4 count0 // Contatore nnz in un chunk5 for j0 to n/β−2
6 do countcount+nnz(Ai,j)
7 if count+nnz(Ai,j+1) > O(β)8 then // Fine chunk
9 append j to Ri // Ultimo blocco del chunk10 count0
11 append n/β−1 to Ri
12 CSB_BLOCKROWV (A, i, Ri, x, y[(i∙β),…,((i+1)∙β)−1])
Prod. Matrice-Vettore con CSB
Divisione in chunk
-1
Prod. Matrice-Vettore con CSB
Divisione in chunk
-1
Prod. Matrice-Vettore con CSB
Divisione in chunk
-1
Prod. Matrice-Vettore con CSB
Divisione in chunk
-1
CSB_BLOCKROWV (A, i, R, x, y)
11 if R.length = 2 // Singolo chunk12 then ℓR[0]+1 // Blocco più a sinistra nel chunk13 rR[1] // Blocco più a destra nel chunk14 if ℓ = r15 then // Il chunk contiene un singolo blocco denso16 startA.blk_ptr[ f(i,ℓ)]17 endA.blk_ptr[ f(i,ℓ)+1]−118 CSB_BLOCKV (A, start, end, β, x, y)19 else // Il chunk è sparso20 multiply y(Ai,ℓ Ai,ℓ+1 … Ai,r)x serially
21 return
// Se la riga di blocchi contiene più chunk22 mid R.length/2 −1 ⌈ ⌉ // Divide i chunk in due sottoinsiemi // Calcola il punto di split per il vettore x23 xmid β·(R[mid]−R[0])24 Alloca un vettore z di cardinalità β, inizializzati a 025 in parallel26 do CSB_BLOCKROWV(A, i, R[0…mid], x[0…xmid−1], y)27 do CSB_BLOCKROWV(A, i, R[mid…R.length−1],
x[xmid…x.length−1], z)28 for k0 to β−129 do y[k]y[k]+z[k]
CSB_BLOCKROWV (A, i, R, x, y)
11 if R.length = 2 // Singolo chunk12 then ℓR[0]+1 // Blocco più a sinistra nel chunk13 rR[1] // Blocco più a destra nel chunk14 if ℓ = r15 then // Il chunk contiene un singolo blocco denso16 startA.blk_ptr[ f(i,ℓ)]17 endA.blk_ptr[ f(i,ℓ)+1]−118 CSB_BLOCKV (A, start, end, β, x, y)19 else // Il chunk è sparso20 multiply y(Ai,ℓAi,ℓ+1…Ai,r)x serially21 return
// Se la riga di blocchi contiene più chunk22 mid R.length/2 −1 ⌈ ⌉ // Divide i chunk in due sottoinsiemi // Calcola il punto di split per il vettore x23 xmid β·(R[mid]−R[0])24 Alloca un vettore z di cardinalità β, inizializzati a 025 in parallel26 do CSB_BLOCKROWV(A, i, R[0…mid], x[0…xmid−1], y)27 do CSB_BLOCKROWV(A, i, R[mid…R.length−1],
x[xmid…x.length−1], z)28 for k0 to β−129 do y[k]y[k]+z[k]
Prod. Matrice-Vettore con CSB
Split ricorsivo dei chunk
y[β..2β-1]
Prod. Matrice-Vettore con CSB
Split ricorsivo dei chunk
y[β..2β-1]
CSB_BLOCKV (A, start, end, dim, x, y)
28 if end−start ≤ O(dim)29 then // Calcola la computazione seriale y←y+Mx30 for kstart to end // A.val[start…end] è un blocco dim×dim31 do y[A.row_ind[k]] y[A.row_ind[k]] + A.val[k]·x[A.col_ind[k]]32 return
33 // Ricorsione: divide il blocco M in 4 quadranti 34 binary search start, start+1,…,end per il più piccolo s2
tale che (A.row_ind[s2] & dim/2) ≠ 0
35 binary search start, start+1,…,s2−1 per il più piccolo s1
tale che (A.col_ind[s1] & dim/2) ≠ 0
36 binary search s2, s2+1,…,end per il più piccolo s3
tale che (A.col_ind[s3] & dim/2) ≠ 0
37 in parallel38 do CSB_BLOCKV (A, start, s1−1, dim/2, x, y) // M00
39 do CSB_BLOCKV (A, s3, end, dim/2, x, y) // M11
40 in parallel41 do CSB_BLOCKV (A, s1, s2−1, dim/2, x, y) // M01
42 do CSB_BLOCKV (A, s2, s3−1, dim/2, x, y) // M10
Prod. Matrice-Vettore con CSB
Decomposizione Z-Morton in 4 quadranti
Prod. Matrice-Vettore con CSB
Decomposizione Z-Morton in 4 quadranti
Prod. Matrice-Vettore con CSB
Decomposizione Z-Morton in 4 quadranti
Prod. Matrice-Vettore con CSB
Decomposizione Z-Morton in 4 quadranti
Analisi di complessità
• Al fine di valutare la complessità dell'algoritmo definiamo:o work: denotato con T1, rappresenta il tempo di
esecuzione in una macchina monoprocessore monothread
o span: denotato con T∞, rappresenta il tempo di esecuzione con un infinito numero di processi o thread
• Viene definito grado di parallelismo il rapporto T1/T∞
Lemma 1
• Lemma 1: il formato CSR usa n∙log(nnz) + nnz∙log(n) bit di indici di supporto per una matrice n×n con nnz elementi non nulli.
• Dimostrazione: per indicizzare x elementi sono necessari log(x) bit. Dal prodotto righe-colonne risultano n∙log(nnz) bit per il row_ptr e nnz∙log(n) bit per col_ind.
Lemma 1 (continua)
Lemma 2
• Lemma 2: Il formato CSB usa (n2/β2)∙log(nnz)+2∙nnz∙log(β) bit di indici di supporto per una matrice n×n con nnz elementi non nulli.
• Dimostrazione: per ogni elemento in val, usiamo log(β) bit per rappresentare l'indice di riga e log(β) bit per rappresentare l'indice di colonna e richiede quindi nnz∙log(β) bit per ciascuno degli indici. Aggiungiamo lo spazio dato dall'array blk_ptr, ossia (n2/β2) ∙ log(nnz) bit.
Lemma 2 (continua)
Lemma 2 (continua)
Corollario 3
• Corollario 3: il formato CSB usa (n)∙log(nnz)+nnz∙log(n) bit di indici di supporto per una matrice n×n con nnz elementi non nulli, con β=√n.
Lemma 4• Lemma 4: Su un blocco di dimensioni β×β, contenente r
elementi non nulli, CSB_BlockV viene eseguito con work O(r) e span O(β).
• Dimostrazione (span):o lo span relativo alla moltiplicazione di una matrice
dim×dim può essere descritto da S(dim)=2∙S(dim/2)+O(log(dim))=O(dim). 2∙S(dim/2): viene invocata 2 volte in parallelo la
ricorsione su un singolo blocco di dim/2 O(log(dim)): costo della ricerca binaria dei tre indici
di split caso base = O(dim): il caso base è seriale su
O(dim) elementi ed è dominante sui casi ricorsivi
Lemma 4 (continua)
• Dimostrazione (work):o Consideriamo l'albero di grado 4 generato dalle
chiamate ricorsive della funzione CSB_BlockV; ogni nodo corrisponde alla computazione di un sottoblocco dim×dim, con dim=2h, e 0<h<log(β). Se un nodo è una foglia, allora verifica il caso base
ed ha sicuramente al più O(2h)=O(dim) elementi non nulli. Ne deriva quindi che il costo di computazione del nodo è O(r).
[..]
CSB_BLOCKV (A, start, end, dim, x, y)
28 if end−start ≤ O(dim)29 then // Calcola la computazione seriale y←y+Mx30 for kstart to end // A.val[start…end] è un blocco dim×dim31 do y[A.row_ind[k]] y[A.row_ind[k]] + A.val[k]·x[A.col_ind[k]]32 return
33 // Ricorsione: divide il blocco M in 4 quadranti 34 binary search start, start+1,…,end per il più piccolo s2
tale che (A.row_ind[s2] & dim/2) ≠ 0
35 binary search start, start+1,…,s2−1 per il più piccolo s1
tale che (A.col_ind[s1] & dim/2) ≠ 0
36 binary search s2, s2+1,…,end per il più piccolo s3
tale che (A.col_ind[s3] & dim/2) ≠ 0
37 in parallel38 do CSB_BLOCKV (A, start, s1−1, dim/2, x, y) // M00
39 do CSB_BLOCKV (A, s3, end, dim/2, x, y) // M11
40 in parallel41 do CSB_BLOCKV (A, s1, s2−1, dim/2, x, y) // M01
42 do CSB_BLOCKV (A, s2, s3−1, dim/2, x, y) // M10
Lemma 4 (continua)
Lemma 4 (continua)
Lemma 4 (continua)
Lemma 4 (continua) [...] Se un nodo è interno, allora ha almeno O(dim) elementi
non nulli. Il costo computazionale del nodo, senza considerare
nodi figli, è pari a O(log(dim))=O(log(2h))=O(h), dovuto alla ricerca binaria.
I nodi generici di livello h sono al più O(r/dim), e quindi concorrono ad un lavoro complessivo per ogni livello pari a O(h∙r/dim).
sommando, per ogni h, nodi interni su tali livelli e nodi foglia, otteniamo O(r):
Lemma 5
• Questo lemma analizza la moltiplicazione fra una riga di blocchi e un vettore
• Lemma 5: Su una riga di blocchi contenente n/β blocchi e r elementi non nulli, CSB_BlockrowV viene eseguito con work O(r) e span O(β∙log(n/β)).
Lemma 5 (continua)
• Dimostrazione (work):o consideriamo la chiamata su una riga di blocco
partizionata in C chunk e definiamo W(C) il lavoro (work) eseguito. La funzione inizializza un vettore z di O(β) elementi e richiama ricorsivamente se stessa due volte, sulla metà dell'input
o Il lavoro è descritto dalla disequazioneW(C) ≤ 2∙W( C/2 )+O(β)⌈ ⌉da cui deriva W(C)=O(C∙β+r), poiché si hanno C attivazioni di complessità O(β), più i casi base di complessità O(r), ossia la computazione seriale del prodotto. Il numero C di chunk è, al più, pari a O(r/β) nel caso in cui r=O(β)
Lemma 5 (continua)
• Dimostrazione (span):o Lo span può essere descritto da S(C)=S( C/2 )⌈ ⌉
+O(β)=O(β∙log(C))+S(1)o Abbiamo che il caso base ha uno span pari O(β) sia nel
caso della moltiplicazione seriale che in quella nella chiamata CSB_BlockV
o Il caso base viene eseguito log(C) volte, con C ≤ n/βo Lo span complessivo è quindi O(β∙log(n/β))
Teorema 6
• Teorema 6: In una matrice n×n contenente r elementi non nulli, CSB_SpMV viene eseguito con un work O(r+n2/β2) e uno span di O(β∙lg(n/β)+n/β).
• Dimostrazione:o CSB_SpMV ricostruisce i chunk e avvia la funzione
CSB_BlockrowV. Il costo computazionale, per work e span deriva dal lemma precedente con l'aggiunta del costo necessario alla costruzione dei chunk.
o [...]
Teorema 6 (continua)
• Dimostrazione:o [...]o nel caso del work si aggiunge un costo pari a O(n2/β2)
dovuto all'analisi di una singola riga di blocchi di costo O(n/β) per un costo totale di O(r+n2/β2)
o nel caso dello span si aggiunge un costo pari a O(n/β) dato che è possibile parallelizzare l'operazione per ogni singola riga di blocchi, ottenendo un costo totale di O(β∙lg(n/β)+n/β)
Corollario 7 e 8
• Corollario 7: in una matrice n×n, contenente nnz ≥ n valori non nulli, scegliendo β=O(√n), CSB_SpMV lavora con un work di O(nnz) e uno span di O((√n)∙log(n)) raggiungendo un parallelismo di almeno
• O( nnz / (√n∙log(n)) )
• Corollario 8: in una matrice n×n, contenente nnz ≥ n valori non nulli, scegliendo β=O(√n), CSB_SpMV_T lavora con un work di O(nnz) e uno span di O(√n∙log(n)) raggiungendo un parallelismo di almeno
• O( nnz / (√n∙log(n)) )
Lemma 9• Lemma 9: In una matrice n×n, scegliendo β = O(√n), la
serializzazione di CSB_SpMV richiede uno spazio di O(√n∙log(n)) non contando lo spazio occupato dalla matrice stessa
• Dimostrazione: o lo spazio complessivo utilizzato è dato da due overhead
il primo, R, è l'array dei chunk, che, per ogni riga, utilizza uno spazio O(n/β). Dato che β=√n, si ha che lo spazio complessivo utilizzato è O(√n).
il secondo, z, è il vettore temporaneo di dimensione pari a β. A causa della profondità della ricorsione, lo spazio utilizzato è O(β∙log(n))=O(√n∙log(n))
la complessità finale è quindi O(√n∙log(n))+O(√n)=O(√n∙log(n))
Corollario 10
• Corollario 10: supponiamo un'esecuzione di CSB_SpMV per una matrice n×n con la scelta β=√n in un
work-stealing scheduler (preemptive round robin) con la proprietà busy-leaves. Allora l'esecuzione richiede uno spazio di O(P∙√n∙log(n)), con P pari al numero di processi utilizzati
Sperimentazione
• Scelta valore di β• Performance media di Ax e ATx• Risultati reali sulla scalabilità degli algoritmi
o matrici di medie dimensionio matrici di grandi dimensioni
Scelta del valore di β
• Si dimostra sperimentalmente che il valore ottimale di β deve rispettare la disequazione ⌈log(√n)⌉ ≤ log(β) ≤ 3+⌈log(√n)⌉
• L'utilizzo di β=√n per semplicità di calcolo rispetta tale vincolo
Performance media di Ax e ATx
• Sia CSB_SpMV che CSB_SpMV_T offrono ottime prestazioni all'aumentare del numero di processorio fino a 4 processori lo speedup cresce linearmenteo da 4 a 8 è meno che lineare, ma comunque crescenteo con più di 8, le prestazioni decadono a causa dei limiti
della memoria di sistema
Risultati sperimentali (dim media)
• I risultati sono stati condotti con matrici relative a problemi reali (e.g. elettroforesi DNA, meccanica strutturale,...)
Risultati sperimentali (dim grande)
• Per matrici grandi CSB scala in modo ottimale
CSR vs CSB
• Analizziamo il rapporto tra le performance di CSR e CSB nel caso di esecuzione parallela
• Per il confronto è stato usato l’algoritmo Star-P che usa CSR
Grazie per l'attenzione