Attualmente sto lavorando su una libreria sparse matrix/math/iterative solver C++, per uno strumento di simulazione che gestisco. Avrei preferito utilizzare un pacchetto esistente, tuttavia, dopo un'indagine approfondita, non è stato trovato nessuno adatto al nostro simulatore (abbiamo esaminato flens, it ++, PetSC, eigen e molti altri). La buona notizia sono i miei risolutori e le strutture a matrice sparsa sono ora molto efficienti e robuste. La cattiva notizia è che ora sto esaminando la parallelizzazione usando OpenMP e la curva di apprendimento è un po 'ripida.Più livelli di parallelismo usando OpenMP - Possibile? Inteligente? Pratico?
Il dominio che risolviamo può essere suddiviso in sottodomini, che si uniscono in un formato a blocchi diagonali. Quindi il nostro schema di archiviazione si presenta come una matrice di matrici quadrate più piccole (blocchi []) ciascuna con un formato appropriato per il sottodominio (ad es. Archiviazione righe compresse: CRS, Archiviazione diagonale compressa: CDS, Denso, ecc.), e una matrice di sfondo (attualmente in uso CRS) che tiene conto della connettività tra sottodomini.
Il "punto caldo" nella maggior parte dei (tutti?) Risolutori iterativi è l'operazione di moltiplicazione di Matrix Vector, e questo è vero per la mia libreria. Pertanto, ho concentrato i miei sforzi sull'ottimizzazione delle mie routine MxV. Per la struttura diagonale blocco, il codice pseudo di M * x = b sarebbero le seguenti:
b=background_matrix*x
start_index = 1;
end_index = 0;
for(i=1:number of blocks) {
end_index=start_index+blocks[i].numRows();
b.range(start_index, end_index) += blocks[i] * x.range(start_index, end_index);
start_index = end_index+1;
}
dove background_matrix è lo sfondo (CRS) matrice, blocchi è la matrice di matrici sub-dominio, e .Range restituisce la parte del vettore da un indice iniziale a un indice finale.
Ovviamente il ciclo può essere (ed è stato) parallelizzato, poiché le operazioni sono indipendenti da altre iterazioni del ciclo (gli intervalli non sono sovrapposti). Dato che abbiamo 10-15 blocchi in un tipico sistema, 4+ thread effettivamente fanno una differenza significativa.
L'altro posto in cui la parallelizzazione è stata considerata una buona opzione è l'operazione MxV per ogni schema di archiviazione sottodominio (chiamate nelle righe 1 e 6 nel codice precedente). C'è molto da fare sulla parallelizzazione delle operazioni MxV con Matrice CRS, CDS e densa. In genere, una bella spinta si vede con 2 thread, con ritorni molto più bassi con l'aggiunta di più thread.
Sto immaginando uno schema, in cui verranno utilizzati 4 thread nel loop block per il codice precedente e ognuno di questi thread utilizzerà 2 thread per i risolti del sottodominio. Tuttavia, non sono sicuro di come, usando OpenMP, si gestisca il pool di thread: è possibile limitare il numero di thread in un ciclo aperto per loop? Questo parallelismo a più livelli è qualcosa che nella pratica ha un senso? Eventuali altri pensieri su quello che ho proposto qui sarebbe apprezzato (e grazie per la lettura fino alla fine!)
Quale risolutore hai utilizzato? – Jacob
@ Jacob- il sistema che sto risolvendo ha diversi tipi di sottodomini che sono risolti in modo più efficiente utilizzando un GMRES con jacobi precondizionato su CRS, ICC precondizionato ICC risolvibile su un CDS o una soluzione densa diretta. Al fine di ottenere il massimo da ogni sottodominio, ho finito con una soluzione GMRES sul sistema globale, utilizzando un precondizionatore additivo Schwarz ad 1 fase non sovrapposto, in cui la soluzione locale nel preconditonatore è l'algoritmo del risolutore appropriato per il tipo di sottodominio. – MarkD
Hai considerato cosa farai quando vuoi risolvere sistemi un po 'più grandi, o vuoi quelle soluzioni più velocemente?OpenMP è ottimo per i singoli nodi di memoria condivisa, ma non appena lo superi (per motivi di dimensioni o semplicemente facendo il calcolo in un tempo più breve), finirai per volere qualcos'altro, che può ridimensionarsi. Suggerisco le cose che il mio laboratorio sviluppa (vedere il profilo), ma hai già menzionato OpenMP come una curva di apprendimento ripida. Il nostro software è ancora più ripido, sebbene abbia alcuni costrutti che possono rappresentare le cose in modo più naturale. – Novelocrat