Un buon punto di partenza è il grande libro The Science of Programming Matrix Computations di Robert A. van de Geijn e Enrique S. Quintana-Ortí. Forniscono una versione scaricabile gratuitamente.
BLAS è suddiviso in tre livelli:
Il livello 1 definisce un insieme di funzioni di algebra lineare che operano solo sui vettori. Queste funzioni traggono vantaggio dalla vettorizzazione (ad esempio dall'uso di SSE).
Le funzioni di livello 2 sono operazioni matrice-vettore, ad esempio alcuni prodotti matrice-vettore. Queste funzioni potrebbero essere implementate in termini di funzioni di Livello1. Tuttavia, è possibile aumentare le prestazioni di queste funzioni se è possibile fornire un'implementazione dedicata che fa uso di un'architettura multiprocessore con memoria condivisa.
Le funzioni di livello 3 sono operazioni come il prodotto matrice-matrice. Ancora una volta potresti implementarli in termini di funzioni Level2. Ma le funzioni di livello3 eseguono operazioni O (N ^ 3) sui dati O (N ^ 2). Quindi, se la tua piattaforma ha una gerarchia della cache, puoi migliorare le prestazioni se fornisci un'implementazione dedicata ottimizzata per la cache / adatta alla cache . Questo è ben descritto nel libro. Il vantaggio principale delle funzioni di Level3 deriva dall'ottimizzazione della cache. Questo boost supera in modo significativo il secondo boost dal parallelismo e da altre ottimizzazioni hardware.
A proposito, la maggior parte (o anche tutte) delle implementazioni BLAS ad alte prestazioni NON sono implementate in Fortran. ATLAS è implementato in C. GotoBLAS / OpenBLAS è implementato in C e le sue parti critiche per le prestazioni in Assembler. Solo l'implementazione di riferimento di BLAS è implementata in Fortran. Tuttavia, tutte queste implementazioni BLAS forniscono un'interfaccia Fortran tale che possa essere collegata a LAPACK (LAPACK ottiene tutte le sue prestazioni da BLAS).
I compilatori ottimizzati giocano un ruolo minore in questo senso (e per GotoBLAS / OpenBLAS il compilatore non ha alcuna importanza).
L'implementazione IMHO no BLAS utilizza algoritmi come l'algoritmo Coppersmith – Winograd o l'algoritmo Strassen. Non sono esattamente sicuro del motivo, ma questa è la mia ipotesi:
- Forse non è possibile fornire un'implementazione ottimizzata per la cache di questi algoritmi (ovvero perderesti più di quanto vinceresti)
- Questi algoritmi non sono numericamente stabili. Poiché BLAS è il kernel computazionale di LAPACK, questo è un no-go.
Modifica / Aggiornamento:
Il documento nuovo e innovativo per questo argomento sono i documenti BLIS . Sono scritti eccezionalmente bene. Per la mia lezione "Nozioni di base sul software per il calcolo ad alte prestazioni" ho implementato il prodotto matrice-matrice seguendo il loro articolo. In realtà ho implementato diverse varianti del prodotto matrice-matrice. Le varianti più semplici sono interamente scritte in C normale e hanno meno di 450 righe di codice. Tutte le altre varianti si limitano a ottimizzare i loop
for (l=0; l<MR*NR; ++l) {
AB[l] = 0;
}
for (l=0; l<kc; ++l) {
for (j=0; j<NR; ++j) {
for (i=0; i<MR; ++i) {
AB[i+j*MR] += A[i]*B[j];
}
}
A += MR;
B += NR;
}
Le prestazioni complessive del prodotto matrice-matrice dipendono solo da questi loop. Circa il 99,9% del tempo viene trascorso qui. Nelle altre varianti ho utilizzato intrinseci e codice assembler per migliorare le prestazioni. Puoi vedere il tutorial che esamina tutte le varianti qui:
ulmBLAS: Tutorial su GEMM (prodotto Matrix-Matrix)
Insieme ai documenti BLIS diventa abbastanza facile capire come le biblioteche come Intel MKL possano ottenere tali prestazioni. E perché non importa se utilizzi l'archiviazione principale di righe o colonne!
I benchmark finali sono qui (abbiamo chiamato il nostro progetto ulmBLAS):
Benchmark per ulmBLAS, BLIS, MKL, openBLAS e Eigen
Un'altra modifica / aggiornamento:
Ho anche scritto un tutorial su come BLAS viene utilizzato per problemi di algebra lineare numerica come la risoluzione di un sistema di equazioni lineari:
Fattorizzazione LU ad alte prestazioni
(Questa fattorizzazione LU è ad esempio utilizzata da Matlab per risolvere un sistema di equazioni lineari.)
Spero di trovare il tempo per estendere il tutorial per descrivere e dimostrare come realizzare un'implementazione parallela altamente scalabile della fattorizzazione LU come in PLASMA .
Ok, ecco qui: Codifica di una fattorizzazione LU parallela ottimizzata per la cache
PS: ho anche fatto alcuni esperimenti per migliorare le prestazioni di uBLAS. In realtà è abbastanza semplice aumentare (sì, gioca con le parole :)) le prestazioni di uBLAS:
Esperimenti su uBLAS .
Ecco un progetto simile con BLAZE :
Esperimenti su BLAZE .