Università degli studi di Roma Tor Vergata Facoltà di Scienze MM FF NN Corso di laurea specialistica in Fisica

Dimensione: px
Iniziare la visualizzazioe della pagina:

Download "Università degli studi di Roma Tor Vergata Facoltà di Scienze MM FF NN Corso di laurea specialistica in Fisica"

Transcript

1 Università degli studi di Roma Tor Vergata Facoltà di Scienze MM FF NN Corso di laurea specialistica in Fisica Relazione sul corso avanzato di Calcolo Parallelo e Grid Computing svolto presso l Università di Catania, promosso dall Istituto Nazionale d Astrofisica (INAF) in collaborazione con il CINECA e l Istituto Nazionale di Fisica Nucleare (INFN) di Catania, dal 28/09/2008 al 04/10/2008. A cura di Alessandro Maiorana sotto la supervisione della prof.ssa Silvia Morante e della dott.ssa Velia Minicozzi

2 Sommario Introduzione II 1. HPC, calcolo distribuito e applicazioni scientifiche 1.1 Sistemi di calcolo in parallelo Architetture e modelli di programmazione paralleli Prospettive future Message Passing Interface (MPI) 2.1 Introduzione e sintassi essenziale Comunicazioni point to point Comunicazioni collettive Ottimizzazione dei codici La GRID 3.1 GRID computing Utilizzo GRID in ambito scientifico Tecniche di debugging di codici 45 Appendice 1 Installazione della libreria Open-MPI 48 Appendice 2 Operazioni collettive MPI 49 Glossario 50 Bibliografia 58

3 Introduzione Negli ultimi vent anni le scienze computazionali sono diventate, insieme con le scienze teoriche e sperimentali, il terzo pilastro dell indagine scientifica, permettendo ai ricercatori di costruire e testare i modelli creati per spiegare fenomeni complessi. Il calcolo ad alta perfomance (High Performance Computing, HPC) è diventato uno strumento essenziale nello studio in numerose discipline scientifiche e tecnologiche, ad esempio: Simulazione di sistemi ingegneristici completi; Simulazione di sistemi biologici completi; Astrofisica; Scienza dei materiali; Bio-informatica, proteomica, farmaco-genetica; Nanotecnologia; Modelli funzionali 3D scientificamente accurati del corpo umano; Climatologia e meteorologia; Digital libraries per la scienza e l ingegneria. Queste sono solo una parte delle applicazioni dell HPC. Esso ci permette, inoltre, di creare una rete di interdisciplinarietà fra branche della scienza, altrimenti separate. Le innovazioni tecnologiche e scientifiche permetteranno all HPC di superare i problemi esistenti, in particolare: Aumentare la velocità delle comunicazioni tra le varie CPU; Distribuire geograficamente il lavoro; Incrementare la produttività; Elaborare un sempre maggior afflusso di dati. Poter incrementare la complessità dei problemi da studiare; Per uno scienziato uno dei problemi da risolvere è quello di riuscire ad elaborare ed analizzare in tempi rapidi un sempre maggior numero di dati, ad esempio il genoma unamo. In futuro l HPC permetterà di elaborare un numero di dati sempre maggiore. Più grande sarà l incremento tecnologico maggiore sarà la capacità di risolvere sistemi complessi ed elaborare una grande quantità di dati. Un esempio di tale sviluppo sono i Test Crash Dummy, che da un paio d anni avvengono in maniera virtuale (Fig.1), dimezzando i costi delle case automobilistiche ed aumentando il numero di informazioni estraibili. Infatti, grazie all HPC, non solo siamo in grado di verificare la sicurezza Fig.1. E-crash dummy II

4 Fig.2. Visualizzazione 3D dellacassa toracica e degli organi. delle automobili e delle sue componenti, ma possiamo analizzare l impatto in 3D, oppure visualizzare quali sono le conseguenze dell apertura dell airbag sulla cassa toracica (Fig.2) e quali organi sono coinvolti. Questo è solo uno degli esempi, in cui l HPC ci permette di integrare ed elaborare una grande quantità di dati e di visualizzarli, attraverso la costruzione di un modello 3D. Dopo quest esempio di applicazione dell HPC, vediamo com è possibile misurare la potenza di un cluster HPC e farne il confronto con altri. Esiste una grandezza che ci permette di misurare il numero di operazioni al secondo che una CPU può effettuare, e prende il nome di flops. Sulla base di questa grandezza ogni anno viene pubblicata una classifica mondiale dei calcolatori più potenti del mondo, che prende il nome di top500. Le posizioni in classifica dipendono da quante operazioni al secondo (floatingpoint/ sec) riesce a compiere un dato sistema, basato su un problema di risoluzione di sistemi lineari. In Fig.3, per esempio, possiamo osservare come lo sviluppo di macchine sempre più potenti ci permetta di raggiungere perfomance sempre maggiori. Le tre curve rappresentano l andamento dei flops in funzione del tempo per il calcolatore che si trova nella prima posizione in classifica nella top500 (quadrati rossi), per il calcolatore che si trova nella posizione 500 (quadrati viola), e la loro somma (quadrati verdi). Si è passati dai primi supercomputer negli anni 70 che raggiungevano i MFlops, ai recenti supercomputer che raggiungono i PFlops. Nel 2008 entrerà in azione negli USA il supercomputer più potente al mondo che prende il nome di Roadrunner; un sistema ibrido che connette 6562 processori dual-core AMD Opteron integrati con processori IBM Cell (disegnati in origine per piattaforme video game come la Playstation 3 Sony) che fungono da acceleratori. L intero sistema si compone di cores e 98 TeraByte di RAM interconnessi via Infiniband 4x DDR. Attualmente al primo posto in classifica nella top500 troviamo il supercomputer Blue Gene P, costruito dall IBM. III Fig.3. Trend delle perfomance

5 Oltre ad un progressivo sviluppo di macchine superpotenti, le case costruttrici di processori stanno sviluppando nuove CPU, che al loro interno contengono più core, aumentando notevolmente le prestazioni del singolo calcolatore. Naturalmente per sfruttare al meglio l HPC bisogna sviluppare degli algoritmi che siano in grado di ottimizzare il calcolo in parallelo. Per questo motivo stanno nascendo nuovi linguaggi di programmazione che supportano il sistema di Global Address Space (GAS), ad esempio UPC, Co-Array Fortran, Titanium, ecc. IV

6 1. HPC, calcolo distribuito e applicazioni scientifiche 1.1 Sistemi di calcolo in parallelo Sappiamo che i calcolatori convenzionali sono basati sul modello di Von Neumann, dove le istruzioni vengono processate in maniera sequenziale, cioè: I. un istruzione viene caricata dalla memoria (fetch) e decodificata; II. vengono calcolati gli indirizzi degli operandi; III. vengono prelevati gli operandi dalla memoria; IV. viene eseguita l istruzione; V. il risultato viene scritto in memoria (store); Naturalmente l obiettivo primario è quello di aumentare la velocità del processo e può essere fatto in due modi: aumentando la velocità dei componenti elettronici; aumentando il grado di parallelismo architetturale (numero di attività che possono essere compiute contemporaneamente); L aumento della velocità dei componenti elettronici è limitato da due fattori: limite della velocità della luce; problema della dissipazione del calore; Esiste, inoltre, un gap nello sviluppo dell architettura dei calcolatori dovuto alle differenze di perfomance tra processori e memoria, infatti mentre la performance dei processori raddoppia ogni 18 mesi quella della memoria raddoppia circa ogni 6 anni. La legge empirica di Moore (Fig.4), afferma che la complessità Fig.4. Andamento della legge empirica di Moore dei dispositivi (numero di transistor per square inch nei microprocessori) raddoppia ogni 18 mesi. Si stima che la legge di Moore valga ancora almeno per questo decennio. Oltre alla potenza del processore, altri fattori influenzano le prestazioni degli elaboratori: dimensione della memoria; larghezza di banda (bandwidth) fra memoria e processore; larghezza di banda verso il sistema di I/O; dimensione e larghezza di banda della cache; latenza fra processore, memoria e sistema di I/O; Storicamente il concetto di parallelismo parte negli anni 40, ma è solo negli anni 70 che avvengono i primi miglioramenti architetturali, come: Memoria bit-parallel e Aritmetica bit-parallel; 1

7 Maggior velocità Registri Cache Memory Memoria Primaria Memoria Secondaria Fig.5. Gerarchie di memoria Maggior Capacità Minor costo Processori indipendenti per l attività di I/O; Memoria interleaved; Gerarchie di memoria; Unità funzionali multiple; Unità funzionali segmentate; Pipelining; Anche nel campo dei software emergono dei miglioramenti legati alla multiprogrammazione, al look ahead e scheduling delle istruzioni. Con la nascità dei sistemi vettoriali, degli array processors, delle architetture sistoliche e dei very long instruction word (VLIW) possiamo realmente parlare di parallelismo, in particolare di parallelismo sincrono, cioè dove ogni processore esegue le stesse istruzioni degli altri ma su dati diversi. Solo con la nascita dei sistemi a multiprocessore e dei multicomputer possiamo parlare di parallelismo asincrono, dove ogni processore esegue le proprie istruzioni in modo indipendente dagli altri. Come già detto, oltre ai problemi legati allo sviluppo dei processori, abbiamo dei problemi legati alla memoria. Innanzitutto vediamo quali sono le gerarchie di memoria (Fig.5), che possono essere identificate attraverso due fattori: A. Tempo di accesso alla memoria: è il tempo necessario ad eseguire un operazione di lettura/ scrittura su una locazione di memoria; B. Tempo di ciclo della memoria: indica il tempo che deve trascorrere prima di un nuovo accesso a una stessa locazione di memoria Negli ultimi anni questi tempi sono molto migliorati rendendo possibili sistemi di memoria più veloci ma al tempo stesso è diminuito anche il tempo di clock del processore. La memoria cache è un unità di dimensioni ridotte usata come buffer per i dati che vengono scambiati fra la memoria centrale e il processore. Consente di ridurre il tempo speso dal processore in attesa dei dati dalla memoria principale. L'efficienza della cache dipende dalla località dei riferimenti nei programmi e si divide in: Località temporale: una istruzione o un dato possono essere referenziati più volte; Località spaziale: quando si referenzia una locazione di memoria, è molto probabile che vengano referenziate anche le locazioni adiacenti; Diversi calcolatori dispongono anche di cache per le istruzioni (o instruction buffer) oppure di cache che contengono sia dati che istruzioni, cioè: l'istruzione viene prelevata dalla cache anziché dalla memoria; un'istruzione può essere eseguita ripetutamente senza ulteriori riferimenti 2

8 alla memoria principale; E' demandato all'abilità del sistema far rientrare le istruzioni che compongono un kernel computazionale pesante (es. un loop) all interno della cache, se queste possono esservi contenute per intero. Lo stesso vale per i dati, ma in questo caso l opera di ottimizzazione coinvolge anche il programmatore. La cache è divisa in slot della stessa dimensione (linee). Ogni linea contiene k locazioni di memoria consecutive (es. 4 word, ognuna di grandezza 4byte). Quando è richiesto un dato dalla memoria, se questo non è già in cache, viene Memoria Cache caricata dalla memoria l intera linea di cache che lo contiene (Fig.6), sovrascrivendo così il contenuto precedente della linea. Quando si modifica un dato, memorizzando un nuovo valore in cache, occorre aggiornare il dato anche in memoria principale, ed esistono due modi per farlo: Cache write-back: i dati scritti nella cache vi rimangono finché la linea di cache non è richiesta per memorizzare altri dati e quando si deve rimpiazzare la cache il dato viene scritto in memoria; comune nei sistemi monoprocessore; Cache write-through: i dati vengono scritti immediatamente nella cache e nella memoria principale. Nei sistemi con più processori occorre gestire la coerenza della cache: per accedere a dati aggiornati e i processori devono essere a conoscenza dell attività delle cache locali. Poiché in ogni istante temporale la cache può contenere solo un sottoinsieme della memoria, occorre sapere quale: si tratta di associare un insieme di locazioni di memoria ad una linea di cache (mapping). In base al mapping la cache può essere organizzata in uno dei seguenti modi: Fig.6. Accesso alla memoria cache Direct mapped: con questo schema, se ad es. la dimensione della cache è di 8 KByte e la memoria centrale ha word di 8 Byte, la prima locazione di memoria (word 1) viene mappata sulla linea 1 (Fig.7), così come la locazione d+1, 2d+1, 3d+1 ecc. (dove d = N linee * N word per linea); quando si hanno riferimenti di memoria che alternativamente puntano alla stessa linea di cache (es. word 1, word 1025, word 1, word 1025, ripetutamen- 3

9 1 1.9 te), ogni riferimento causa un cache miss e si deve rimpiaz zare la linea appena inserita Si genera parecchio lavoro ag- giuntivo (overhead); questo Linea Linea fenomeno è detto thrashing. Linea Set associative: la cache Linea Linea 5 fa più copie dello stesso ban co, in questo modo crea una Linea doppia possibilità di accedere Cache ai dati senza correre il rischio 2049 di sovrascriverli(fig.8) su dati 2050 ancora utili. Memoria Full associative: in questo caso la cache è libera di Fig.7. Esempio di cache direct mapping scegliere in quale linea caricare il dato senza restrizioni. Nei calcolatori tradizionali, la CPU way set associative è costituita da un insieme di registri 2048 word, linee di 4 word generali, da alcuni registri speciali Memoria (es. il program counter) e dall'unità aritmetico logica (ALU) che, una per volta, calcola le operazioni. Un primo passo verso il parallelismo consiste nel suddividere le funzioni dell'alu e progettare unità indipendenti capaci di operare in parallelo (unità funzionali indipendenti). E' compito del compilatore esaminare le istruzioni e stabilire quali operazioni possono essere fatte in parallelo, senza alterare la semantica del programma. Un altro concetto molto importante è il pipelining, che è analogo a quello di catena di montaggio dove in una linea di flusso (pipe) di stazioni di assemblaggio gli elementi vengono assemblati a flusso continuo. I- dealmente tutte le stazioni di assemblaggio devono avere la stessa velocità di elaborazione altrimenti la stazione più lenta diventa il bottleneck dell'intera pipe. Per esempio un task T viene scomposto in un insieme di sottotask {T 1,T 2,...T k } legati da una relazione di dipendenza: il task T j non può partire finché tutti i sottotask precedenti {T i, i<j} non sono terminati (Fig.9). Nel 1966 Michael J. Flynn classifica i sistemi di calcolo a seconda della molteplicità del flusso di istruzioni e del flusso dei dati che possono gestire; in seguito questa classificazione è stata estesa con una sottoclassificazione per considerare anche il tipo di architettura della memoria (Fig.10). Si considerino lo stre Cache Linea 1 Linea 2 Linea 3 Linea 4 Linea 5.. Linea 256 Linea Linea Banco 1 Fig.8. Esempio di cache set associative Banco 2

10 am delle istruzioni (sequenza delle Spazio istruzioni eseguite dal calcolatore) e lo T j i j mo subtask del task i mo S 4 S 3 S 2 S 1 1 T T 3 T 1 T 1 T T 4 T 4 T 4 T 4 T T 3 T 3 T 3 T T T T T T 1 T Fig.9. Sovrapposizione delle operazioni in una pipe a 4 stadi. Fig.10. Architetture di calcolo 5 Tempo(cicli) stream dei dati (sequenza dei dati usati per eseguire uno stream di istruzioni): Single Instruction stream (SI), Single Data stream (SD), Multiple Instruction stream (MI), Multilpe Data stream (MD). Si ottengono così quattro combinazioni possibili: Single Instruction Single Data (SISD): corrisponde alla classica architettura di Von Neumann; sono sistemi scalari monoprocessore dove l'esecuzione delle i- struzioni può essere pipelined e dove ciascuna istruzione aritmetica inizia un'operazione aritmetica; Single Instruction Multiple Data (SIMD): in questo caso si parla di parallelismo sincrono. I sistemi SIMD hanno una sola unità di controllo, ed una singola istruzione opera simultaneamente su più dati. Appartengono a questa classe gli array processor e i sistemi vettoriali; Multiple Instruction Single Data (MISD): è un'architettura parallela in cui diverse unità effettuano diverse elaborazioni sugli stessi dati. Attualmente non esistono macchine MISD. Sono stati sviluppati alcuni progetti di ricerca ma non esistono processori commerciali che ricadono in questa categoria; Multiple Instruction Multiple Data (MIMD): in questo caso si parla di pa-

11 rallelismo asincrono dove più processori eseguono istruzioni diverse e operano su dati diversi. Versione multiprocessore della classe SIMD. Spazia dai linked main frame computer alle grandi reti di micro-processori. Oltre ad una classificazione di Flynn, possiamo effettuare una classificazione in base al tipo di condivisione della memoria, cioè: Sistemi a memoria condivisa: in questo caso i processori coordinano la loro attività, accedendo ai dati e alle istruzioni in una memoria globale (shared memory) condivisa da tutti i processori (Fig.11). L accesso alla memoria è uniforme: i processori presentano lo stesso tempo di accesso per tutte le parole di memoria, mentre l interconnessione processore-memoria avviene tramite common bus, crossbar switch, o multistage network. Ogni processore può disporre di una cache locale, le periferiche sono condivise.i sistemi a memoria condivisa presentano un numero limitato di processori (da 2 a 32) molto potenti (possono presentare anche un architettura vettoriale). Questi multiprocessori sono chiamati tightly coupled systems per l alto grado di condivisione delle risorse. I sistemi Uniform Memory Access (UMA) e Symmetric Multi Processors (SMP) ne sono un esempio. Fra le architetture citiamo le ETA10, Cray 2, Cray C90, IBM 3090/600 VF, NEC SX-5. Sistemi a memoria distribuita: la memoria è distribuita fisicamente tra i processori (local memory), e tutte le memorie locali sono private e può accedervi solo il processore locale. La comunicazione tra i processori avviene tramite un protocollo di comunicazione a scambio di messaggi (message passing). In genere si tratta di sistemi che presentano un numero elevato di processori (da poche decine ad alcune migliaia), ma di potenza non troppo elevata, chiamati nodi di elaborazione. Il modello più utilizzato P M M P P M N P M M P Fig.12. Sistemi a memoria distribuita 6 P M P P M P P Fig.11. Sistemi a memoria condivisa è il Non Uniform Memory Access (NUMA), dove l insieme delle memorie locali forma uno spazio di indirizzi globale, accessibile da tutti i processori. Il tempo di accesso dal processore alla memoria non è uniforme, infatti, l accesso è più veloce se il processore accede alla propria memoria locale, mentre è più lento quando si accede alla memoria dei processori remoti e si ha un delay dovuto alla rete di interconnessione.

12 I moderni sistemi paralleli utilizzano memorie distribuite in cui nodi (SMP) sono costituiti da più processori (dual-core, quad-core, ecc.) e una memoria condivisa. Un altro fattore importante per il calcolo in parallelo sono le reti d interconnesione costituito dall insieme dei cavi che definiscono come i diversi processori di un calcolatore parallelo sono connessi tra loro e con le unità di memoria. Naturalmente il tempo richiesto per trasferire i dati dipende dal tipo di interconnessione e questo tempo prende il nome di communication time. La massima distanza che devono percorrere i dati scambiati tra due processori che comunicano incide sulle prestazioni della rete. Le caratteristiche di una rete di interconnessione sono: Bandwidth: identifica la quantità di dati che possono essere inviati per unità di tempo sulla rete, che deve essere massimizzata; Latency: identifica il tempo necessario per instradare un messaggio tra due processori. Si definisce anche come il tempo necessario per trasferire un messaggio di lunghezza nulla, e deve essere minimizzato. Possiamo inoltre definire l interconnesione, come: Interconnessione completa (ideale): ogni nodo può comunicare direttamente con tutti gli altri nodi (in parallelo), per esempio con n nodi si ha un'ampiezza di banda proporzionale a n 2 ed il costo cresce proporzionalmente a n 2 (Fig.13); Interconnessione indiretta (pratica): solo alcuni nodi sono connessi direttamente. Un percorso diretto o indiretto permette di raggiungere tutti i nodi. Il caso pessimo è costituito da un solo canale di comunicazione, condiviso da tutti i nodi (es. un cluster di workstation collegate da una LAN). Occorrono soluzioni intermedie in grado di bilanciare costi e prestazioni (mesh, albero, shuffleexchange, omega, ipercubo, ecc.). La connettività è più ristretta: soluzione appropriata perché molti algoritmi paralleli richiedono topologie di connessione più ristrette (locali), ad esempio la comunicazione tra primi vicini. Fra le interconnessioni indirette esistono varie topologie: Topologia Mesh: in una network a griglia, i nodi sono disposti secondo un reticolo a k dimensioni (k dimensional lattice) di ampiezza w, per un totale di w k nodi: se k=1 allora si parla di array lineare se k=2 si parla di 2D array La comunicazione diretta è consentita solo tra i nodi vicini (Fig.14), mentre i nodi interni comunicano direttamente con altri 2 k nodi. Topologia Toroidale: alcune varianti del modello a mesh presentano con- 7 Fig.13. Interconnessione completa

13 nessioni di tipo wrap-around fra i nodi ai bordi della mesh (Fig.15). Topologia Ipercubo: una topologia ipercubo (cubeconnected) è formata da n =2 k nodi connessi secondo i vertici di un cubo a k dimensioni. Ogni nodo è connesso direttamente a k altri nodi. Il degree di una topologia ipercubo è logaritmo di n ed anche il diametro è log n. Una network cube connected è una network butterfly le cui colonne sono collassate in nodi singoli. Topologia Tree: i processori sono i nodi terminali (foglie) di un albero. Il degree di una network con topologia ad albero con N nodi è log 2N e il diametro è 2log 2N - 2. Esistono due tipologie di tree: A. Fat Tree: la bandwidth della network au menta all aumentare del livello della rete (Fig.17a). B. Piramide: una network piramidale di ampiezza p è un albero quaternario completo con livelli, dove i nodi di ciascun livello sono collegati in una mesh 2D (Fig.17b). P P P P P P P P P Fig.14. Topologia Mesh 2D Fig.15. Topologia Toroidale Fig.16. Topologia Ipercubo Fig.17a. Topologia Fat Tree Fig.17b. Topologia Piramide 1.2 Architetture e modelli di programmazione parallela Cosa si intende per parallel computing o programmazione in parallelo? Il parallel computing è una tecnica di programmazione che coinvolge l utilizzo di più processori che operano insieme su un singolo problema. Il problema globale è suddiviso in parti, ciascuna delle quali viene eseguita da un diverso processore in parallelo. Inoltre un programma parallelo è composto di tasks (processi) 8

14 che comunicano tra loro per realizzare un obiettivo computazionale complessivo. L'esecuzione di processi di calcolo non sequenziali richiede: un calcolatore non sequenziale (in grado di eseguire un numero arbitrario di operazioni contemporaneamente); un linguaggio di programmazione che consenta di descrivere formalmente algoritmi non sequenziali. Inoltre, come già visto, un calcolatore parallelo è un sistema costituito da un insieme di processori in grado di comunicare e cooperare per risolvere grandi problemi computazionali in modo veloce. I calcolatori in parallelo nascono anche dall esigenza di evitare il von Neumann bottleneck, dove tutte le informazioni devono passare per il CPU serialmente. Un modello di programmazione è un insieme di astrazioni di programma che fornisce una visione semplificata e trasparente del sistema hardware e software nella sua globalità. I processori di un calcolatore parallelo comunicano tra loro secondo due schemi di comunicazione: & Shared memory: i processori comunicano accedendo a variabili condivise; & Message passing: i processori comunicano scambiandosi messaggi; Questi schemi identificano altrettanti paradigmi di programmazione parallela: $ paradigma a memoria condivisa o ad ambiente globale (Shared memory) dove i processi interagiscono esclusivamente operando su risorse comuni; $ paradigma a memoria locale o ad ambiente locale (Message passing) dove non esistono risorse comuni, i processi gestiscono solo informazioni locali e l'unica modalità di interazione è costituita dallo scambio di messaggi (message passing). Nella programmazione parallela occorre affrontare problematiche che non si presentano con la programmazione sequenziale. Occorre decidere: quali parti di codice costituiscono le sezioni parallele; quando iniziare l esecuzione delle diverse sezioni parallele; quando terminare l esecuzione delle sezioni parallele; quando e come effettuare la comunicazione fra le entità parallele; quando effettuare la sincronizzazione fra le entità parallele. Con il modello di programmazione Shared Memory, si fa affidamento sull indirizzamento globale della memoria, mentre con il modello a memoria distribuita è possibile solo la gestione locale della memoria, e quindi si può gestire solo uno spazio di indirizzamento locale. Ad esempio se volessimo calcolare la somma degli elementi di una matrice M[n, n], e cioè: s = i Se affrontassimo il problema affidandoci all indirizzamento globale della memoria dovremmo allocare la matrice M[n, n] nella memoria comune, e tutti i processori che intervengono nella computazione possono indirizzare tutti gli elementi di M (Fig.18). 9 j m ij

15 In contrapposizione un indirizzamento locale genera che ogni processore vede solo la sua memoria locale e vi alloca una fetta della matrice M[n, n] (Fig.19). P 0 s 0 P 0 M P 1 P 2 s 1 s 2 P 1 P 2 P 3 S s 0 s 1 s 2 s 3 s 3 S?? P 3 Fig.18. Schema di indirizzamento globale Ulteriormente possiamo schematizzare i paradigmi di programmazione in parallelo, così: Paradigma a memoria condivisa (Open-MP); Paradigma Message Passing (PVM, MPI); Paradigma Data Passing (Shmem, One Side Communication); Paradigma Data Parallel (HPF, HPF-Craft). Inoltre nell usare uno di questo schemi di programmazione possiamo tendere ad un parallelismo implicito, in cui il parallelismo non è visibile al programmatore, cioè è il compilatore il responsabile del parallelismo, ma in cui le perfomance non migliorano molto, oppure possiamo parlare di parallelismo esplicito, visibile al programmatore, in cui si adottano delle chiamate a librerie, e, in cui il miglioramento nelle perfomance è più vasto. Contemporaneamente possiamo adottare un parallelismo sui dati, in cui partizioniamo i dati (data parallelism), e ogni processo esegue lo stesso lavoro su un sottoinsieme dei dati. Le caratteristiche di questa tecnica sono: Il posizionamento dei dati ( data placement ) è critico; Più scalabile del parallelismo funzionale; Programmazione in Message-Passing o High Performance Fortran (HPF); Problema della gestione del contorno; Bilanciamento del carico. Oppure possiamo adottare un parallelismo sul controllo o funzionale, in cui vengono distribuite le funzioni e ogni processo esegue una diversa "funzione. In questo caso è fondamentale identificare le funzioni, e poi i data requirements. Infine tutti i linguaggi di programmazione parallela devono soddisfare dei requisiti fondamentali e devono possedere dei costrutti adatti, che sono: Costrutti per dichiarare entità parallele, cioè moduli di programma che 10 Fig.19. Schema di indirizzamento locale

16 devono essere eseguiti come processi sequenziali distinti, il che vuol dire che più processi possono svolgere lo stesso modulo di programma, operando su dati differenti; Costrutti per esprimere la concorrenza, cioè strumenti per specificare l'attivazione di un processo (quando deve iniziare l'esecuzione del modulo di programma che corrisponde a quel processo) e/o strumenti per specificare la terminazione di un processo; Costrutti per specificare le interazioni dinamiche fra processi; Costrutti linguistici per specificare la sincronizzazione e la comunicazione fra i processi che devono cooperare; Costrutti linguistici per garantire la mutua esclusione fra processi che competono (per il modello a memoria condivisa). Avendo tutti gli strumenti in mano per poter parallelizzare il nostro algoritmo, dobbiamo tenere a mente quali sono i nostri obiettivi e quali decisioni prendere, considerando che si deve: Assicurare lo speed-up e la scalabilità; Assegnare a ciascun processo una quantità unica di lavoro; Assegnare a ogni processo i dati necessari per il lavoro da svolgere; Minimizzare la replica dei dati e della computazione; Minimizzare la comunicazione tra i processi; Bilanciare il work load. Ed infine dobbiamo tenere ben in mente che per un problema esistono diverse soluzioni parallele, e che la miglior soluzione parallela non sempre deriva dalla miglior soluzione scalare. 1.3 Prospettive future In quest ultimo paragrafo vogliamo introdurre i progetti europei più importanti per la creazione l installazione di centri di calcolo HPC. Un progetto molto importane è DEISA, che è un'infrastruttura per il calcolo HPC distribuito, costituita dai principali centri di supercalcolo europei (CSC- Finlandia, CINECA-Italia, EPCC-Gran Bretagna, ECMWF-The European Centre for Medium-Range Weather Forecasts in cui sono coinvolti 31 stati europei, FZJ-Germania, IDRIS-Francia, RZG-Germania, SARA-Olanda, BSC-Spagna, HLRS-Germania, LRZ-Germania). L'infrastruttura, basata sul Grid Computing è sviluppata e mantenuta all'interno di uno speciale progetto finanziato dalla Comunità Europea. La missione di DEISA è di favorire la scoperta scientifica tramite un ampio spettro di strumenti scientifici e tecnologici, migliorando e rinforzando le capacità europee nell'area dell'hpc. A partire da maggio 2008 è stata lanciata una nuova iniziativa DEISA2. Questa iniziativa consiste nell identificazione, lo sviluppo e l attivazione di un numero molto piccolo di applicazioni di elevata rilevanza in tutte le aree della scienza e della tecnologia. I progetti selezionati devono avere la prerogativa di essere computazionalmente 11

17 complessi, non attivati presso DEISA, avere delle basi di innovazione potenziale, eccellenza e rilevanza scientifica. Tutti i progetti verranno poi valutati da u- na commissione scientifica formata da due paesi facenti parte al progetto DEI- SA2. Un altro progetto europeo è l HPC-Europa, che ha come obiettivo l'accesso transnazionale a sette infrastrutture di supercalcolo da parte dei ricercatori coinvolti in attività che necessitano di strumenti computazionali di alto livello. HPC-Europa si propone una maggiore integrazione fra le strutture di Supercalcolo a livello europeo e di contribuire alla creazione di un'area della ricerca europea, senza frontiere per la mobilità dei ricercatori, la conoscenza e le tecnologie innovative. Coinvolge BSC, CINECA, EPCC, HLRS, GENCI-Francia, SA- RA e CSC. Il progetto PRACE (Partnership for Advanced Computing in Europe) prevede di supportare l installazione di alcuni sistemi HPC di classe Pflop/s (Tier 0). Tali sistemi verranno poi integrati con i sistemi HPC presenti nelle singole nazioni; questi sistemi, che ci si aspetta essere dell ordine delle centinaia di Tflop/s, costituiscono il cosiddetto Tier 1 e a loro volta saranno integrati con sistemi HPC locali o regionali, meno potenti Tier 2, secondo un Fig.20. Installazione piramidale PRACE modello a piramide che definisce un preciso eco-sistema HPC a supporto della comunità scientifica europea. Il consorzio PRACE è costituito da istituti di ricerca di Austria, Finlandia, Francia, Germania, Grecia, Italia, Paesi Bassi, Norvegia, Polonia, Portogallo, Spagna, Svezia, Svizzera e Regno Unito. 12

18 2. Message Passing Interface (MPI) 2.1 Introduzione e sintassi essenziale MPI è il primo standard de iure per i linguaggi paralleli a scambio di messaggi, e definisce le specifiche sintattiche e semantiche, ma non l implementazione. E stato messo a punto in una serie di riunioni tenutesi tra novembre 1992 e gennaio La commissione MPI era costituita da membri provenienti da 40 i- stituti diversi (università, istituti di ricerca, industrie, enti governativi). Gli scopi per il quale è stato creato sono: Rendere portabile il software parallelo: Fornire agli sviluppatori di software un unico standard ben definito per la codifica di software libero; Fornire ai costruttori di architetture un unico insieme di primitive da implementare nel modo più efficiente per ciascuna architettura. Un programma MPI consiste di un programma seriale a cui si aggiungono delle chiamate a delle librerie che convertono il programma seriale in uno parallelo. Le chiamate possono essere principalmente divise in quattro classi: A. Chiamate usate per inizializzare, gestire e terminare le comunicazioni; B. Chiamate usate per comunicare tra coppie di processori (communication point to point); C. Chiamate usate per comunicare tra gruppi di processori (communication collective); D. Chiamate per creare data types. Ricordiamo che i linguaggi esistenti attualmente, cioè C, C++ e Fortran sono intrinsecamente seriali, e non concepiscono nei loro costrutti un programma in parallelo. Quando scriviamo un programma che deve essere implementato in parallelo, dobbiamo pensare in parallelo, tenendo bene a mente quali sono gli strumenti a nostra disposizione, piuttosto che fissare la nostra attenzione sulle librerie. Quando inizia un programma parallelo che contiene al suo interno alcune chiamate alle librerie MPI dobbiamo includere in testa al nostro programma l MPI header file: #include <mpi.h> (Sintassi del C); include mpif.h (Sintassi del Fortran) L header file contiene definizioni, macro e prototipi di funzioni necessarie per la compilazione di un programma MPI. La libreria MPI consiste di circa 125 funzioni, molte delle quali derivano dalla combinazione di un numero ridotto di concetti ortogonali, inoltre, molte di queste funzionalità possono essere ignorate fino a che non servono esplicitamente. Ci sono sei funzioni fondamentali che possono essere utilizzate per scrivere molti programmi paralleli, e sono: 13

19 MPI_INIT (Inizializza l ambiente MPI); MPI_COMM_SIZE (Determina quanti processi vi sono); MPI_COMM_RANK (Determina il numero rank del processo); MPI_SEND (Invia un messaggio); MPI_FINALIZE (Termina l ambiente MPI). Oltre a queste sei funzioni, ne esistono altre che possono aggiungere al programma: Flessibilità (tipi di dati); Efficienza (comunicazioni non bloccanti); Modularità (gruppi, comunicatori); Convenienza (operazioni/comunicazioni collettive, topologie virtuali). In MPI è possibile dividere il numero totale dei processi in gruppi, chiamati comunicatori. Il comunicatore è una variabile che identifica un gruppo di processi che hanno la facoltà di comunicare l uno con l altro. Il comunicatore che include tutti i processi è chiamato MPI_COMM_WORLD, che è anche il comunicatore automaticamente definito in default (Fig.21). Il programmatore può definire molti comunicatori allo stesso tempo, ed inoltre tutte le subroutine di comunicazione MPI hanno come Fig.21. MPI_COMM_WORLD argomento un comunicatore. La funzione MPI_INIT ha il compito di inizializzare l ambiente MPI, e deve seguire alcune regole: Deve essere chiamata prima di ogni altra funzione MPI; Non deve essere necessariamente la prima istruzione del programma; E la prima funzione che esegue tutti i processi; Esegue il setup del sistema che permette tutte le successive chiamate parallele; La sua sintassi è: MPI_Init(&argc, &argv) (C); MPI_INIT(IERR) INTEGER IERR (Fortran) La funzione MPI_FINALIZE finalizza l ambiente MPI, inoltre: E l ultima istruzione MPI; Viene chiamata da tutti i processi; Libera la memoria allocata da MPI; La sua sintassi è: MPI_Finalize() (C); CALL MPI_FINALIZE(IERR) (Fortran) La funzione MPI_COMM_SIZE determina quanti processi sono associati con 14

20 un comunicatore, e la sua sintassi è: MPI_Comm_size(MPI_Comm comm, int *size); INTEGER COMM, SIZE, IERR CALL MPI_COMM_SIZE(COMM, SIZE, IERR) Questa chiamata restituisce in output size, cioè il numero di processi associati a quel dato comunicatore. La funzione MPI_COMM_RANK identifica i processi all interno di un comunicatore e consente di conoscere l identificativo (ID) di un processore all interno di un gruppo; inoltre, può essere usata per trovare un rank non-global se i processi sono divisi in più comunicatori MPI. Il rank è un intero che identifica il processo all interno del comunicatore comm. Un processo può avere un diverso rank per ogni comunicatore a cui appartiene. La sintassi è: MPI_Comm_rank(MPI_Comm comm, int *rank); INTEGER COMM, RANK, IERR CALL MPI_COMM_RANK(COMM, RANK, IERR) A questo punto siamo in grado di scrivere il nostro primo programma in parallelo. Esempio: programma che stampa su terminale la parola Hello world, I m a proc X of total Y, e mette in coda queste stampe: #inlcude <stdlib.h> #include <stdio.h> #include "mpi.h" main(int argc, char** argv) { MPI_Init (&argc, &argv); int myrank; int mysize; MPI_Status status; MPI_Comm_rank( MPI_COMM_WORLD, &myrank); MPI_Comm_size( MPI_COMM_WORLD, &mysize); printf("hello world! I'm process %d of %d\n", myrank, mysize); MPI_Finalize(); } Tutte le librerie MPI utilizzano un comando che permette di richiamare le librerie e i path esatti per quelle librerie; così quando dobbiamo compilare il nostro programma dobbiamo usare i comandi: mpicc (C), mpicxx (C++); mpif77 (Fortran77), mpif90 (Fortran90) Quando si installa una libreria MPI, in automatico viene installato un program- 15

21 ma che permette di lanciare l eseguibile in parallelo, e questo è il suo comando: mpirun np <n. di processori> <nome dell eseguibile>; Questo programma una volta compilato ed eseguito scriverà sul terminale il seguente messaggio, ad esempio su quattro processori: Hello world! I m process 1 of 4 Hello world! I m process 2 of 4 Hello world! I m process 3 of 4 Hello world! I m process 4 of Comunicazioni point to point Prima di introdurre le funzioni usate da MPI per mettere in comunicazione più processori, analizziamo quali sono le caratteristiche del paradigma Message Passing, introdotto nel capitolo precedente. In questo paradigma ogni attore (processo) che partecipa alla comunicazione dispone di proprie risorse locali esclusive, a differenza del modello memoria condivisa. Ogni processo opera in un proprio ambiente (spazi degli indirizzi logici disgiunti) e la comunicazione avviene attraverso scambi di messaggi, che possono essere istruzioni, dati o segnali di sincronizzazione. Lo schema a scambi di messaggi può essere implementato anche su un sistema a memoria condivisa, anche se il delay della comunicazione causato dallo scambio di messaggi è molto più lungo di quello che si ha quando si accede a variabili condivise in una memoria comune. Nella Fig.22 è schematizzato il paradigma di Message Passing, che è il connubio fra il data transfer e la sincronizzazione, dove abbiamo messo in evidenza la richiesta di cooperazione tra il processo mittente e quello destinatario. Il sistema di comunicazione fra processi deve consentire fondamentalmente due o- perazioni: send(message) e receive(message), che consentano a due processi di comunicare tra loro. Le comunicazioni tra i processi possono essere di due tipi: > Simmetrica: in questo caso i nomi dei processi vengono direttamente Processo 0 Data Posso inviare? Ascolta... Data Processo 1 Ascolta... Si!!! Data Tempo Fig.22. Schematizzazione paradigma Message Passing inseriti nelle operazioni di send e receive, ad esempio: send(p1, message) invia un messaggio al processo P1 16

22 receive(p0, message) riceve un messaggio dal processo P0 > Asimmetrica: in questo caso il mittente nomina esplicitamente il destinatario, invece il mittente non indica il nome del processo con cui vuole comunicare, ad esempio: send(p, message) invia un messaggio al processo P receive(id, message) riceve un messaggio da un processo qualsiasi Questo tipo di comunicazione è adatta per collegamenti di tipo clientserver, e può avere vari schemi di collegamento: - da molti a uno; - da uno a molti; - da molti a molti. Quindi la sincronizzazione e la comunicazione fra i processi avviene tramite i costrutti send e receive, inoltre la semantica di queste due primitive relativamente alla sincronizzazione può avvenire in due modalità: Modalità bloccante: il processo che è mittente si blocca e attende che l operazione richiesta dalla primitiva send giunga a compimento; il processo ricevente rimane bloccato finché sul canale da cui vuole ricevere non viene inviato il messaggio richiesto. Modalità non bloccante: in questo caso la comunicazione è separata in tre fasi: I fase: Initiate non blocking communication; II fase: Do some work; III fase: Wait for non-blocking communication to complete; l operazione non attende il suo completamento, il processo passa ad eseguire l istruzione successiva; il processo che emette una send non bloccante non attende che il messaggio spedito sia andato a buon fine, ma passa ad eseguire le istruzioni successive. Altre primitive poi permettono di controllare lo stato del messaggio inviato; il processo che emette una receive non bloccante consente di verificare lo stato del canale e restituisce il messaggio oppure un flag che indica che il messaggio non è ancora arrivato. Vediamo adesso come le funzioni di MPI realizzano la comunicazione fra processi. Iniziamo a vedere come avviene la comunicazione fra 2 processi. Concettualmente è molto semplice, per e- sempio il processo sorgente A manda un messaggio al destinatario processo B, e B riceve il messaggio da A. Naturalmente la comunicazione può avvenire all interno di un comunicatore, e la sorgente e il destinatario sono Fig.23. Schema di comunicazione point to point MPI 17

23 identificati dal loro rank nel comunicatore (Fig.23). Ma cosa sono i messaggi? Un messaggio è un array di elementi composto da un qualche data type MPI, ed è per questo motivo che generalmente bisogna dare ad ogni routine MPI il tipo di dato che bisogna passare. Questo permette ai programmi MPI di essere eseguiti in maniera automatica in ambienti eterogenei. Inoltre un messaggio deve contenere un certo numero di elementi di quel data type. MPI definisce un numero di costanti che corrispondono ai data types nei linguaggi C e Fortran. Quando una routine MPI è chiamata, il data type Fortran (o C) del dato che sta per passare deve incontrare la corrispondente costante intera MPI, ricordando che i tipi di C sono differenti da quelli Fortran. Gli MPI data types possono essere divisi in: Basic types; Derived types: questi possono essere costruiti a partire dai basic types; I data types definiti dall utente permettono ad MPI di allargare e restringere i dati da e verso buffer non contigui. Ogni messaggio è identificato dal suo Fig.24. Struttura di un messaggio envelope (Fig.24), e può essere ricevuto solo se il ricevente specifica il corretto envelope. Nella tabella 1 possiamo vedere quali sono i basic data types MPI corrispondenti al linguaggio Fortran. MPI Data type Fortran Data type MPI_INTEGER INTEGER MPI_REAL REAL MPI_DOUBLE_PRECISION DOUBLE PRECISION MPI_COMPLEX COMPLEX MPI_DOUBLE_COMPLEX DOUBLE COMPLEX MPI_LOGICAL LOGICAL MPI_CHARACTER CHARACTER(1) MPI_PACKED MPI_BYTE Tabella 1. Fortran - MPI basic data types 18

24 Nella tabella 2 possiamo vedere quali sono i basic data types MPI corrispondenti al linguaggio C. MPI Data type MPI_CHAR MPI_SHORT MPI_INT MPI_LONG MPI_UNSIGNED_CHAR MPI_UNSIGNED_SHORT MPI_UNSIGNED MPI_UNSIGNED_LONG MPI_FLOAT MPI_DOUBLE MPI_LONG_DOUBLE MPI_BYTE MPI_PACKED Tabella 2. C - MPI basic data types L ottica della comunicazione si divide in: Ottica globale, che può essere: A. Sincrona: il mittente sa se il messaggio è arrivato o meno; B. Asicrona: il mittente non sa se il messaggio è arrivato o meno; Ottica locale legata al buffer di trasmissione, e può essere: A. Bloccante: restituisce il controllo al processo che ha invocato la primitiva di comunicazione solo quando la primitiva di comunicazione è stata completata, cioè il buffer di uscita è stato svuotato. Il concetto di bloccante è diverso da quello di sincrona; B. Non bloccante: restituisce il controllo al processo che ha invocato la primitiva di comunicazione quando la primitiva di comunicazione è stata eseguita, senza controllo sull effettivo completamento, eventualmente da poter effettuare in seguito. Il processo invocante può nel frattempo passare ad eseguire altre operazioni. In MPI vi sono diverse combinazioni possibili tra SEND/RECEIVE sincrone e asincrone, bloccanti e non bloccanti. Cosa vuol dire completare o completamento di un comunicazione? Possiamo anche in questo caso separare un completamento locale da uno globale, e diremo, che: Una comunicazione è completata localmente su di un processo se il processo ha completato tutta la sua parte di operazioni relative alla comunicazione fino allo 19 C Data type signed char signed short int signed int signed long int unsigned char unsigned short int unsigned int unsigned long int float double long double

25 svuotamento del buffer di uscita. Dal punto di vista dell esecuzione del programma, completare localmente una comunicazione significa che il processo può eseguire l istruzione successiva alla SEND o RECEIVE, possibilmente un altra SEND. Una comunicazione è completata globalmente se tutti i processi coinvolti hanno completato tutte le rispettive operazioni relative alla comunicazione, inoltre è completata globalmente se e solo se è completata localmente su tutti i processi coinvolti. Come abbiamo già detto in precedenza le due primitive possono essere bloccanti e non bloccanti, nel caso della libreria MPI significa: SEND non bloccante: questa funzione ritorna immediatamente, e il buffer del messaggio non deve essere sovrascritto subito dopo il ritorno al processo chiamante, ma si deve controllare che la SEND sia completata localmente; SEND bloccante: questa funzione ritorna quando la SEND è completata localmente, e il buffer del messaggio può essere sovrascritto subito dopo il ritorno al processo chiamante; RECEIVE non bloccante: ritorna immediatamente, e il buffer del messaggio non deve essere letto subito dopo il ritorno al processo chiamante, ma si deve controllare che la RECEIVE sia completata localmente; RECEIVE bloccante: ritorna quando la RECEIVE è completata localmente, e il buffer del messaggio può essere letto subito dopo il ritorno. Inoltre, la modalità di comunicazione point to point deve specificare quando un operazione di SEND può iniziare a trasmettere e quando può ritenersi completata. La libreria MPI prevede quattro modalità, cioè: Modalità sincrona: la SEND può iniziare a trasmettere anche se la RE- CEIVE corrispondente non è iniziata. Tuttavia, la SEND è completata solo quando si ha garanzia che il processo destinatario ha eseguito e completato la RECEIVE; Modalità buffered: simile alla modalità sincrona per l inizio della SEND. Tuttavia, il completamento è sempre indipendente dall esecuzione della RECEIVE; Modalità standard: la SEND può iniziare a trasmettere anche se la RE- CEIVE corrispondente non è iniziata. La semantica del completamento è sincrona o buffered; Modalità ready: la SEND può iniziare a trasmettere assumendo che la corrispondente RECEIVE sia iniziata. Riassumendo il tutto, l operazione di SEND possiede quattro modalità di comunicazione (sincrona, standard, buffered, ready) e due modalità di blocking (bloccante, non bloccante), mentre l operazione di RECEIVE ha una modalità di comunicazione (standard) e le stesse modalità bloccanti della SEND. Inoltre una qualsiasi operazione di RECEIVE può essere utilizzata per ricevere mes- 20

26 saggi da una qualsiasi SEND. In questa relazione ci occuperemo esclusivamente di SEND e RECEIVE standard, lasciando al lettore ulteriori approfondimenti per quanto riguarda le altre modalità. Iniziamo a descrivere la sintassi di queste due funzioni, partendo dalla modalità bloccante per poi passare a quella non bloccante. La sintassi di queste due funzioni è: int MPI_Send (void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm); int MPI_Recv (void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Status *status); MPI_SEND (buf, count, type, dest, tag, comm, ierr) MPI_RECV (buf, count, type, dest, tag, comm, status, ierr) Spieghiamo cosa contengono queste funzioni. Innanzitutto possiamo separare le variabili presenti all interno della parentesi, seguendo lo schema visto in Fig.24, in message body (buf, count, type) ed envelope (dest, tag, comm). Il termine buf indica dove inserire il messaggio ricevuto o inviato. Count, che deve essere un intero, indica il numero di elementi presenti nel buf che devo inviare. Type è il tipo di variabile presente nel buf da inviare, fra quelli presenti nelle tabelle 1 e 2, ed è questo parametro che determina quanta memoria allocare. Dest, che deve essere un numero intero, indica il rank del processo destinatario. Tag, anch esso un intero, identifica il numero del messaggio. Comm identifica il comunicatore dei mittenti e dei destinatari. Status è un array di grandezza MPI_STATUS_SIZE che contiene le informazioni sullo stato della comunicazione, e può essere di tre tipi: status.mpi_source: contiene il rank del mittente; status.mpi_tag: contiene il tag del messaggio; status.mpi_get_count: contiene il numero di item ricevuti. La sintassi per queste tre funzioni è: status.mpi_source; status.mpi_tag; int MPI_Get_Count (MPI_Status status, MPI_Datatype datatype, int *count); status (MPI_SOURCE) status (MPI_TAG) MPI_GET_COUNT (status, datatype, count, ierror) INTEGER status (mpi_status_size), datatype, count, ierror Sia in Fortran che in C la funzione RECV accetta delle wildcard per ricevere da ogni sorgente (MPI_ANY_SOURCE) e da ogni tag (MPI_ANY_TAG), seguendo l ordine con cui le varie sorgenti vengono chiamate all interno del programma. Per una comunicazione che avvenga con successo bisogna rispettare delle regole, cioè: I. Il mittente deve specificare un rank per il destinatario valido; II. Il destinatario deve specificare un rank per il mittente valido; III. Devono avere lo stesso comunicatore; IV. I tag devono coincidere; 21

27 V. Il tipo di messaggio deve coincidere; VI. Il buffer del ricevitore deve essere abbastanza grande da contenere per intero il messaggio. Dovrebbe essere una volta e mezzo più grande del buffer del mittente. Facciamo un esempio in cui utilizziamo le funzioni SEND e RECEIVE non bloccanti. Scriviamo un programma in C in cui il processo 0 invia il proprio rank al processo 1, e il processo 1 invia il proprio rank al processo 0, ed infine ciascun processo stampa su terminale il proprio rank e quello ricevuto: #include <stdio.h> #include<stdlib.h> #include "mpi.h" main(int argc, char** argv) { MPI_Init (&argc, &argv); int myrank; int mysize; int yourrank; MPI_Status status; MPI_Comm_rank( MPI_COMM_WORLD, &myrank); MPI_Comm_size( MPI_COMM_WORLD, &mysize); if (mysize!=2) { if (myrank==0) printf("this program need exactly 2 processors! \n"); return 1; } if (myrank==0) { int yourrank; MPI_Send(&myrank, 1, MPI_INTEGER, 1, 0, MPI_COMM_WORLD); MPI_Recv(&yourrank, 1, MPI_INTEGER, 1, 1, MPI_COMM_WORLD,& status); printf("hello I'M PROCESS %d AND I HAVE RECEIVED RANK %d \n", myrank, yourrank); } else { MPI_Recv(&yourrank, 1, MPI_INTEGER, 0, 0, MPI_COMM_WORLD,& 22

28 status); MPI_Send(&myrank, 1, MPI_INTEGER, 0, 1, MPI_COMM_WORLD); printf("hello I'M PROCESS %d AND I HAVE RECEIVED RANK %d \n", myrank, yourrank); } MPI_Finalize(); } Questo programma scriverà sul terminale: HELLO I'M PROCESS 0 AND I HAVE RECEIVED RANK 1 HELLO I'M PROCESS 1 AND I HAVE RECEIVED RANK 0 Un problema legato agli scambi dei messaggi è il Deadlock (Fig.25) che avviene quando due processi sono bloccati ed ognuno sta aspettando l altro P 0 a = 100; send (&a, 1, 1); a = 0; modifico il valore di a uno solo invio il dato contenuto nel buffer a al proceso processo 11 P 1 receive (&a, 1, 0); printf ( %d\n, a); Fig.26. Esempio di sovrapposizione di dati per andare avanti. Inoltre come abbiamo visto in precedenza la funzione SEND esce dal programma una volta che ha copiato per intero i propri dati nella memoria dell altro processo, a prescindere dal fatto che una RECEIVE sia stata chiamata. Vogliamo illustrare attraverso un esempio un problema che poteva accadere nel programma precedente. Nella Fig.26 schematizziamo un esempio di possibile problema: il processo 0 invia il dato di una variabile al processo 1, ma prima che il processo 0 riceva questa variabile, all interno del programma il valore di questa variabile cambia. Quale valore riceve il buffer destinatario? La semantica dell operazione di send richiede che il valore ricevuto da P 1 sia Fig.25. Deadlock uno solo memorizzo il dato ricevuto in a ricevuto dal processo 0

29 Tuttavia se la piattaforma hardware supporta l accesso diretto alla memoria, cioè il dato viene copiato da una memoria all altra, e il trasferimento asincrono dei messaggi, il processo P 1 potrebbe ricevere il valore 0 invece di 100. L operazione di SEND deve bloccare fino a quando la semantica dell operazione non è garantita. Se la SEND sblocca, cioè permette l esecuzione del resto del programma prima che P 1 abbia ricevuto il dato, P 1 può ricevere il dato sbagliato. E per questo motivo che abbiamo usato in precedenza una SEND bloccante, in cui l operazione di send non termina finché il processo ricevente non ha avuto il messaggio, vi è un handshake tra il processo mittente e destinatario che permette l inizio dell operazione di trasferimento. Ma supponiamo che l operazione di RECEIVE sia all interno del programma molto lontana dall operazione di SEND, e che quindi il programma resti bloccato per molto tempo prima di svolgere tutte le funzioni successive alla SEND. In questo caso il processo di comunicazione diventa obsoleto, e il tempo impiegato per la comunicazione diventa maggiore del tempo di calcolo. In molte implementazioni MPI i dati da inviare sono copiati in un buffer interno, in maniera tale che quando il processo mittente deve eseguire una SEND mette il messaggio nel buffer e termina dopo che la copia nel buffer è completata, e può continuare con le altre operazioni. A questo punto i dati trasferiti vengono memorizzati in un buffer del processo ricevente. Quando il processo destinatario incontra un operazione di RECEIVE verifica che i dati siano nel suo buffer. In questo modo riusciamo a velocizzare di molto le operazioni, ma, purtroppo, la grandezza di questo buffer è circa 2MB, quindi se inviamo, ad esempio un vettore o una matrice più grandi di 2MB, corriamo il rischio di non inviare niente e di mandare il programma in hang. In questo caso ci corrono in aiuto le funzioni SEND e RECEIVE non bloccanti. Le comunicazioni non bloccanti permettono la separazione tra l inizio della comunicazione e il completamento, cioè terminano prima che sia assicurata la loro correttezza semantica. Il vantaggio principale è legato al fatto che il programma può fare altro a livello computazionale mentre effettua la comunicazione, cioè possiamo costruire un overlapping fra la comunicazione e il calcolo. Lo svantaggio principale è legato al fatto che il programmatore deve inserire dei codici aggiuntivi che indichino se la semantica di un trasferimento precedente è stata violata o non violata, e il controllo avviene in una fase successiva. La sintassi di queste due funzioni è: int MPI_Isend (void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *req); int MPI_Irecv (void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *req); MPI_ISEND (buf, count, type, dest, tag, comm, req ierr) MPI_IRECV (buf, count, type, dest, tag, comm, req, ierr) Req è una variabile intera, e identifica quale comunicazione sta avvenendo. Se usiamo queste due funzioni ci assicuriamo un miglioramento nelle performance, ma abbiamo perso il controllo sulla comunicazione. Per questo motivo, as- 24

30 sociate a queste due funzioni, esistono due ulteriori primitive che hanno il compito di controllare se la SEND ha finito di inviare e se la RECEIVE ha ricevuto quello che la SEND ha inviato. La sintassi di queste due nuove funzioni è: int MPI_Wait (MPI_Request *req, MPI_Status *status); MPI_WAIT (req, status, ierr) Req abbiamo già visto cosa sia, e deve essere iniziato da una SEND o da una RECEIVE. Anche status sappiamo già cosa sia, e se req è stato associato ad u- na RECEIVE, allora status deve contenere le informazioni sui messaggi ricevuti, altrimenti status può contenere un errore. La sintassi dell altra funzione è: int MPI_Test (MPI_Request *req, int *flag, MPI_Status *status); MPI_TEST (req, flag, status, ierr) Flag è una variabile logica che restituisce il valore vero se la comunicazione req è completata, altrimenti restituisce falso. Vediamo un esempio di comunicazione con funzioni non bloccanti, in cui aumentiamo la dimensione del messaggio fino al punto in cui se utilizzassimo primitive bloccanti il nostro programma andrebbe in hang. Il programma è simile a quello precedente solo che in questo caso la comunicazione fra i due processi è incrociata, e cioè il processo 0 invia al processo 1, e contemporaneamente deve ricevere dal processo 1: #include "stdlib.h" #include "stdio.h" #include "mpi.h" main(int argc, char** argv) { MPI_Init (&argc, &argv); int myrank; int mysize; int Y = 30000; int * message_to_send; int * message_to_recv; MPI_Status status; MPI_Request req1, req2; MPI_Comm_rank( MPI_COMM_WORLD, &myrank); MPI_Comm_size( MPI_COMM_WORLD, &mysize); if (mysize!=2) { if (myrank==0) printf("this program need exactly 2 processors! \n"); return 1; } 25

31 for (int i = 1; i <= Y; i++) { message_to_send = (int *) malloc(i* sizeof(int)); message_to_recv = (int *) malloc(i* sizeof(int)); if (myrank==0) { MPI_Isend(message_to_send, i, MPI_INTEGER, 1, 0, MPI_COMM_WORLD, &req1); MPI_Irecv(message_to_send, i, MPI_INTEGER, 1, 1, MPI_COMM_WORLD, &req2); MPI_Wait(&req2, &status); MPI_Wait(&req1, &status); printf("hello I'M PROCESS %d AND I HAVE RECEIVED RANK %d \n", myrank, i); } else { MPI_Isend(message_to_send, i, MPI_INTEGER, 0, 1, MPI_COMM_WORLD, &req1); MPI_Irecv(message_to_send, i, MPI_INTEGER, 0, 0, MPI_COMM_WORLD, &req2); MPI_Wait(&req1, &status); MPI_Wait(&req2, &status); printf("hello I'M PROCESS %d AND I HAVE RECEIVED RANK %d \n", myrank, i);} free (message_to_send); free (message_to_recv); } MPI_Finalize(); } Questo programma stamperà su terminale per volte il messaggio: HELLO I'M PROCESS 0 AND I HAVE RECEIVED RANK 1 HELLO I'M PROCESS 1 AND I HAVE RECEIVED RANK 0 In questo caso il calcolo parallelo consiste di un numero di processi, ognuno dei quali lavora solo sui dati locali, ed ogni processo ha delle variabili puramente locali, cioè non ha accesso alla memoria remota e la condivisione dei dati è sostituita dallo scambio dei messaggi 2.3 Comunicazioni collettive Le comunicazioni collettive permettono di scambiare messaggi fra gruppi di processi, e devono essere chiamate da tutti i processi che appartengono a quel comunicatore, che specifica quali processi sono coinvolti nella comunicazione. 26

32 Le caratteristiche principali delle comunicazioni collettive sono: Non interferiscono con le comunicazioni point to point e viceversa; Tutti i processi devono chiamare la routine collettiva; Non esistono comunicazioni collettive non bloccanti; Non esistono tag; I buffer delle RECEIVE devono essere della giusta grandezza. MPI possiede cinque tipi di comunicazione collettive (Fig.27), e sono: A. One-to-Many (multicast); B. One-to-All (broadcast); C. Many(All)-to-One (gather); D. Many-to-Many; E. All-to-All. process data P 0 P 1 A One-to-All (broadcast) A A P 2 A P 3 A P 0 A A B C D P 1 B Many-to-One (gatter) (gather) P 2 P 3 C D One-to-Many (scatter) P 0 A A B C D P 1 B Many-to-Many(allgatter) (allgather) A B C D P 2 C A B C D P 3 D A B C D P 0 P 1 P 2 P 3 A A A A B B B B C C C C D D D D All-to-All Fig.27. Tipi di comunicazione 27 A B C D A B C D A B C D A B C D

33 Nella Tabella 3 possiamo trovare le principali funzioni MPI che permettono la comunicazione collettiva in tutte le sue forme: Funzione MPI_BCAST MPI_SCATTER MPI_GATHER MPI_ALLGATHER MPI_REDUCE MPI_ALLREDUCE MPI_BARRIER Tabella 3. Principali funzioni MPI per le comunicazioni collettive La sintassi della funzione MPI_BCAST è: int MPI_Bcast (void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm); INTEGER count, type, root, comm, ierr CALL MPI_BCAST (buf, count, type, root, comm, ierr) Root è il rank del processore che esegue il broadcast. Tutti i processi devono specificare la stessa root, rank e comm. La sintassi della funzione MPI_SCATTER è: int MPI_Scatter (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, int root, MPI_Comm comm) INTEGER sendcount, recvcount, root, comm, ierr CALL MPI_SCATTER (sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm, ierr) Sendbuf è l indirizzo del dato inviato, sendcounts è il numero di elementi inviati ad ogni processo che devono essere moltiplicati per il numero di processi nel comunicatore, sendtype il tipo di dato inviato, recvbuf l indirizzo del dato ricevuto, recvcount il numero di elementi ricevuti, recvtype è il tipo di dato ricevuto, root il processore che esegue l operazione. Esiste una versione alternativa di MPI_SCATTER ed è la funzione MPI_SCATTERV, in cui i messaggi individuali vengono distribuiti dal root ad ogni processo nel comunicatore, e la dimensione dei messaggi può essere differente. Tutte le routines il cui nome termina con v consentono di avere grossi tronconi di dati di dimensione diversa, dove l argomento della chiamata è un vettore e non uno scalare. La sintassi è 28 Operazione Un processore spedisce dati ad altri processi appartenenti ad un gruppo. Il processore root comunica i dati a tutti i processi appartenenti ad un gruppo. Vengono comunicati ad uno o a tutti i processi appartenenti ad un gruppo i dati posseduti da diversi processi. Il risultato di una operazione eseguita sui dati posseduti da diversi processi viene comunicata ad uno o a tutti i processi appartenenti ad un gruppo. L esecuzione di ogni processore appartenente ad un gruppo viene messa in pausa fino a che tutti i processi di quel gruppo non sono giunti a questa istruzione.

34 praticamente uguale alla funzione MPI_SCATTER, solo che dopo int *sendcount, bisogna inserire la variabile int *displs, che è un vettore di interi di lunghezza pari alla dimensione del gruppo che contiene i displacement nell array. La funzione MPI_GATHER trasmette da tutti i processi appartenenti ad un comunicatore ad un singolo processo denominato ricevente. La sintassi di questa funzione è: int MPI_Gather (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, int root, MPI_Comm comm); INTEGER sendcount, recvcount, root, comm, ierr CALL MPI_GATHER (sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm, ierr) Anche per la funzione MPI_GATHER esiste la funzione MPI_GATHERV, e si fanno le stessa considerazioni viste già per la funzione MPI_SCATTER solo che stavolta i messaggi hanno senso invertito. Esiste inoltre la funzione MPI_ALLGATHER in cui semplicemente sparisce il processo ricevente poichè tutti i processi del comunicatore ricevono il messaggio. La funzione MPI_REDUCE agisce con una particolare operazione su dati appartenenti a differenti processi per consegnarne il risultato finale ad un particolare processo (a tutti i processi nel caso della funzione MPI_ALLREDUCE), inoltre permette di: Collegare dati da ogni processo; Ridurre i dati ad un singolo valore; Depositare il risultato sui processi root; Depositare il risultato su tutti i processi; Overlapping della comunicazione e del calcolo. La sintassi di questa funzione è: int MPI_Reduce (void *sendbuf, int count, MPI_Datatype type, void *recvbuf, MPI_Op op, int root, MPI_Comm comm); INTEGER root, comm, ierr CALL MPI_GATHER (sendbuf, type, recvbuf, root, comm, ierr) Op si riferisce alla particolare operazione (appendice 2) che il processo ricevente deve eseguire sui dati a lui comunicati. Nella MPI_ALLREDUCE manca il root, poiché i risultati sono immagazzinati su tutti i processi. La funzione MPI_BARRIER (Fig.28) blocca tutti i processi appartenenti ad un gruppo fino a che tutti i processi che appartengono a questo gruppo hanno chiamato questa funzione. MPI_BARRIER viene quindi usata per sincronizzare tutti i processi appartenenti ad un Fig.28. Esempio funzione MPI_BARRIER 29

35 particolare gruppo identificato dal comunicatore presente nella chiamata. La sintassi di questa funzione è: int MPI_Barrier (MPI_Comm comm); INTEGER comm, ierr CALL MPI_GATHER (comm, ierr) L ultima funzione collettiva di cui ci occupiamo è MPI_ALLTOALL, in cui tutti i processi inviano a tutti i processi e la sua sintassi è: int MPI_Alltoall (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Comm comm); INTEGER sendcount, recvcount, comm, ierr CALL MPI_ALLTOALL (sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm, ierr) Questa funzione è particolarmente utile quando vogliamo trasporre i dati. Un esempio in cui usiamo le funzioni collettive e risparmiamo molto tempo per le comunicazioni è il prodotto matrice per vettore, in questo caso vediamo un e- sempio scritto in Fortran90: program pmv implicit none include 'mpif.h' integer, dimension (MPI_STATUS_SIZE) :: STATUS integer :: IE,RANGO,NP,N,BS,I,J real, dimension(:,:), allocatable :: A,B real, dimension(:), allocatable :: X,Y,Z real :: c! Inizializziamo le routine MPI call MPI_INIT (IE) call MPI_COMM_RANK (MPI_COMM_WORLD, RANGO, IE) call MPI_COMM_SIZE (MPI_COMM_WORLD, NP, IE)! Indicizziamo e allochiamo in memoria la matrice if(rango.eq.0) then write(*,*) 'dai l'ordine della matrice A' read(*,*) N if(np*(n/np).ne.n) goto 10 BS=N/NP allocate (A(N,N), X(N), Y(N), B(N,BS), Z(BS)) call random_number(a) call random_number(x) A=int(100*A) X=int(100*X) write(*,*) (DOT_PRODUCT(A(I,1:N),X),I=1,N)! Viene trasposta la matrice A do I=1,N do J=1,I-1 30

36 C=A(I,J) A(I,J)=A(J,I) A(J,I)=C end do end do endif! Chiamiamo la funzione MPI che invia BS a tutti i processori del gruppo call MPI_BCAST (BS, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, IE) if (RANGO.ne.0) then N=BS*NP allocate (B(N, BS), X(N), Z(BS)) endif! Allochiamo lo spazio per il vettore X(N) su tutti i processori del gruppo call MPI_BCAST (X, N, MPI_REAL, 0, MPI_COMM_WORLD, IE)! Inviamo gli elementi del vettore dal root ai processori del gruppo call MPI_SCATTER (A, BS*N, MPI_REAL, B, BS*N, MPI_REAL, 0, MPI_COMM_WORLD, IE) do i=1,bs Z(I)=DOT_PRODUCT(B(1:N,I),X) end do! Inviamo i nuovi elementi del vettore da tutti i processori al root call MPI_GATHER (Z, BS, MPI_REAL, Y,BS, MPI_REAL, 0, MPI_COMM_WORLD, IE) if (RANGO.eq.0) then Write(*,*) Y(1:N) endif 10 call MPI_FINALIZE (IE) end 2.4 Ottimizzazione dei codici Quando affrontiamo un problema computazionale si analizza il problema e si fanno, per prima cosa, delle scelte architetturali che condizionano il resto della vita del progetto. Queste scelte architetturali si esprimono, successivamente, attraverso il design dell applicazione parallela. Nella fase di design, le opzioni di implementazione alternative vengono confrontate e vengono scelte quelle che sono stimate essere le più convenienti in base alla perfomance, alla flessibilità, alla semplicità di implementazione, ecc. E onere del programmatore: A. Identificare il potenziale parallelismo ; B. Distribuire i dati; C. Gestire le comunicazioni e la sincronizzazione tra i task paralleli. Per prima cosa quindi dobbiamo identificare gli hotspot dell applicazione: 31

37 Generalmente nelle applicazioni tecniche-scientifiche la maggior parte del tempo di calcolo è speso in poche sezioni di codice (hotspot), e spesso sono dei loop. In secondo luogo dobbiamo analizzare il grado di parallelismo degli hotspot: Se l hotspot consiste in uno o più loop con iterazioni strettamente indipendenti, il grado di parallelismo è massimo; Se esiste una dipendenza di qualche tipo tra le varie iterazioni del loop, potrebbe essere ancora possibile parallelizzare il loop trattando in modo specifico le dipendenze (sincronizzazione e comunicazione tra processi; Qualora la dipendenza tra le iterazioni del loop precluda il parallelismo sarà necessario valutare algoritmi alternativi, più paralleli o tenersi la versione seriale! L identificazione del parallelismo è legata alla stima e all ottimizzazione del bilanciamento del carico tra i processi: L efficienza computazionale di un applicazione parallela dipende dal tempo impiegato dal task più lento; Se la quantità di lavoro che devono svolgere i processi è sistematicamente squilibrata, uno o più task saranno significativamente più lenti degli altri, riducendo l efficienza dell applicazione; In quest ultimo caso si dovrà disegnare un algoritmo di bilanciamento del carico. Per quanto riguarda la distribuzione dei dati, dobbiamo: Decidere come decomporre il problema (almeno inizialmente) secondo un criterio di parallelizzazione degli hotspot, ignorando le sezioni del programma poco CPU intensive; Distribuire i dati tra i vari processi come richiesto dall algoritmo parallelo, cercando di ottimizzare l algoritmo affinché si accedano preferibilmente dati locali al processo, cioè ridurre la comunicazione. Infine, per quanto riguarda il design delle applicazioni parallele dobbiamo decomporre il problema ed esistono due tipi di decomposizione, domain decomposition: I dati da elaborare (il dominio) sono divisi in porzioni omogenee; Ogni porzione è mappata su un processore diverso; Ogni processore lavora solo sulla porzione di dati assegnata. Se necessario, i processori comunicano periodicamente per scambiare dati; Questa strategia di decomposizione del problema è particolarmente indicata nei casi in cui il set di dati da elaborare è statico e le operazioni da compiere locali. La seconda è functional decomposition: 32

38 Quando il problema consiste di un set di operazioni distinte ed indipendenti che possono essere svolte parallelamente, possiamo assegnare ad o- gni processo la responsabilità di svolgere una di queste operazioni; Solitamente, al termine del calcolo delle varie operazioni, un processo riprende il controllo dell esecuzione e svolge la restante parte (seriale) del codice: master-slave. Naturalmente l invio di messaggi e la sincronizzazione introducono nel programma parallelo un costo computazionale assente nel caso seriale, che prende il nome di overhead parallelo o overhead di comunicazione. Quando si pianifica il pattern di comunicazione tra task, e quando si disegnano in dettaglio le comunicazioni, ci sono diversi fattori da tenere in considerazione, in particolare: Latency e bandwidth di comunicazione; Sincronizzazione e modalità di comunicazione. La latency è il tempo necessario per lo scambio di un messaggio di dimensioni minime (0 byte) tra due processi, ma è anche il tempo necessario per attivare la comunicazione tra due processi. Un valore tipico di latency è 1-5 μs. La bandwidth è la quantità di dati che possono essere comunicati nell unità di tempo. Un valore tipico di bandwidth è 1-2 GB/s. Si può facilmente comprendere che inviare molti piccoli messaggi può comportare un overhead di comunicazione dovuto alla latency. Un altro problema da ottimizzare è la sincronizzazione che in molti casi, esplicitamente o implicitamente, è richiesta dalle operazioni di comunicazione. La sincronizzazione induce un ulteriore overhead perché prima di procedere sarà necessario aspettare che il task più lento giunga all istruzione di sincronizzazione. Per questo motivo bisogna scegliere la modalità giusta di comunicazione per il problema dato in maniera tale da minimizzare l overhead di comunicazione. Le comunicazioni, come già visto, possono essere sincrone: Richiedono un qualche tipo di sincronizzazione tra i task che condividono dati e tale operazione implica un overhead; Sono più semplici da programmare e più sicure. Oppure asincrone: Consentono ad un task di trasferire dati, indipendentemente dallo stato del task che li deve ricevere; Sono più complesse da programmare. La possibilità di sovrapporre il calcolo con la comunicazione è l unico vero vantaggio nell utilizzo di comunicazioni asincrone. Un altro problema della sincronizzazione è legato al fatto, che, se la quantità di lavoro svolta dai vari processi è sbilanciata, alcuni raggiungono il punto di sincronizzazione in anticipo e debbono attendere gli altri (load imbalance). Per questo motivo bilanciare il carico di lavoro tra i task significa minimizzare il tempo in cui ogni processo non svolge lavoro (idle time), ottimizzando così le prestazioni. Certe classi di problemi consentono di dividere in modo omogeneo il lavoro fra i processi, attraverso una distribuzione omogenea delle strutture 33

39 dati tra i processi. Altre classi di problemi non consentono di ottenere un bilanciamento omogeneo in modo semplice, e sono: Loop triangolari; Problemi con array sparsi; Metodi con griglie adattive. Gli schemi di comunicazione, sincronizzazione e load balancing debbono essere ottimizzati globalmente per ottenere le massime performance parallele, cioè: min (comunicazione/sincronizzazione + sbilanciamento) Questa formula indica il modus operandi che un programmatore dovrebbe tenere a mente nel costruire il proprio algoritmo, cioè, cercare di ridurre al minimo il rapporto tra comunicazione e sincronizzazione sommato agli sbilanciamento, che rappresentano gli sbilanciamenti che si generano quando parallelizziamo un codice dovuto ai differenti carichi di lavoro distribuiti sui processori. In alcuni casi, minimizzare il costo della comunicazione e sincronizzazione richiede scelte in contrasto con quelle che permetterebbero la minimizzazione dello sbilanciamento, e perciò possiamo minimizzare solo uno dei due elementi presenti nella somma, generando due differenti modi di parallelizzare : parallelismo fine grain: in questo caso minimizziamo lo sbilanciamento aumentando le fasi di sincronizzazione e comunicazione per la distribuzione di nuovi quanti di lavoro; parallelismo coarse grain: minimizziamo il rapporto tra comunicazione e sincronizzazione generando solo pochi messaggi grandi. La granularità ottimale dipende sia dall applicazione che dal hardware a disposizione, e può accadere che: Quando l algoritmo parallelo implica un forte sbilanciamento e la latenza dell interconnessione di rete è bassa, la soluzione migliore sarà un parallelismo fine grain. Quando l algoritmo parallelo è naturalmente bilanciato la soluzione migliore sarà un parallelismo coarse grain. Quando l algoritmo parallelo implica un forte sbilanciamento e la latenza dell interconnessione di rete è alta, la soluzione sarà intermedia ; sarà necessario stimare il costo della comunicazione/sincronizzazione e del sbilanciamento prima di decidere il grado di granularità. Nella fase di design è necessario stimare e misurare le perfomance di un algoritmo parallelo. Successivamente alla fase di realizzazione, dovranno essere stimate le perfomance ottenute con la corrente implementazione. Qualora la stima e la misura delle perfomance siano fortemente diverse, sarà necessario migliorare l implementazione. Ma come possiamo stimare e misurare le prestazioni parallele? Ci aspettiamo che lanciando il nostro programma seriale su più processori, supponendo di aver parallelizzato nel modo migliore possibile, il tempo di esecuzione via via si dimezzi. Purtroppo non è così. Innanzitutto come misuriamo i tempi di esecuzione di un programma? Esiste in linux il comando time ls <nome programma>, che ci permette di misurare i tempi di ese- 34

40 cuzione di un programma seriale. Purtroppo questo comando non è valido per i programmi in parallelo. Inoltre per misurare realmente i vantaggi ottenuti dalla parallelizzazione, dovremmo calcolare i tempi solo delle parti di calcolo vero e proprio, e non considerare nella nostra stima le fasi, per esempio, delle allocazioni di memoria. Per fortuna MPI possiede una funzione che permette di misurare i tempi di esecuzione di un programma, che permette anche di separarne le varie parti e misurarne i tempi in modo separato, per poi avere una stima reale del tempo di calcolo parallelo. La funzione è MPI_WTIME, e la sua sintassi è: double MPI_Wtime (void); DOUBLE PRECISION MPI_WTIME() Questa funzione ci dà in uscita un tempo, misurato in secondi, a partire da un tempo arbitrario nel passato. A questo punto l idea più semplice che ci viene in mente è quella di inserire questa funzione in vari parti del programma, per e- sempio inserirne una subito sotto la fase iniziale di allocazione della memoria, dove non esiste parallelizzazione, una all interno del loop parallelo, e semplicemente fare la differenza fra le due per calcolare i tempi di esecuzione del calcolo in parallelo. Ma come facciamo a misurare all interno di un programma seriale i tempi di esecuzione delle varie parti? Sia le librerie del C che del Fortran possiedono due funzioni che permettono di misurare i tempi di vari blocchi del programma, e sono: int gettimeofday (struct timeval *restrict tp, void *restrict tzp); CALL SYSTEM_CLOCK (COUNT=IC, COUNT_RATE=IR, COUNT_MAX=IM) Non entriamo nel dettaglio di queste due funzioni, ci basta sapere che permettono di misurare i tempi di esecuzione seriale di un qualsiasi pezzo di codice. A questo punto siamo in grado di confrontare i tempi seriali con quelli paralleli. Eliminiamo il background, relativo alle operazioni di allocazione, e ci aspettiamo che i tempi di calcolo si dimezzino all aumentare del numero di processori. Purtroppo non é così. Infatti, oltre alle parti, iniziali e finali di un codice, può accadere che anche all interno del loop parallelizzato esistano delle parti non parallelizzabili. Questa parte prende il nome di frazione scalare, e siamo in grado di scrivere la legge di Amdahl (Fig.29), la quale afferma che se fs è la frazione di un calcolo che è sequenziale (cioè che non può beneficiare del parallelismo ), e (1 fs) è 35 Fig.29. Legge di Amdahl

41 la frazione che può essere parallelizzata, allora il tempo da noi misurato u- sando n processori è: t(n) = t(1) * [fs + (1 - fs)/n] Questa legge afferma che il tempo di calcolo non scala in maniera lineare, a causa delle parti scalari, e come si evince dal grafico, oltre una certa soglia si raggiunge un valore limite, che rende inutile l aumento del numero di processori. Anche in questo caso le parti scalari possono essere stimate facendo un confronto con i tempi ottenuti quando eseguiamo il programma seriale. Purtroppo la frazione scalare riduce di molto le perfomance. Inoltre dobbiamo considerare le parti MPI aggiunte al codice, che prima non erano presenti, cioè: Tempi di comunicazione/sincronizzazione; Tempi di eventuali idle time dovuto a load imbalance; Tempi legati al possibile miglioramento dell uso della gerarchia di memoria al crescere del numero di processori; Calcoli aggiuntivi. I primi tre dipendono esplicitamente dal numero di processi. Ciò vuol dire che se adesso calcoliamo come il tempo varia al variare del numero di processi, otteniamo un grafico (Fig.30) in cui è ben evidente che all aumentare del numero di processori rischiamo, oltre a non aver più nessun vantaggio, di aumentare progressivamente i tempi di calcolo. Aumentando ancora il numero di processori potremmo addirittura ottenere un punto in cui i tempi di calcolo sono maggiori di quelli ottenuti con la medesima esecuzione seriale. E evidente che più processori si usano maggiore è il tempo che serve per la comunicazione, ma non solo, anche il fattore di sbilanciamento è legato inevitabilmente all aumentare del numero di processori. La stima che è stata fatta nel grafico è molto negativa, infatti abbiamo supposto che la comunicazione e la sincronizzazione vadano come la radice quadrata di n, mentre lo sbilanciamento Fig.30. Stima reale dei tempi di calcolo 36 va come n elevato 0.7. Nella maggior parte dei casi, quando la parallelizzazione del codice è stata effettuata in maniera ottimale, questa stima migliora di molto, ma non elimina totalmente questi tempi, che influenzano il nostro calcolo. Sta al programmatore trovare quel punto nella curva di Fig.30 in cui il tempo di calcolo e il numero di processori sono ottimali. In aiuto dei programmatori viene una metrica conforme che permette di trovare questo punto di convergenza fra efficienza (tempi di calcolo) e costi computazionali (numero di processori). Questa metrica è la SPEEDUP, che è uguale a:

42 3. La GRID 3.1 GRID computing Fig.31. Schema di una Grid 37 Il termine Grid computing (letteralmente, "calcolo a griglia") sta ad indicare un paradigma del calcolo distribuito, di recente introduzione, costituito da un'infrastruttura altamente decentralizzata e di natura variegata in grado di consentire ad un vasto numero di utenti l'utilizzo di risorse (prevalentemente CPU e storage) provenienti da un numero indistinto di calcolatori (anche e soprattutto di potenza non particolarmente elevata) interconnessi da una rete (solitamente, ma non necessariamente, Internet). Nel campo delle architetture di calcolo parallelo, il Grid Computing rappresenta oggi, senza alcun dubbio, la frontiera delle attività di ricerca. Tale fatto è testimoniato sia dal numero di progetti di ricerca dedicati a tale parola chiave, sia dal numero di grandi ditte di sistemi di calcolo, software e informatica in generale, che si sono dotate di una loro soluzione Grid, sia dalle iniziative nazionali o sovranazionali connesse alla parola chiave Grid. Tuttavia, questo termine, oggi così attuale, è, se si considerano i progetti di ricerca e l evoluzione delle tecnologie informatiche nel loro complesso, solo la punta di un iceberg. Il termine Grid (Fig.31), infatti, rappresenta la formulazione particolarmente fortunata di un idea, quella della condivisione delle risorse di calcolo, sviluppatasi faticosamente negli ultimi tre decenni a seguito della rapida e- voluzione delle tecnologie informatiche. Negli ultimi dieci anni, poi, a partire dai primi esperimenti di macchine parallele virtuali realizzate su reti locali sino a giungere a concezioni avveniristiche quali la potenza di calcolo su richiesta o l integrazione dinamica di componenti simulativi sviluppati indipendentemente, un filo conduttore può essere individuato nella necessità di superare il problema dell eterogeneità, sia a livello hardware che a livello software, al fine di fornire un immagine integrata del sistema. Questo problema dell eterogeneità, tuttavia, si presenta in nuove forme ogni qualvolta, trovata una soluzione accettabile per dominare il livello di eterogeneità precedentemente affrontato, si voglia superare la concezione precedente per aprire a nuove idee e possi-

Classificazione delle Architetture Parallele

Classificazione delle Architetture Parallele Università degli Studi di Roma Tor Vergata Facoltà di Ingegneria Classificazione delle Architetture Parallele Corso di Sistemi Distribuiti Valeria Cardellini Anno accademico 2009/10 Architetture parallele

Dettagli

Alcuni strumenti per lo sviluppo di software su architetture MIMD

Alcuni strumenti per lo sviluppo di software su architetture MIMD Alcuni strumenti per lo sviluppo di software su architetture MIMD Calcolatori MIMD Architetture SM (Shared Memory) OpenMP Architetture DM (Distributed Memory) MPI 2 1 Message Passing Interface MPI www.mcs.anl.gov./research/projects/mpi/

Dettagli

Scuola di Calcolo Scientifico con MATLAB (SCSM) 2017 Palermo 31 Luglio - 4 Agosto 2017

Scuola di Calcolo Scientifico con MATLAB (SCSM) 2017 Palermo 31 Luglio - 4 Agosto 2017 Scuola di Calcolo Scientifico con MATLAB (SCSM) 2017 Palermo 31 Luglio - 4 Agosto 2017 www.u4learn.it Alessandro Bruno Introduzione al calcolo parallelo Approcci per il calcolo parallelo Programmazione

Dettagli

Sistemi a processori multipli

Sistemi a processori multipli Sistemi a processori multipli Sommario Classificazione e concetti di base Sistemi multi-processore Sistemi multi-computer (cluster) Sistemi distribuiti Obiettivo comune Risolvere problemi di dimensioni

Dettagli

Modelli di programmazione parallela

Modelli di programmazione parallela Modelli di programmazione parallela Oggi sono comunemente utilizzati diversi modelli di programmazione parallela: Shared Memory Multi Thread Message Passing Data Parallel Tali modelli non sono specifici

Dettagli

Architetture della memoria

Architetture della memoria Architetture della memoria Un elemento determinante per disegnare una applicazione parallela e' l architettura della memoria della macchina che abbiamo a disposizione. Rispetto all architettura della memoria

Dettagli

Modello a scambio di messaggi

Modello a scambio di messaggi Modello a scambio di messaggi Aspetti caratterizzanti il modello Canali di comunicazione Primitive di comunicazione 1 Aspetti caratterizzanti il modello modello architetturale di macchina (virtuale) concorrente

Dettagli

Architettura hardware

Architettura hardware Architettura hardware la parte che si può prendere a calci Architettura dell elaboratore Sistema composto da un numero elevato di componenti, in cui ogni componente svolge una sua funzione elaborazione

Dettagli

Calcolo parallelo. Una sola CPU (o un solo core), per quanto potenti, non sono sufficienti o richiederebbero tempi lunghissimi

Calcolo parallelo. Una sola CPU (o un solo core), per quanto potenti, non sono sufficienti o richiederebbero tempi lunghissimi Calcolo parallelo Ci sono problemi di fisica, come le previsioni meteorologiche o alcune applicazioni grafiche, che richiedono un enorme potenza di calcolo Una sola CPU (o un solo core), per quanto potenti,

Dettagli

CLASSIFICAZIONE DEI SISTEMI OPERATIVI (in ordine cronologico)

CLASSIFICAZIONE DEI SISTEMI OPERATIVI (in ordine cronologico) CLASSIFICAZIONE DEI SISTEMI OPERATIVI (in ordine cronologico) - Dedicati Quelli dei primi sistemi operativi. La macchina viene utilizzata da un utente per volta che può eseguire un solo programma per volta.

Dettagli

Il Modello a scambio di messaggi

Il Modello a scambio di messaggi Il Modello a scambio di messaggi 1 Interazione nel modello a scambio di messaggi Se la macchina concorrente e` organizzata secondo il modello a scambio di messaggi: PROCESSO=PROCESSO PESANTE non vi è memoria

Dettagli

Funzioni, Stack e Visibilità delle Variabili in C

Funzioni, Stack e Visibilità delle Variabili in C Funzioni, Stack e Visibilità delle Variabili in C Programmazione I e Laboratorio Corso di Laurea in Informatica A.A. 2016/2017 Calendario delle lezioni Lez. 1 Lez. 2 Lez. 3 Lez. 4 Lez. 5 Lez. 6 Lez. 7

Dettagli

Componenti principali. Programma cablato. Architettura di Von Neumann. Programma cablato. Cos e un programma? Componenti e connessioni

Componenti principali. Programma cablato. Architettura di Von Neumann. Programma cablato. Cos e un programma? Componenti e connessioni Componenti principali Componenti e connessioni Capitolo 3 CPU (Unita Centrale di Elaborazione) Memoria Sistemi di I/O Connessioni tra loro 1 2 Architettura di Von Neumann Dati e instruzioni in memoria

Dettagli

Componenti principali

Componenti principali Componenti e connessioni Capitolo 3 Componenti principali n CPU (Unità Centrale di Elaborazione) n Memoria n Sistemi di I/O n Connessioni tra loro Architettura di Von Neumann n Dati e instruzioni in memoria

Dettagli

Il processore. Istituzionii di Informatica -- Rossano Gaeta

Il processore. Istituzionii di Informatica -- Rossano Gaeta Il processore Il processore (detto anche CPU, ovvero, Central Processing Unit) è la componente dell unità centrale che fornisce la capacità di elaborazione delle informazioni contenute nella memoria principale

Dettagli

MPI. MPI e' il risultato di un notevole sforzo di numerosi individui e gruppi in un periodo di 2 anni, tra il 1992 ed il 1994

MPI. MPI e' il risultato di un notevole sforzo di numerosi individui e gruppi in un periodo di 2 anni, tra il 1992 ed il 1994 MPI e' acronimo di Message Passing Interface Rigorosamente MPI non è una libreria ma uno standard per gli sviluppatori e gli utenti, che dovrebbe essere seguito da una libreria per lo scambio di messaggi

Dettagli

Componenti e connessioni. Capitolo 3

Componenti e connessioni. Capitolo 3 Componenti e connessioni Capitolo 3 Componenti principali CPU (Unità Centrale di Elaborazione) Memoria Sistemi di I/O Connessioni tra loro Architettura di Von Neumann Dati e instruzioni in memoria (lettura

Dettagli

Non blocking. Contro. La programmazione di uno scambio messaggi con funzioni di comunicazione non blocking e' (leggermente) piu' complicata

Non blocking. Contro. La programmazione di uno scambio messaggi con funzioni di comunicazione non blocking e' (leggermente) piu' complicata Non blocking Una comunicazione non blocking e' tipicamente costituita da tre fasi successive: L inizio della operazione di send/receive del messaggio Lo svolgimento di un attivita' che non implichi l accesso

Dettagli

Le reti rete La telematica telematica tele matica Aspetti evolutivi delle reti Modello con mainframe terminali Definizione di rete di computer rete

Le reti rete La telematica telematica tele matica Aspetti evolutivi delle reti Modello con mainframe terminali Definizione di rete di computer rete Reti e comunicazione Le reti Con il termine rete si fa riferimento, in generale ai servizi che si ottengono dall integrazione tra tecnologie delle telecomunicazioni e le tecnologie dell informatica. La

Dettagli

Comunicazione tra Computer. Protocolli. Astrazione di Sottosistema di Comunicazione. Modello di un Sottosistema di Comunicazione

Comunicazione tra Computer. Protocolli. Astrazione di Sottosistema di Comunicazione. Modello di un Sottosistema di Comunicazione I semestre 03/04 Comunicazione tra Computer Protocolli Prof. Vincenzo Auletta auletta@dia.unisa.it http://www.dia.unisa.it/professori/auletta/ Università degli studi di Salerno Laurea in Informatica 2

Dettagli

Come aumentare le prestazioni Cenni alle architetture avanzate

Come aumentare le prestazioni Cenni alle architetture avanzate Politecnico di Milano Come aumentare le prestazioni Cenni alle architetture avanzate Mariagiovanna Sami Richiamo: CPI CPI = (cicli di clock della CPU richiesti dall esecuzione di un programma)/ numero

Dettagli

La CPU e la Memoria. Sistemi e Tecnologie Informatiche 1. Struttura del computer. Sistemi e Tecnologie Informatiche 2

La CPU e la Memoria. Sistemi e Tecnologie Informatiche 1. Struttura del computer. Sistemi e Tecnologie Informatiche 2 La CPU e la Memoria Sistemi e Tecnologie Informatiche 1 Struttura del computer Sistemi e Tecnologie Informatiche 2 1 I registri La memoria contiene sia i dati che le istruzioni Il contenuto dei registri

Dettagli

Calcolatori Elettronici A a.a. 2008/2009

Calcolatori Elettronici A a.a. 2008/2009 Calcolatori Elettronici A a.a. 2008/2009 Instruction Set Architecture: nozioni generali Massimiliano Giacomin 1 DOVE CI TROVIAMO Livello del linguaggio specializzato Traduzione (compilatore) o interpretazione

Dettagli

Programma del corso. Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori

Programma del corso. Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori Programma del corso Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori Evoluzione dei sistemi informatici Cos è una rete? Insieme di

Dettagli

Architettura dei Calcolatori. Macchina di von Neumann /2. Macchina di von Neumann /1. Architettura dei Calcolatori

Architettura dei Calcolatori. Macchina di von Neumann /2. Macchina di von Neumann /1. Architettura dei Calcolatori rchitettura dei Calcolatori Giuseppe Pozzi Impianti di Elaborazione Facoltà di Ingegneria dell'informazione Politecnico di Milano giuseppe.pozzi@polimi.it - versione del 20 settembre 2002 - rchitettura

Dettagli

Il calcolatore. È un sistema complesso costituito da un numero elevato di componenti. è strutturato in forma gerarchica

Il calcolatore. È un sistema complesso costituito da un numero elevato di componenti. è strutturato in forma gerarchica Il calcolatore È un sistema complesso costituito da un numero elevato di componenti. è strutturato in forma gerarchica ogni livello di descrizione è caratterizzato da una struttura rappresentante l organizzazione

Dettagli

Modelli di interazione tra processi

Modelli di interazione tra processi Modelli di interazione tra processi Modello a memoria comune (ambiente globale, global environment) Modello a scambio di messaggi (ambiente locale, message passing) 1 Modello a memoria comune Il sistema

Dettagli

ARCHITETTURA DI UN ELABORATORE! Ispirata al modello della Macchina di Von Neumann (Princeton, Institute for Advanced Study, anni 40).!

ARCHITETTURA DI UN ELABORATORE! Ispirata al modello della Macchina di Von Neumann (Princeton, Institute for Advanced Study, anni 40).! ARCHITETTURA DI UN ELABORATORE! Ispirata al modello della Macchina di Von Neumann (Princeton, Institute for Advanced Study, anni 40).! MACCHINA DI VON NEUMANN! UNITÀ FUNZIONALI fondamentali! Processore

Dettagli

Modelli di interazione tra processi

Modelli di interazione tra processi Modelli di interazione tra processi Modelli di interazione Modello a memoria comune (ambiente globale) Modello a scambio di messaggi (ambiente locale, message passing) Modello a memoria comune Il sistema

Dettagli

TEORIA DEI SISTEMI OPERATIVI. Sistemi monoprogrammatie multiprogrammati

TEORIA DEI SISTEMI OPERATIVI. Sistemi monoprogrammatie multiprogrammati TEORIA DEI SISTEMI OPERATIVI Sistemi monoprogrammatie multiprogrammati 1 STRUTTURA DEL SISTEMA OPERATIVO UTENTE La struttura di un sistema operativo è di tipo gerarchico: i programmi che lo compongono

Dettagli

Von Neumann Bottleneck

Von Neumann Bottleneck Von Neumann Bottleneck Gerarchia di memoria Struttura della Gerarchia Al livello 1 poniamo la memoria più veloce (piccola e costosa) Al livello n poniamo la memoria più lenta (grande ed economica) Scopo

Dettagli

Architettura di von Neumann

Architettura di von Neumann Fondamenti di Informatica per la Sicurezza a.a. 2008/09 Architettura di von Neumann Stefano Ferrari UNIVERSITÀ DEGLI STUDI DI MILANO DIPARTIMENTO DI TECNOLOGIE DELL INFORMAZIONE Stefano Ferrari Università

Dettagli

Architettura di von Neumann

Architettura di von Neumann Fondamenti di Informatica per la Sicurezza a.a. 2007/08 Architettura di von Neumann Stefano Ferrari UNIVERSITÀ DEGLI STUDI DI MILANO DIPARTIMENTO DI TECNOLOGIE DELL INFORMAZIONE Stefano Ferrari Università

Dettagli

Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo. Daniele Loiacono

Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo. Daniele Loiacono Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo Riferimenti q Questo materiale deriva dalle slide del prof. Lanzi per il corso di Informatica B, A.A. 2009/2010 q Il materiale presente in

Dettagli

Informatica Generale 07 - Sistemi Operativi:Gestione dei processi

Informatica Generale 07 - Sistemi Operativi:Gestione dei processi Informatica Generale 07 - Sistemi Operativi:Gestione dei processi Cosa vedremo: Esecuzione di un programma Concetto di processo Interruzioni Sistemi monotasking e multitasking Time-sharing Tabella dei

Dettagli

LA GESTIONE DELLA I/O

LA GESTIONE DELLA I/O LA GESTIONE DELLA I/O Il S.O. È l interfaccia tra l hardware e i programmi che effettuano richieste di I/O Sottosistema di I/O strutturato in moduli chiamati DRIVER uno per ogni dispositivo I Driver rendono

Dettagli

Architetture di rete. 4. Le applicazioni di rete

Architetture di rete. 4. Le applicazioni di rete Architetture di rete 4. Le applicazioni di rete Introduzione L avvento di tecnologie (hw, sw, protocolli) di rete avanzate ha permesso la nascita di architetture software molto evolute che permettono lo

Dettagli

Lezione 15 Il Set di Istruzioni (1)

Lezione 15 Il Set di Istruzioni (1) Lezione 15 Il Set di Istruzioni (1) Vittorio Scarano Architettura Corso di Laurea in Informatica Università degli Studi di Salerno Un quadro della situazione Input/Output Sistema di Interconnessione Registri

Dettagli

Corso di Informatica

Corso di Informatica CdLS in Odontoiatria e Protesi Dentarie Corso di Informatica Prof. Crescenzio Gallo crescenzio.gallo@unifg.it Il Processore (CPU) 2 rchitettura del processore CPU Unità di Controllo Unità ritmetica Logica

Dettagli

Architettura dei Calcolatori Elettronici

Architettura dei Calcolatori Elettronici Architettura dei Calcolatori Elettronici Prof. Orazio Mirabella L architettura del Calcolatore: esame delle sue caratteristiche Fondamentali Capacità di eseguire sequenze di istruzioni memorizzate Calcolatore

Dettagli

Spazio di indirizzamento virtuale

Spazio di indirizzamento virtuale Programmazione M-Z Ingegneria e Scienze Informatiche - Cesena A.A. 016-01 Spazio di indirizzamento virtuale Pietro Di Lena - pietro.dilena@unibo.it // The function name says it all int stack_overflow (){

Dettagli

Il Processore. Informatica di Base -- R.Gaeta 27

Il Processore. Informatica di Base -- R.Gaeta 27 Il Processore Il processore (detto anche CPU, ovvero, Central Processing Unit) è la componente dell unità centrale che fornisce la capacità di elaborazione delle informazioni contenute nella memoria principale

Dettagli

Primi passi col linguaggio C

Primi passi col linguaggio C Andrea Marin Università Ca Foscari Venezia Laurea in Informatica Corso di Programmazione part-time a.a. 2011/2012 Come introdurre un linguaggio di programmazione? Obiettivi: Introduciamo una macchina astratta

Dettagli

Architettura degli elaboratori - 2 -

Architettura degli elaboratori - 2 - Università degli Studi dell Insubria Dipartimento di Scienze Teoriche e Applicate Architettura degli elaboratori e gerarchie di memoria Marco Tarini Dipartimento di Scienze Teoriche e Applicate marco.tarini@uninsubria.it

Dettagli

Architetture Applicative Altri Esempi

Architetture Applicative Altri Esempi Architetture Applicative Altri Esempi Alessandro Martinelli alessandro.martinelli@unipv.it 15 Aprile 2014 Architetture Applicative Altri Esempi di Architetture Applicative Architetture con più Applicazioni

Dettagli

Architettura dei computer

Architettura dei computer Architettura dei computer In un computer possiamo distinguere quattro unità funzionali: il processore la memoria principale (memoria centrale, RAM) la memoria secondaria i dispositivi di input/output La

Dettagli

Il Processore: l unità di controllo

Il Processore: l unità di controllo Il Processore: l unità di controllo La frequenza con cui vengono eseguiti i cicli di esecuzione è scandita da una componente detta clock Ad ogni impulso di clock la UC esegue un ciclo di esecuzione di

Dettagli

Elementi di informatica

Elementi di informatica Elementi di informatica Architetture degli elaboratori Il calcolatore Un calcolatore è sistema composto da un elevato numero di componenti Il suo funzionamento può essere descritto se lo si considera come

Dettagli

Sottosistemi ed Architetture Memorie

Sottosistemi ed Architetture Memorie Sottosistemi ed Architetture Memorie CORSO DI CALCOLATORI ELETTRONICI I CdL Ingegneria Biomedica (A-I) DIS - Università degli Studi di Napoli Federico II La memoria centrale Memoria centrale: array di

Dettagli

Architettura hardware

Architettura hardware Architettura dell elaboratore Architettura hardware la parte che si può prendere a calci Sistema composto da un numero elevato di componenti, in cui ogni componente svolge una sua funzione elaborazione

Dettagli

Modelli di interazione tra processi

Modelli di interazione tra processi Modelli di interazione tra processi Modello a memoria comune (ambiente globale, global environment) Modello a scambio di messaggi (ambiente locale, message passing) 1 Modello a memoria comune Il sistema

Dettagli

Corso di Fondamenti di Informatica Elementi di Architettura

Corso di Fondamenti di Informatica Elementi di Architettura di Cassino e del Lazio Meridionale Corso di Informatica Elementi di Architettura Anno Accademico 2016/2017 Francesco Tortorella Modello di von Neumann Bus di sistema CPU Memoria Centrale Interfaccia Periferica

Dettagli

Come aumentare le prestazioni Cenni alle architetture parallele

Come aumentare le prestazioni Cenni alle architetture parallele Politecnico di Milano Come aumentare le prestazioni Cenni alle architetture parallele Mariagiovanna Sami La necessità di architetture con prestazioni più elevate Per particolari applicazioni (alcune di

Dettagli

La memoria principale

La memoria principale La memoria principale DRAM (Dynamic RAM) il contenuto viene memorizzato per pochissimo tempo per cui deve essere aggiornato centinaia di volte al secondo (FPM, EDO, SDRAM, RDRAM) SRAM (Static RAM) veloce

Dettagli

Informatica 3. LEZIONE 1: Introduzione. Modulo 1: Introduzione al corso Modulo 2: Introduzione ai linguaggi di programmazione

Informatica 3. LEZIONE 1: Introduzione. Modulo 1: Introduzione al corso Modulo 2: Introduzione ai linguaggi di programmazione Informatica 3 LEZIONE 1: Introduzione Modulo 1: Introduzione al corso Modulo 2: Introduzione ai linguaggi di Informatica 3 Lezione 1- Modulo 1 Introduzione al corso Introduzione Corso di Informatica 3

Dettagli

Introduzione al Many/Multi-core Computing

Introduzione al Many/Multi-core Computing Introduzione al Many/Multi-core Computing Sistemi Operativi e reti 6 giugno 2011 Parte I Architettura Classificazione fra architetture Flynn s taxonomy SISD Single instruction on Single Data- (es. architetture

Dettagli

ISO- OSI e architetture Client-Server

ISO- OSI e architetture Client-Server LEZIONE 9 ISO- OSI e architetture Client-Server Proff. Giorgio Valle Raffaella Folgieri giorgio.valle@unimi.it folgieri@dico.unimi.it Lez 10 modello ISO-OSI e architettura client-server 1 Nelle scorse

Dettagli

Sistemi Operativi: Concetti Introduttivi

Sistemi Operativi: Concetti Introduttivi Sistemi Operativi: Concetti Introduttivi 1.1 Principali funzioni di un Sistema Operativo 1.2 Cenni Storici 1.3 Classificazione dei Sistemi Operativi 1.4 Struttura dei Sistemi Operativi 1.5 Processi e gestione

Dettagli

Il problema dello I/O e gli Interrupt. Appunti di Sistemi per la cl. 4 sez. D A cura del prof. Ing. Mario Catalano

Il problema dello I/O e gli Interrupt. Appunti di Sistemi per la cl. 4 sez. D A cura del prof. Ing. Mario Catalano Il problema dello I/O e gli Interrupt Appunti di Sistemi per la cl. 4 sez. D A cura del prof. Ing. Mario Catalano Il Calcolatore e le periferiche Periferica Decodifica Indirizzi Circuiti di Controllo Registri

Dettagli

Informatica 3. Informatica 3. Lezione 1- Modulo 1. LEZIONE 1: Introduzione. Concetti di linguaggi di programmazione. Introduzione

Informatica 3. Informatica 3. Lezione 1- Modulo 1. LEZIONE 1: Introduzione. Concetti di linguaggi di programmazione. Introduzione Informatica 3 Informatica 3 LEZIONE 1: Introduzione Lezione 1- Modulo 1 Modulo 1: Introduzione al corso Modulo 2: Introduzione ai linguaggi di Introduzione al corso Politecnico di Milano - Prof. Sara Comai

Dettagli

Programma del corso. Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori

Programma del corso. Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori Programma del corso Introduzione Rappresentazione delle Informazioni Calcolo proposizionale Architettura del calcolatore Reti di calcolatori Cos è un Calcolatore? Un computer (calcolatore) è una macchina

Dettagli

La gerarchia di memorie (2)

La gerarchia di memorie (2) La gerarchia di memorie (2) Architetture Avanzate dei Calcolatori Valeria Cardellini Migliorare le prestazioni delle cache Consideriamo la formula del tempo medio di accesso in memoria (AMAT) AMAT = hit

Dettagli

Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo. Daniele Loiacono

Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo. Daniele Loiacono Introduzione al Calcolo Parallelo Algoritmi e Calcolo Parallelo Riferimenti Questo materiale deriva dalle slide del prof. Lanzi per il corso di Informatica B, A.A. 2009/2010 Il materiale presente in queste

Dettagli

Richiami sull architettura del processore MIPS a 32 bit

Richiami sull architettura del processore MIPS a 32 bit Caratteristiche principali dell architettura del processore MIPS Richiami sull architettura del processore MIPS a 32 bit Architetture Avanzate dei Calcolatori Valeria Cardellini E un architettura RISC

Dettagli

Componenti di un processore

Componenti di un processore Componenti di un processore Unità di Controllo Bus Interno REGISTRI Program Counter (PC) Registro di Stato (SR) Registro Istruzioni (IR) Registri Generali Unità Aritmetico- Logica Registro Indirizzi Memoria

Dettagli

Programmi per calcolo parallelo. Calcolo parallelo. Esempi di calcolo parallelo. Misure di efficienza. Fondamenti di Informatica

Programmi per calcolo parallelo. Calcolo parallelo. Esempi di calcolo parallelo. Misure di efficienza. Fondamenti di Informatica FONDAMENTI DI INFORMATICA rof IER LUCA MONTESSORO Facoltà di Ingegneria Università degli Studi di Udine Calcolo parallelo e sistemi multiprocessore 2000 ier Luca Montessoro (si veda la nota di copyright

Dettagli

Sistemi di Elaborazione delle Informazioni

Sistemi di Elaborazione delle Informazioni SCUOLA DI MEDICINA E CHIRURGIA Università degli Studi di Napoli Federico II Corso di Sistemi di Elaborazione delle Informazioni Dott. Francesco Rossi a.a. 2016/2017 1 Programma del corso Informatica di

Dettagli

Introduzione all'architettura dei Calcolatori

Introduzione all'architettura dei Calcolatori Introduzione all'architettura dei Calcolatori Architettura dei calcolatori Che cos è un calcolatore? Come funziona un calcolatore? un calcolatore è un sistema un sistema è un oggetto costituito da molte

Dettagli

L ARCHITETTURA DEI CALCOLATORI. Il processore La memoria centrale La memoria di massa Le periferiche di I/O

L ARCHITETTURA DEI CALCOLATORI. Il processore La memoria centrale La memoria di massa Le periferiche di I/O L ARCHITETTURA DEI CALCOLATORI Il processore La memoria centrale La memoria di massa Le periferiche di I/O Caratteristiche dell architettura 2 Flessibilità adatta a svolgere diverse tipologie di compiti

Dettagli

Elementi di informatica

Elementi di informatica Elementi di informatica Architetture degli elaboratori Il calcolatore Un calcolatore è sistema composto da un elevato numero di componenti Il suo funzionamento può essere descritto se lo si considera come

Dettagli

Sistemi e Tecnologie per l'automazione LS. HW per elaborazione digitale in automazione: Microcontrollori e DSP

Sistemi e Tecnologie per l'automazione LS. HW per elaborazione digitale in automazione: Microcontrollori e DSP Laurea Specialistica in Ingegneria Informatica Laurea Specialistica in Ingegneria Elettronica e delle Telecomunicazioni Sistemi e Tecnologie per l'automazione LS HW per elaborazione digitale in automazione:

Dettagli

Introduzione. Caratteristiche generali. Sistemi e Tecnologie per l'automazione LS. HW per elaborazione digitale in automazione: Microcontrollori e DSP

Introduzione. Caratteristiche generali. Sistemi e Tecnologie per l'automazione LS. HW per elaborazione digitale in automazione: Microcontrollori e DSP Laurea Specialistica in Ingegneria Informatica Laurea Specialistica in Ingegneria Elettronica e delle Telecomunicazioni Sistemi e Tecnologie per l'automazione LS HW per elaborazione digitale in automazione:

Dettagli

static dynamic random access memory

static dynamic random access memory LA MEMORIA SRAM e D R A M static dynamic random access memory SRAM: unità che memorizza un gran numero di parole in un insieme di flip-flop, opportunamente connessi, mediante un sistema di indirizzamento

Dettagli

SISD - Single Instruction Single Data. MISD- Multiple Instructions Single Data. SIMD Single Instruction Multiple Data. Architetture di processori

SISD - Single Instruction Single Data. MISD- Multiple Instructions Single Data. SIMD Single Instruction Multiple Data. Architetture di processori Classificazione di Flynn Architetture di processori SISD - Single Instruction Single Data Le istruzioni sono eseguite sequenzialmente su un solo insieme di dati Le macchine sequenziali comuni appartengono

Dettagli

Linguaggi, Traduttori e le Basi della Programmazione

Linguaggi, Traduttori e le Basi della Programmazione Corso di Laurea in Ingegneria Civile Politecnico di Bari Sede di Foggia Fondamenti di Informatica Anno Accademico 2011/2012 docente: Prof. Ing. Michele Salvemini Sommario Il Linguaggio I Linguaggi di Linguaggi

Dettagli

Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma.

Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma. Unità Didattica 1 Linguaggio C Fondamenti. Struttura di un programma. 1 La storia del Linguaggio C UNIX (1969) - DEC PDP-7 Assembly Language BCPL - un OS facilmente accessibile che fornisce potenti strumenti

Dettagli

Esonero di Informatica I. Ingegneria Medica

Esonero di Informatica I. Ingegneria Medica Di seguito sono elencati una serie di domande tipo esonero ; i quiz vogliono dare un sistema di autovalutazione e di confronto allo studente che deve prepararsi alla prova di metà corso. Il numero e l

Dettagli

Macchine Astratte. Luca Abeni. February 22, 2017

Macchine Astratte. Luca Abeni. February 22, 2017 Macchine Astratte February 22, 2017 Architettura dei Calcolatori - 1 Un computer è composto almeno da: Un processore (CPU) Esegue le istruzioni macchina Per fare questo, può muovere dati da/verso la memoria

Dettagli

Lezione 15. L elaboratore Elettronico

Lezione 15. L elaboratore Elettronico Lezione 15 Architettura di un calcolatore L elaboratore Elettronico Un elaboratore elettronico è una macchina elettronica in grado di elaborare dati secondo le specifiche fornite da un algoritmo Internamente

Dettagli

Corso di Architettura (Prof. Scarano) 09/04/2002

Corso di Architettura (Prof. Scarano) 09/04/2002 Corso di Architettura (Prof. Scarano) 09/0/2002 Un quadro della situazione Lezione 15 Il Set di Istruzioni (1) Vittorio Scarano Architettura Corso di Laurea in Informatica Università degli Studi di Salerno

Dettagli

I THREAD O PROCESSI LEGGERI

I THREAD O PROCESSI LEGGERI I THREAD O PROCESSI Processi (pesanti): LEGGERI entità autonome con poche risorse condivise (si prestano poco alla scrittura di applicazioni fortemente cooperanti) Ogni processo può essere visto come Immagine

Dettagli

5. I device driver. Device driver - gestori delle periferiche. Struttura interna del sistema operativo Linux. Tipi di periferiche. Tipi di periferiche

5. I device driver. Device driver - gestori delle periferiche. Struttura interna del sistema operativo Linux. Tipi di periferiche. Tipi di periferiche Device driver - gestori delle periferiche Struttura interna del sistema operativo Linux Sono moduli software che realizzano l interfacciamento e la gestione dei dispositivi periferici Interagiscono con

Dettagli

Capitolo 2: Strutture dei sistemi di calcolo

Capitolo 2: Strutture dei sistemi di calcolo Capitolo 2: Strutture dei sistemi di calcolo Funzionamento di un sistema di calcolo Struttura di I/O Struttura della memoria Gerarchia delle memorie Architetture di protezione Struttura delle reti di calcolatori

Dettagli

Il Sottosistema di Memoria

Il Sottosistema di Memoria Il Sottosistema di Memoria Calcolatori Elettronici 1 Memoria RAM RAM: Random Access Memory Tempi di accesso indipendenti dalla posizione Statica o Dinamica Valutata in termini di Dimensione (di solito

Dettagli

Struttura hw del computer

Struttura hw del computer Informatica per laurea triennale facoltà di medicina LEZIONE 3 Il processore, la memoria e l esecuzione dei programmi 1 Struttura hw del computer Il nucleo di un computer è costituito da 3 principali componenti:

Dettagli

Il Sistema Operativo

Il Sistema Operativo Il Sistema Operativo Il sistema operativo Con il termine sistema operativo si intende l insieme di programmi e librerie che opera direttamente sulla macchina fisica mascherandone le caratteristiche specifiche

Dettagli

Macchina di Riferimento: argomenti

Macchina di Riferimento: argomenti Macchina di Riferimento: argomenti L'architettura di una macchina MIPS Organizzazione della memoria I registri della CPU L'esecuzione dei programmi Il ciclo fetch-execute Il simulatore SPIM 1 Architettura

Dettagli

Algoritmo. La programmazione. Algoritmo. Programmare. Procedimento di risoluzione di un problema

Algoritmo. La programmazione. Algoritmo. Programmare. Procedimento di risoluzione di un problema Algoritmo 2 Procedimento di risoluzione di un problema La programmazione Ver. 2.4 Permette di ottenere un risultato eseguendo una sequenza finita di operazioni elementari Esempi: Una ricetta di cucina

Dettagli

Architettura dei Calcolatori elettronici

Architettura dei Calcolatori elettronici Architettura dei Calcolatori elettronici CORSO DI CALCOLATORI ELETTRONICI I CdL Ingegneria Biomedica (A-I) DIS - Università degli Studi di Napoli Federico II Dal punto di vista architetturale un calcolatore

Dettagli

Sistemi Operativi SISTEMI DI INPUT/OUTPUT. D. Talia - UNICAL. Sistemi Operativi 10.1

Sistemi Operativi SISTEMI DI INPUT/OUTPUT. D. Talia - UNICAL. Sistemi Operativi 10.1 SISTEMI DI INPUT/OUTPUT 10.1 Sistemi I/O Hardware di I/O Interfaccia di I/O per le applicazioni Sottosistema per l I/O del kernel Trasformazione delle richieste di I/O Stream Prestazioni 10.2 I/O Hardware

Dettagli

ISA Input / Output (I/O) Data register Controller

ISA Input / Output (I/O) Data register Controller ISA Input / Output (I/O) Numerose Periferiche di tanti tipi diversi, collegati alla CPU mediante BUS diversi. Solo Input (tastiera, mouse), producono dati che la CPU deve leggere. Solo Output (Schermo),

Dettagli

Che cos e l Informatica. Informatica generale. Caratteristiche fondamentali degli algoritmi. Esempi di algoritmi. Introduzione

Che cos e l Informatica. Informatica generale. Caratteristiche fondamentali degli algoritmi. Esempi di algoritmi. Introduzione Che cos e l Informatica Scienza dell elaborazione dell informazione Informatica generale non si riduce all utilizzo di strumenti (e.g. linguaggi di programmazione e basi di dati); si occupa del trattamento

Dettagli

Architettura di un calcolatore: Introduzione parte 2

Architettura di un calcolatore: Introduzione parte 2 Corso di Calcolatori Elettronici I Architettura di un calcolatore: Introduzione parte 2 Prof. Roberto Canonico Università degli Studi di Napoli Federico II Dipartimento di Ingegneria Elettrica e delle

Dettagli

Linguaggi di Programmazione

Linguaggi di Programmazione Linguaggi di Programmazione Linguaggi di Programmazione Programmazione. Insieme delle attività e tecniche svolte per creare un programma (codice sorgente) da far eseguire ad un computer. Che lingua comprende

Dettagli

Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE. Francesco Tura. F. Tura

Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE. Francesco Tura. F. Tura Informatica ALGORITMI E LINGUAGGI DI PROGRAMMAZIONE Francesco Tura francesco.tura@unibo.it 1 Lo strumento dell informatico: ELABORATORE ELETTRONICO [= calcolatore = computer] Macchina multifunzionale Macchina

Dettagli

Introduzione alle gerarchie di memoria

Introduzione alle gerarchie di memoria Introduzione alle gerarchie di memoria 1 Un ripasso Circuito sequenziale Segnale di clock Circuito sincrono Temporizzazione sensibile ai fronti Latch tipo S-R Latch tipo D Flip-flop tipo D Register file

Dettagli

Sistemi e reti CPU Concetti di base

Sistemi e reti CPU Concetti di base Sistemi e reti CPU Concetti di base A cura dell Ing. Claudio Traini Cenni Storici 1971 il primo processore mai realizzato : Intel 4004 Progettato dal vicentino Federico Faggin 1 Cenni Storici 1976 Faggin

Dettagli

Introduzione al funzionamento di un calcolatore elettronico

Introduzione al funzionamento di un calcolatore elettronico 1 / 21 Introduzione al funzionamento di un calcolatore elettronico Natascia Piroso 23 settembre 2009 2 / 21 Sommario Che cos è un calcolatore? 1 Che cos è un calcolatore? Definizioni preliminari Il calcolatore

Dettagli

Esame di INFORMATICA Lezione 4

Esame di INFORMATICA Lezione 4 Università di L Aquila Facoltà di Biotecnologie Esame di INFORMATICA Lezione 4 MACCHINA DI VON NEUMANN Il sottosistema di memorizzazione (memoria) contiene dati + istruzioni, inseriti inizialmente tramite

Dettagli