L'analisi algoritmica mediante conteggio al flop è obsoleta?


43

Nei miei corsi di analisi numerica, ho imparato ad analizzare l'efficienza degli algoritmi contando il numero di operazioni in virgola mobile (flop) di cui hanno bisogno, in relazione alla dimensione del problema. Ad esempio, nel testo di Trefethen & Bau sull'algebra lineare numerica, ci sono persino immagini 3D dei conteggi del flop.

Ora è di moda affermare che "i flop sono gratuiti" perché la latenza della memoria per recuperare qualsiasi cosa non presente nella cache è molto maggiore del costo di un flop. Ma stiamo ancora insegnando agli studenti a contare i flop, almeno nei corsi di analisi numerica. Dovremmo insegnare loro invece a contare gli accessi alla memoria? Dobbiamo scrivere nuovi libri di testo? O l'accesso alla memoria è troppo specifico per la macchina per passare il tempo? Qual è la tendenza a lungo termine in termini di floppaggi o accesso alla memoria?

Nota: alcune delle risposte seguenti sembrano rispondere a una domanda diversa come "Dovrei riscrivere ossessivamente la mia implementazione per salvare alcuni flop o migliorare le prestazioni della cache?" Ma quello che sto chiedendo è più sulla falsariga di " È più utile stimare la complessità algoritmica in termini di operazioni aritmetiche o accessi alla memoria ?"


1
> "È più utile stimare la complessità algoritmica in termini di operazioni aritmetiche o accessi alla memoria?" . Da un punto di vista pratico, i sistemi integrati sono ancora limitati dalla velocità della FPU piuttosto che dalla larghezza di banda della memoria. Pertanto, anche se il conteggio dei flop era considerato obsoleto dagli standard HPC, è ancora utile per le altre comunità.
Damien,

Risposte:


31

Penso che la cosa giusta da fare (primo ordine) sia guardare il rapporto tra flop e byte necessari nell'algoritmo, che io chiamo . Sia la massima frequenza di flop del processore e la massima larghezza di banda. Se , l'algoritmo sarà limitato in termini di larghezza di banda. Se , l'algoritmo è al flop limitato.F m a x B m a x F m a xβFmaxBmaxBmaxβ>FmaxFmaxβ>BmaxBmaxβ>Fmax

Penso che il conteggio degli accessi alla memoria sia obbligatorio, ma dovremmo anche pensare a:

  • Quanta memoria locale è richiesta

  • Quanta concorrenza possibile abbiamo

Quindi puoi iniziare ad analizzare gli algoritmi per l'hardware moderno.


3
Sono d'accordo con Matt, ma voglio sottolineare che è ora ragionevolmente comunemente definito definito in letteratura come "intensità aritmetica" e "intensità numerica". Penso che il modello Roofline di Williams, Waterman e Patterson sia probabilmente un buon inizio per pensare a questi problemi. Penso che questo dovrebbe essere esteso nel tempo al rapporto di memoria / flop di un algoritmo. β
Aron Ahmadia,

2
David stava facendo più 8 anni prima.
Matt Knepley,

3
Va bene, quindi c'è un modello migliore, più complesso (come sempre). Ma questo modello fornisce una risposta che dipende dalla macchina. Cosa dovremmo insegnare agli studenti come prima analisi?
David Ketcheson,

3
Il punto è che la macchina è stata ridotta a un singolo numero, il rapporto tra i picchi di picco e la larghezza di banda di picco, così come l'algoritmo. Questo è semplice come si arriva. Senza un modello computazionale, qualsiasi stima della complessità è inutile e questa è la più semplice realistica.
Matt Knepley,

1
Penso che tu abbia frainteso il problema. Abbiamo già un trasporto ottico che può trasportare grandi carichi. Il problema è farlo su un chip. Hai solo così tanti fili e una frequenza di clock superiore. Il trasporto ottico allevierebbe questo problema solo su un chip ottico.
Matt Knepley

22

Non vedo perché si debba essere il "vincitore"; questo non è un gioco a somma zero, in cui i conteggi del flop e l'accesso alla memoria devono annegare l'altro. Puoi insegnare a entrambi, e penso che entrambi abbiano i loro usi. Dopotutto, è difficile dire che l' algoritmo con gli accessi alla memoria sarà necessariamente più veloce dell'algoritmo con gli accessi . Tutto dipende dai costi relativi delle diverse parti (quel fastidioso prefattore che ignoriamo sempre in queste analisi!).O ( N ) O ( N log N ) O ( N 2 )O(N4)O(N)O(NlogN)O(N2)

Da una prospettiva più ampia, penso che l'analisi delle prestazioni algoritmiche dovrebbe essere "tutto compreso". Se insegniamo alle persone a essere veri sviluppatori e utenti HPC, allora devono capire quali sono i costi della programmazione nel mondo reale. I modelli di analisi astratti che abbiamo non tengono conto del tempo del programmatore. Dovremmo pensare in termini di "tempo totale alla soluzione", piuttosto che solo conteggi al flop ed efficienza algoritmica. Non ha molto senso dedicare tre o quattro giorni al programmatore per riscrivere una routine che farà risparmiare un secondo di tempo al computer per lavoro, a meno che non si stia pianificando di eseguire qualche milione di calcoli. Allo stesso modo, un investimento di pochi giorni per risparmiare un'ora o due di tempo di calcolo ripaga rapidamente. Quel nuovo algoritmo potrebbe essere sorprendente,


7
Un algoritmo che esegue l'accesso ai dati ? :)O ( N 2 )O(NlogN)O(N2)
Andreas Klöckner,

2
Perchè no? Se si riferisce solo alle operazioni in virgola mobile, forse ci sono anche un numero significativo di operazioni intere che causano l' accesso ai dati :)O ( N 2 )O(NlogN)O(N2)
kini,

9

Come altri hanno sottolineato, la risposta dipende ovviamente dal fatto che il collo di bottiglia sia la CPU o la larghezza di banda della memoria. Per molti algoritmi che funzionano su alcuni set di dati di dimensioni arbitrarie, il collo di bottiglia è in genere la larghezza di banda della memoria poiché il set di dati non si adatta alla cache della CPU.

Inoltre, Knuth menziona che è più probabile che l'analisi dell'accesso alla memoria superi la prova del tempo, presumibilmente perché è relativamente semplice (anche se si tiene conto della compatibilità con la cache) rispetto alle complessità delle moderne pipeline della CPU e alla previsione dei rami.

Knuth usa il termine gigamem nel volume 4A di TAOCP, durante l'analisi dei BDD. Non sono sicuro che lo usi nei volumi precedenti. Ha fatto il commento di cui sopra sulla resistenza alla prova del tempo nella sua conferenza annuale sull'albero di Natale del 2010.

È interessante notare che lo stai facendo in modo errato dimostra che anche l'analisi delle prestazioni in base alle operazioni di memoria non è sempre semplice in quanto vi sono elementi come la pressione della VM che entrano in gioco se i dati non si adattano alla RAM fisica in una sola volta.


8

Il modo in cui si determinano i costi di un algoritmo dipende dal "livello" di elaborazione scientifica che si lavora e dalla classe (ristretta o ampia) di problemi che si considera.

Se si pensa all'ottimizzazione della cache, questo è chiaramente più rilevante, ad esempio, per l'implementazione di pacchetti numerici di algebra lineare come BLAS e librerie simili. Quindi questo appartiene all'ottimizzazione di basso livello, ed è bene avere un algoritmo fisso per un problema specifico e con vincoli sufficienti sull'input. Ad esempio, l'ottimizzazione della cache potrebbe essere rilevante per avere una rapida implementazione dell'iterazione del gradiente coniugato se si promette che la matrice sia sufficientemente sparsa.

D'altra parte, più ampia è la classe di problemi, meno si può prevedere sull'elaborazione effettiva (come, diciamo, non si sa quanto saranno scarse le matrici di input dell'implementazione CG). Più ampia è la classe di macchine su cui dovrebbe essere eseguito il programma, meno si può prevedere sull'architettura della cache.

Inoltre, a un livello più elevato di informatica scientifica, potrebbe essere più rilevante modificare la struttura del problema. Ad esempio, se si impiega del tempo a trovare un buon precondizionatore per un sistema lineare di equazioni, questo tipo di ottimizzazione di solito batte qualsiasi ottimizzazione di basso livello, poiché il numero di iterazioni è drasticamente ridotto.

In conclusione, l'ottimizzazione della cache è utile solo se non è rimasto nulla da ottimizzare tramite il parallelismo e la riduzione del numero asintotico di FLOP.

Penso che sia saggio adattare la posizione dell'informatica teorica: alla fine, migliorare la complessità asintotica di un algoritmo ha un ritorno maggiore rispetto alla micro-ottimizzazione di alcune linee di codice esistenti. Pertanto, il conteggio dei FLOP è ancora preferito.


"L'ottimizzazione della cache è utile solo se non è rimasto nulla da ottimizzare con il parallelismo e la riduzione del numero asintotico di FLOP". Non sono d'accordo. Se si desidera calcolare una grande espressione di un grande numero di numeri, è meglio eseguire un passaggio alla volta con tutti i numeri rispetto a tutti i passaggi per ciascun numero. Entrambi hanno lo stesso numero di FLOPS, ma uno è migliore nell'accesso alla memoria. Bonus se selezioni la dimensione del mazzo da inserire nella cache (o il compilatore lo fa per te). Questo è ciò che fa numexpr in Python: github.com/pydata/numexpr
Davidmh

6

Mi sono sempre rifiutato di pensare anche al conteggio dei flop, degli accessi alla memoria o di qualunque cosa tu abbia. Questo è un concetto degli anni '60, quando ciò che hai fatto è stato praticamente dato e solo come lo hai fatto è dipeso dall'ottimizzazione algoritmica. Pensa a risolvere un problema agli elementi finiti su una mesh xyz uniforme usando l'eliminazione gaussiana dell'iterazione Jacobi.

Ora puoi ottimizzarlo all'inferno e salvare alcuni flop, guadagnando il 10% del tempo di esecuzione. Oppure puoi pensare di implementare un metodo multigrid e un precondizionatore di blocchi ottimale, ottenendo un fattore 10 in tempo di esecuzione. Questo è ciò che dovremmo addestrare i nostri studenti a fare: pensa a quali algoritmi esterni complessi possono farti nel cercare di trovare un algoritmo interno migliore. Il tuo capo (Keyes) ha queste diapositive sui progressi nei calcoli MHD che rendono questo punto piuttosto ovvio.


In realtà stavo chiedendo il tipo di pensiero di alto livello che suggerisci, non l'ottimizzazione di basso livello. Quale metrica dovresti usare per determinare se multigrid e il tuo precondizionatore saranno più veloci delle alternative?
David Ketcheson,

Non saprei contare - a mano - FLOPS o qualsiasi altra istruzione conta per algoritmi complessi che si estendono su decine o migliaia di righe di codice. Pensa, ad esempio, a quanto sia complessa la fase di analisi e costruzione degli algoritmi AMG. Esistono così tante parti di questi algoritmi e tutte dipendono dai dati effettivi che non è possibile prevedere il numero di operazioni.
Wolfgang Bangerth,

1
All'inizio penso di aver frainteso quello a cui stavi arrivando, ma non sono ancora d'accordo con il tuo punto. Gli "algoritmi esterni" possono (e direi, dovrei) essere ancora progettati pensando alla complessità asintotica. Sicuramente non diresti che un passaggio da un algoritmo quadratico a un algoritmo quasi lineare porterebbe nel migliore dei casi a una riduzione del 10% del tempo di esecuzione; ma in che altro modo quantificare la complessità asintotica che attraverso i flop e / o le operazioni di memoria?
Jack Poulson il

7
Penso che questo approccio "buttati le mani" agli algoritmi sia una schifezza. Devi semplificare l'analisi osservando solo i costi del primo ordine e semplificando il modello in modo che sia trattabile, ma dire che non puoi analizzare qualcosa come MG o Cholesky perché è troppo complicato è decisamente sbagliato.
Matt Knepley,

1
Bene, ma cosa significa analizzare MG o Cholesky quando ogni FLOP che contate è nascosto dietro diversi strati di latenza causati da processori hyperthreaded, cache, RAM lenta, processori multiscalar e vettorializzazione automatica? Il punto che sto sottolineando è che entro un fattore di 5-10, non è più possibile prevedere il tempo di esecuzione dei propri algoritmi senza cronometrarlo. Era completamente diverso negli anni '50 e '60 quando le persone iniziarono a contare questo FLOP.
Wolfgang Bangerth,

1

Sì, obsoleto. L'analisi algoritmica mediante flop o qualsiasi altro metodo è utile solo come il modello astratto della macchina se si considera la dimensione del problema attuale. Le prestazioni effettive dipendono sia dall'implementazione che dall'hardware e l'applicabilità di qualsiasi modello astratto per quest'ultimo alla realtà sta diminuendo nel tempo. Ad esempio, mentre parallelizzi ulteriormente l'implementazione di un algoritmo complesso, come la dinamica molecolare, diversi aspetti diventano limitatori di velocità su hardware diverso e l'analisi algoritmica non ha nulla a che fare con le osservazioni. In un certo senso, l'unica cosa importante è misurare le prestazioni dell'implementazione (i) dell'algoritmo (i) sui tipi di hardware in questione.

Tali astrazioni sono utili come strumento di apprendimento? Sì, come molti modelli utilizzati per l'insegnamento, sono utili purché siano posti accanto alla comprensione dei limiti del modello. La meccanica classica va bene purché apprezzi che non funzionerà su scale di piccola distanza o grande velocità ...


-1

Non rispondi veramente alla tua domanda, ma aggiungi un'altra variabile da considerare: qualcosa da prendere in considerazione sono le caratteristiche del linguaggio di programmazione. Ad esempio, Python sortutilizza l' algoritmo Timsort , progettato (tra le altre belle proprietà) per ridurre al minimo il numero di confronti, che potrebbe essere potenzialmente lento per gli oggetti Python. D'altra parte, confrontare due float in C ++ è velocissimo, ma scambiarli è più costoso, quindi usano altri algoritmi.

Altri esempi sono l'allocazione dinamica della memoria (banale in un elenco Python, veloce sia in tempo di runtime che in quello degli sviluppatori, giusto .append()), rispetto a FORTRAN o C, dove, sebbene possibile e più veloce se correttamente implementato, ci vuole molto più tempo di programmazione e cervello. Vedi Python è più veloce di FORTRAN.


Questo è vero, ma, come dici tu, non risponde alla domanda. È su un argomento diverso.
David Ketcheson,

Bene, in una corretta analisi è qualcosa da prendere in considerazione quando si decide quale algoritmo implementare.
Davidmh,
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.