




























































































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Appunti completi del corso di Parallel Computing (2023/2024) tenuto dal professore Marco Bertini. Gli appunti contengono: introduzione, concetti di parallelizzazione, threads, profiling e timing, CPU, vettorizzazione, OpenMP, GPU e CUDA.
Tipologia: Appunti
1 / 242
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!





























































































Un sistema si dice concorrente se può supportare due o più azioni in progresso allo stesso momento. Ovvero, un’applicazione concorrente avrà due o più thread in pro- gresso in un determinato momento (ad esempio, due thread vengono continuamente scambiati dal sistema operativo su un processore a singolo core per avanzare progressi- vamente). Un sistema si dice parallelo se può supportare due o più azioni in esecuzione allo stes- so momento. Ovvero, un’applicazione parallela avrà due o più thread in esecuzione si- multanea se il calcolatore possiede più core disponibili (ad esempio, due o più thread vengono assegnati a core separati per essere eseguiti contemporaneamente). N.B : possiamo considerare il parallelismo come un sottoinsieme della concorrenza, ovvero Parallelismo ⊆ Concorrenza.
Un programma concorrente diventa parallelo se sono disponibili abbastanza core ( unità di elaborazione ) per eseguire thread (o processi multipli) simultaneamente. Quindi, la programmazione concorrente è caratterizzata dalla composizione di pro- cessi in esecuzione indipendente. Invece, la programmazione parallela è caratterizzata dall’esecuzione simultanea di calcoli. Sotto questo aspetto, la concorrenza rappresenta la gestione di molte azioni contempo- raneamente. Invece, il parallelismo consiste nel fare molte azioni allo stesso momento. Quindi, la concorrenza fornisce un modo di strutturare la risoluzione di un problema che può essere parallelizzabile (ma non necessariamente).
Un algoritmo concorrente è un algoritmo strutturato in modo tale da poter eseguire i suoi passaggi in modo indipendente. Un algoritmo concorrente può essere eseguito in serie. Tuttavia, è necessaria una comunicazione per coordinare le esecuzioni indipenden- ti. Un algoritmo parallelo è progettato per eseguire più operazioni nello stesso momento. Il parallelismo di un algoritmo può migliorare le prestazioni su diversi tipi di computer. N.B : il termine parallelizzazione indica la traduzione di un codice seriale in un codice concorrente.
necessaria per far funzionare la CPU ad una determinata frequenza è approssimativa- mente proporzionale alla frequenza (ovvero V ∝ f ). Perciò, il consumo di potenza di una CPU sarà proporzionale al cubo della frequenza, cioè P ∝ f^3. Quindi, aumentando la frequenza, possiamo elaborare in un tempo minore la stessa quantità di lavoro, ma l’energia richiesta dal sistema di calcolo dipenderà in modo qua- dratico dalla frequenza, ovvero E ∝ f^2 (questa energia verrà dissipata sotto forma di calore). Il parallelismo, può essere utilizzato per conservare l’energia richiesta dalla CPU. L’idea è quella di incrementare il numero di core disponibili, ognuno dei quali opera ad una frequenza minore. In questo modo, ogni singolo core può eseguire un numero di istru- zioni minore in un’unita temporale, ma essi opereranno simultaneamente riducendo il tempo di esecuzione dei task.
Le GPU hanno bisogno di molta potenza, ma grazie al parallelismo possiamo ridurre il consumo.
�����ES: Il processore Xeon E5-4660 a 16 core di Intel ha una potenza termica di 120 W. Supponiamo che l’applicazione venga completata utilizzando 20 pro- cessori di questo tipo per 24 ore. Il consumo energetico stimato per l’esecu- zione dell’applicazione sarà:
( 120
) × (24ore) = 57_._ 60 kWh
Supponiamo adesso di eseguire l’applicazione su quattro GPU NVIDIA Te- sla V100 per 24 ore. Una GPU Tesla V100 di NVIDIA ha una potenza ter- mica di 300 W. Il consumo energetico stimato per l’esecuzione dell’applica- zione sarà:
( 300
) × (24ore) = 28_._ 80 kWh
In generale, le GPU hanno una potenza termica superiore alle CPU, ma possono potenzialmente ridurre il tempo di esecuzione o richiedere solo po- che GPU per ottenere lo stesso risultato.
Osserviamo che alcuni programmi paralleli possono essere peggiori delle loro contropar- ti sequenziali. Questo è dovuto principalmente a due fattori:
1.1 Tipi di parallelismo
Analizziamo i principali tipi di parallelismo:
di istruzioni e dati in operazioni seriali o multiple. In particolare, si distinguono quattro categorie:
Possiamo riassumere questa categorizzazione attraverso la seguente tabella che rappre- senta la tassonomia di Flynn:
N.B : la tassonomia è stata ampliata con SPMD (Single Program Multiple Data), ov- vero un’architettura in cui i task vengono suddivisi ed eseguiti simultaneamente su più processori con input diversi, per ottenere risultati più rapidi (SPMD potrebbe essere considerato un programma parallelo su un computer MIMD).
Figura 1.2: La figura mostra il modello di computer parallelo CTA. Tale modello è costituito da P computer sequenziali, collegati da una rete di interconnessione (o rete di comunicazione). Inoltre viene mostrato in dettaglio come è costituito un processore Pi.
Un aspetto fondamentale dei computer paralleli è che i riferimenti alla memoria locale e non locale richiedono tempi diversi per essere completati. Il ritardo necessario per fare un riferimento alla memoria è chiamato Memory Latency (o latenza di memoria ) ed è indicato con la lettera λ. La Memory Latency non può essere specificata in secondi, perché il modello si gene- ralizza su molte architetture diverse, ognuna costruita con elementi di progettazione diversi provenienti da tecnologie diverse. Pertanto, viene specificata rispetto alla laten- za della memoria locale del processore, che viene considerata di tempo unitario. Questa convenzione implica che la latenza della memoria locale segue approssimativamente la velocità del processore e si ipotizza che la memoria locale possa essere referenziata alla velocità di una parola per istruzione. I riferimenti alla memoria non locale sono molto più costosi, avendo valori λ di 2 − 5 ordini di grandezza superiori ai tempi di riferimento della memoria locale.
1.3 Metriche per la valutazione delle prestazioni
Quando si parla di calcolo parallelo, la nozione di prestazioni è complessa perché ci so- no molteplici aspetti da considerare, tra cui l’uso della memoria, il tempo di elabora- zione e l’overhead. Un’applicazione può operare su valori organizzati come flussi o come singoli valori di dati. N.B : un flusso è una sequenza possibilmente infinita di valori dello stesso tipo (ad esempio, matrici di dimensioni note che rappresentano immagini).
Prendiamo in considerazione diverse metriche di performance:
N.B : quando si tratta di singoli valori di dati, il tempo di completamento è signi- ficativo al contrario del tempo di servizio.
�����ES (programma sequenziale): Consideriamo un singolo modulo sequenziale Σ che opera su un flusso di dati di lunghezza m. In particolare, il modulo Σ implementa k operazioni, ciascuna con tempo medio di servizio ti e probabilità di occorrenza pi. Allo- ra possiamo analizzare le seguenti metriche:
t =
∑^ k
i =
pi · ti
t
tc = m · t
�����ES (programma parallelo): Consideriamo una trasformazione di Σ in una versione parallela Σ n^ di n moduli. Pertanto, il grado di parallelismo di Σ n n è sempre n , indipenden- temente dalla capacità effettiva di tutti i moduli di operare in parallelo in qualsiasi momento. Allora possiamo analizzare le seguenti metriche:
Tale metrica mette in relazione il tempo di completamento ts del programma se- quenziale con il tempo di completamento tP del relativo programma parallelo, dove P è il numero di processori. Ovvero:
ts tP In particolare, la speedup viene detta:
- Ideale se SP = P. - Lineare se SP ∼= P. - Superlineare se SP > P , per qualche P.
N.B : quando i dati sono partizionati e distribuiti su P processori, i singoli da- ti sono (molto) più piccoli e possono essere inseriti interamente nella cache dei dati di ciascun processore. Pertanto, la riduzione delle miss nella cache per un al- goritmo con speedup lineare può portare ad una speedup superlineare. Questo è anche uno dei motivi per cui la scalabilità è più difficile da valutare rispetto alla speedup. N.B : alcuni fattori possono limitare la speedup, come la possibile inattività dei processori, l’esecuzione di calcoli aggiuntivi nella versione parallela e l’overhead associato alle operazioni di comunicazione e sincronizzazione tra i moduli.
Figura 1.3: Tipi di speedup. 1. Speedup ideale o lineare. 2. Speedup sublineare. 3. Speedup con un numero ottimale di processori. 4. No speedup. 5. Speedup superlineare.
t 1 tP
Analogamente, se consideriamo k processori, con k < P , allora possiamo definire la speedup relativa rispetto a k processori come:
SPk =
tk tP
La speedup relativa SPk viene utilizzata quando k rappresenta il numero più pic- colo di processori su cui può essere eseguito il problema.
L’efficienza fornisce una stima del grado di utilizzo dei processori per la risoluzio- ne del problema, in relazione alla quantità di sforzi sprecati a causa di inattività dei processori e delle operazioni di comunicazione e sincronizzazione. N.B : molti algoritmi difficilmente parallelizzabili hanno un’efficienza che si avvi- cina a zero all’aumentare del numero di processori P utilizzati. N.B : una speedup ideale comporta un’efficienza del 100%, ovvero EP = 1.
�����ES (speedup): Consideriamo un problema di ricerca all’interno di una struttura dati. Una possibile implementazione di un algoritmo parallelo per risolvere questo pro- blema coinvolge la suddivisione dello spazio di ricerca in P parti (o chunks ). Quindi, si assegna a ciascuno dei P processori un chunk specifico su cui ef- fettuare la ricerca. In questo contesto, la speedup viene valutata come se- gue: SP =
( x · t Ps ) + ∆ t ∆ t dove x rappresenta il numero di chunks visitati prima di individuare il dato cercato e ∆ t rappresenta il tempo aggiuntivo richiesto per eseguire la ricerca all’interno del chunk in cui è presente il dato.
Nel caso peggiore per la ricerca sequenziale, in cui l’elemento cercato si tro- va nell’ultimo chunk, la speedup tende all’infinito ( SP −→ ∞) quando ∆ t tende a zero. Questo scenario sottolinea il vantaggio significativo dell’ap- proccio parallelo quando il dato da cercare si trova all’interno dell’ultimo chunk.
Di conseguenza, la speedup massima possibile SP è limitata e tende a un valore (^) f^1 quan-
do il numero di processori P tende all’infinito (ovvero SP P −→∞ −−−−→ f −^1 ). Questo implica che anche se il 95% di un programma è parallelizzabile, il miglioramen- to della speedup non supererà mai un fattore di 20 volte. In altre parole, ci sono limiti intrinseci al grado di miglioramento che può essere ottenuto attraverso il parallelismo, e questi limiti sono fortemente influenzati dalla frazione di codice che non può essere parallelizzata.
La legge di Amdahl si applica principalmente nei contesti in cui la dimensione del pro- blema è fissa. Tuttavia, nella pratica, quando si dispone di risorse computazionali ag- giuntive, queste tendono ad essere impiegate per affrontare problemi di dimensioni maggiori (ovvero, insiemi di dati più grandi). In questa dinamica, il tempo dedica- to all’elaborazione della parte parallelizzabile può crescere in modo significativo più rapidamente rispetto al lavoro intrinsecamente sequenziale.
�����ES: Consideriamo un programma che deve effettuare due operazioni, ovvero la somma di 10 scalari (operazione sequenziale) e la somma di matrici di di- mensione 10 × 10 (operazione parallelizzabile). Se un singolo processore esegue queste operazioni (programma sequenziale), il tempo di completamento totale sarà:
t 1 = (10 + 100) · t sum = 110 · t sum
Se consideriamo l’utilizzo di 10 processori in grado di eseguire in parallelo il calcolo della somma matriciale, il tempo di completamento sarà:
t 10 = 10 · t sum +
· t sum = 20 · t sum
In questo caso, la speedup ottenuta utilizzando 10 processori sarà:
Ovvero, stiamo sfruttando il 55% del potenziale dei processori utilizzati. Invece, se consideriamo 100 processori, il tempo di completamento sarà:
t 100 = 10 · t sum +
· t sum = 11 · t sum
In questo caso, la speedup ottenuta utilizzando 100 processori sarà:
Ovvero, stiamo sfruttando il 10% del potenziale dei processori utilizzati. N.B : stiamo assumendo una distribuzione equa del carico tra i processori.
La legge di Amdahl descrive un fatto che si applica a un’istanza di calcolo. Una volta fissata l’istanza, considera gli effetti dell’aumento del parallelismo. Tuttavia, la mag- gior parte dei calcoli paralleli fissa il parallelismo ed espande le dimensioni dell’istan- za. In questo caso la percentuale di codice sequenziale spesso diminuisce man mano che si considerano istanze più grandi. Aumentando le dimensioni del problema, la par- te sequenziale può aumentare in modo trascurabile, rendendo una parte maggiore del problema adatta al parallelismo.
�����ES: Consideriamo l’esercizio precedente, ma aumentiamo la dimensione delle matrici a 100 × 100.