Perché il mio ridimensionamento della moltiplicazione Matrix-Vector?


15

Ci scusiamo per il lungo post, ma volevo includere tutto ciò che pensavo fosse rilevante al primo tentativo.

Quello che voglio

Sto implementando una versione parallela dei metodi di sottospazio di Krylov per le matrici dense. Principalmente GMRES, QMR e CG. Mi sono reso conto (dopo la profilazione) che la mia routine DGEMV era patetica. Così ho deciso di concentrarmi su questo isolandolo. Ho provato a eseguirlo su una macchina a 12 core ma i risultati seguenti sono per un laptop Intel i3 a 4 core. Non c'è molta differenza nella tendenza.

La mia KMP_AFFINITY=VERBOSEuscita è disponibile qui .

Ho scritto un piccolo codice:

size_N = 15000
A = randomly_generated_dense_matrix(size_N,size_N); %Condition Number is not bad
b = randomly_generated_dense_vector(size_N);
for it=1:n_times %n_times I kept at 50 
 x = Matrix_Vector_Multi(A,b);
end

Credo che questo simuli il comportamento di CG per 50 iterazioni.

Cosa ho provato:

Traduzione

Inizialmente avevo scritto il codice in Fortran. L'ho tradotto in C, MATLAB e Python (Numpy). Inutile dire che MATLAB e Python erano orribili. Sorprendentemente, C era meglio di FORTRAN di un secondo o due per i valori di cui sopra. Costantemente.

profiling

Ho profilato il mio codice per l'esecuzione e ha funzionato per 46.075secondi. Questo era quando MKL_DYNAMIC era impostato suFALSE e venivano usati tutti i core. Se avessi usato MKL_DYNAMIC come vero, solo la metà (circa) del numero di core sarebbe stata in uso in un dato momento. Ecco alcuni dettagli:

Address Line    Assembly                CPU Time

0x5cb51c        mulpd %xmm9, %xmm14     36.591s

Il processo che richiede più tempo sembra essere:

Call Stack                          LAX16_N4_Loop_M16gas_1
CPU Time by Utilization             157.926s
CPU Time:Total by Utilization       94.1%
Overhead Time                       0us
Overhead Time:Total                 0.0%    
Module                              libmkl_mc3.so   

Ecco alcune foto:inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

conclusioni:

Sono un vero principiante nella profilazione ma mi rendo conto che l'accelerazione non è ancora buona. Il codice sequenziale (1 core) termina in 53 secondi. Questa è una velocità inferiore a 1,1!

Domanda reale: cosa devo fare per migliorare la mia velocità?

Roba che penso possa aiutare ma non posso essere sicuro:

  • Implementazione di Pthreads
  • Implementazione MPI (ScaLapack)
  • Sintonizzazione manuale (Non so come. Si prega di raccomandare una risorsa se si suggerisce questo)

Se qualcuno ha bisogno di maggiori dettagli (soprattutto per quanto riguarda la memoria), per favore fatemi sapere cosa dovrei eseguire e come. Non ho mai profilato memoria prima.

Risposte:


20

La tua matrice ha dimensioni 15.000 x 15.000, quindi hai 225 milioni di elementi nella matrice. Ciò comporta circa 2 GB di memoria. Questo è molto più della dimensione della cache del tuo processore, quindi deve essere caricato completamente dalla memoria principale in ogni moltiplicazione di matrice, rendendo necessari circa 100 GB di trasferimenti di dati, oltre a ciò di cui hai bisogno per i vettori di origine e destinazione.

La larghezza di banda di memoria massima di i3 è di circa 21 GB / s in base alle specifiche Intel, ma se ti guardi intorno al Web, scoprirai che al massimo metà di ciò è realmente disponibile nella realtà. Quindi, per lo meno, ti aspetteresti che il tuo benchmark duri 10 secondi e la tua misurazione effettiva di 45 secondi non è così lontana da quel segno.

Allo stesso tempo, stai anche facendo moltiplicare e aggiungere circa 10 miliardi in virgola mobile. Considerando, diciamo, 10 cicli di clock per la combinazione e frequenza di clock di 3 GHz, uscirai a ~ 30 secondi. Naturalmente, possono essere eseguiti contemporaneamente con carichi di memoria speculativi se la cache è intelligente.

Tutto sommato, direi che non sei troppo lontano dal segno. Cosa ti saresti aspettato?


Non c'è un modo per ottenere almeno uno speedup di 2-3?
Inquiry

@Nunoxic - Potresti voler confrontare le prestazioni della memoria del tuo sistema usando uno strumento come SiSoftware Sandra. L'analisi di Wolfgang mi sembra perfetta, se la tua applicazione è legata alla larghezza di banda della memoria, la parallelizzazione aiuterà poco o per niente. Inoltre, guarda tutte le opzioni di risparmio energetico che potresti avere, potrebbero rallentare le prestazioni della memoria. Inoltre, considera la possibilità di sostituire la tua memoria con una memoria di qualità superiore, ad esempio una latenza CAS inferiore potrebbe fare una grande differenza per il tempo della parete.
Mark Booth,

4

Come stai moltiplicando il vettore matrice? Un doppio anello a mano? O chiamate a BLAS? Se stai usando MKL, ti consiglio vivamente di usare le routine BLAS della versione filettata.

Per curiosità, potresti anche voler compilare la tua versione sintonizzata di ATLAS e vedere come funziona sul tuo problema.

Aggiornare

Seguendo la discussione nei commenti qui sotto, si scopre che il tuo Intel Core i3-330M ha solo due core "reali". I due core mancanti sono emulati con hyperthreading . Poiché nei core hyperthreaded sono condivisi sia il bus di memoria che le unità a virgola mobile, non si otterrà alcun aumento di velocità se uno dei due è un fattore limitante. In effetti, l'uso di quattro core probabilmente rallenterà anche le cose.

Che tipo di risultati ottieni "solo" due core?


Ho provato ATLA, GoTo e Netlib BLAS. Tutti sono più deboli di MKL in termini di prestazioni. È previsto o sto facendo qualcosa di sbagliato? Ho compilato ATLAS come indicato nel manuale. Inoltre, ho incollato il mio codice (esatto) qui . Si chiama BLAS di MKL.
Inquiry

Ok, e per il ridimensionamento, sei sicuro che nel tuo caso di base, il codice sia in esecuzione solo su una singola CPU? Ad esempio, se lo confronti, l'istogramma di utilizzo della CPU mostra solo un singolo core?
Pedro

Sì. L'istogramma della CPU mostra 1 core.
Inquiry

Solo per curiosità, cosa ottieni per due o tre core? La tua macchina ha effettivamente quattro core fisici o solo due core con hyperthreading ?
Pedro,

Come lo scopro? Ho incluso il mio KMP_AFFINITY nel principale.
Inquiry

0

Ho l'impressione che l'ordinamento delle righe principali sia ottimale per questo problema rispetto ai tempi di accesso alla memoria, all'utilizzo delle linee della cache e ai mancati TLB. Immagino che la tua versione FORTRAN abbia usato invece l'ordinamento delle colonne principali, il che potrebbe spiegare perché è costantemente più lento della versione C.

B non è tenuto nella cache. È possibile verificare se si osserva la stessa (effettiva) larghezza di banda di memoria per size_N = 15000 rispetto a size_N = 5000. In tal caso, è molto probabile che il codice sia già ottimale e che la larghezza di banda di memoria del proprio sistema sia semplicemente non eccezionale.

Potresti anche testare la velocità se sommi semplicemente tutti gli elementi della matrice in un singolo ciclo invece della moltiplicazione della matrice vettoriale. (Potresti voler srotolare il loop di un fattore 4, perché la non associatività dell'addizione potrebbe impedire al compilatore di fare questa ottimizzazione per te.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.