Breve introduzione al calcolo parallelo Creative Commons 2013 Free Report CC BY Mauro Ennas 1998-2013 Some Rights Reserved CC 1998-2013 BY Mauro Ennas - Some Rights Reserved Breve introduzione al calcolo parallelo Se utilizzi queste note (testo, codici e figure) per produrre nuovo materiale, cita la fonte. Indice 1 Introduzione al calcolo parallelo 1 2 Architetture parallele 8 2.1 La Connection Machine - TMC . . . . . . . . . . . . . . . . . . . . 13 2.2 L’IBM-SP2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.2.1 Componenti del sistema . . . . . . . . . . . . . . . . . . . 17 2.2.2 I processori . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.2.3 Il sottosistema di comunicazione . . . . . . . . . . . . . . 18 2.2.4 Ambiente parallelo . . . . . . . . . . . . . . . . . . . . . . . 20 3 Programmazione parallela 21 3.1 Modello message-passing . . . . . . . . . . . . . . . . . . . . . . 22 3.2 Modello shared-memory . . . . . . . . . . . . . . . . . . . . . . . 22 3.3 Modello data-parallel . . . . . . . . . . . . . . . . . . . . . . . . . 23 4 Programmazione data-parallel 25 4.1 L’High Performance Fortran . . . . . . . . . . . . . . . . . . . . . 26 4.2 Il FORTRAN 90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.3 Caratteristiche del linguaggio HPF . . . . . . . . . . . . . . . . . 31 4.3.1 Il mapping dei dati Mauro Ennas . . . . . . . . . . . . . . . . . . . . . . 33 Creative Commons 2013 5 Compilatori per macchine parallele 36 5.1 PGHPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5.2 ADAPTOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 5.3 Prestazioni degli algoritmi paralleli . . . . . . . . . . . . . . . . . 39 5.3.1 Modello semplificato per i tempi di calcolo . . . . . . . . . 41 Bibliografia 43 CC 1998-2013 BY Mauro Ennas - Some Rights Reserved Breve introduzione al calcolo parallelo Se utilizzi queste note (testo, codici e figure) per produrre nuovo materiale, cita la fonte. Capitolo 1 Introduzione al calcolo parallelo La costruzione del primo calcolatore elettronico moderno viene attribuita ai due ricercatori statunitensi Mauchly ed Eckert dell’Università della Pennsylvania, che insieme ad oltre trenta studenti della stessa Università riuscirono a progettare e portare a termine la costruzione del calcolatore denominato ENIAC I 1 nel 1946. L’importanza del calcolo automatico era emersa precocemente, rispetto alle tecnologie disponibili, nei secoli precedenti ad opera di Gottfried Wilhelm von Leibnitz (1646-1716) che costruı̀ una macchina meccanica capace di effettuare moltiplicazioni e divisioni e Charles Babbage (1792-1871) che tentò di costruire un grosso calcolatore meccanico, costituito da ingranaggi e ruote dentate, che per complessità e caratteristiche di progetto stimolò, nei decenni sucessivi, i progettisti dei moderni sistemi di calcolo. Con l’ENIAC I viene fatta cominciare l’era moderna del progetto di calcolatori elettronici 2 in quanto dall’esperienza maturata nella costruzione di un 1 2 Elettronic Numeric Integrator And Calculator. Anche se è noto che, in realtà, i primi tentativi risalgono a dieci anni prima, ne è un esempio l’elaboratore Z1 di Konrad Zuse nella Germania hitleriana (1938) che rappresenta il primo calcolatore a relè funzionante; seguirono lavori di John Atanasoff dello Iowa State College e di George Stibbits presso i Bell Labs che costruirono Mauro Ennas Creative Commons 2013 2 simile mostro, costituito da 18000 tubi a vuoto e 1500 relè, pesante ben 30 tonnellate e con consumi quantificati in 140 kilowatt, Mauchley ed Eckert diedero vita, sei anni dopo, al primo calcolatore commerciale l’UNIVAC I (1952). Dai corsi tenuti da Mauchley ed Eckert nel dopoguerra si scatenò un interesse crescente per il progetto di calcolatori elettronici e vennero affinate le tecniche di progetto finchè si giunse nel 1960 ad un modello generale proposto da John von Neumann che costruı̀ la IAS machine (a transistori 3 ) presso l’Istituto di Studi Avanzati dell’Università di Princeton. La cosidetta MEMORIA Unità di Controllo Accumulatore Input Figura 1.1: Output Macchina di von Neumann. macchina di von Neumann (figura (1.1)) è alla base delle moderne architetture dei calcolatori elettronici. Gli anni cinquanta e sessanta furono segnati dallo sviluppo di una piccola azienda produttrice, originariamente, di perforatrici e ordinatori meccanici per schede. Si tratta dell’IBM, che finanziò vari progetti e produsse per proprio conto macchine a valvole prima e a transistori poi, commercializzandoli su vasta scala sino a divenire leader mondiale del mercato dei calcolatori elettronici negli anni sessanta e settanta con i processori INTEL. Da studi effettuati al M.I.T. di Boston sotto la sigla TX project (Transistorized eXperimental) nasce la DEC di Kenneth Olsen con varie versioni dei sistemi PDP calcolatori ad aritmetica binaria e con meccanismi di refresh della memoria del tutto simili a quelli delle moderne RAM dinamiche. 3 Il primo transistore venne costruito nei laboratori Bell nel 1948 da John Bardeen, Walter Bratten e William Shockeley che per questa invenzione furono insigniti del Premio Nobel nel 1956. Mauro Ennas Creative Commons 2013 3 a partire dal PDP-1 che introdusse il controllo del video (CRT) e sul quale vennero programmati i primi videogiochi, sino al più noto PDP-11. La terza generazione di calcolatori viene fatta coincidere con l’avvento dei circuiti integrati (1965-1980) che permisero all’IBM un’ulteriore espansione nel mercato commerciale, sviluppando una linea di sistemi (famiglia) i cosidetti IBM-360 (dal 1964); vennero introdotte importanti innovazioni quali la possibilità di gestire in memoria più programmi contemporaneamente tramite la multiprogrammazione, la possibilità di emulazione di altri processori e l’estensione dello spazio di indirizzamento. La quarta genera- Cray X-MP Figura 1.2: Evoluzione dei calcolatori paralleli. La continua crescita del numero di processori per una singola macchina è strettamente correlato ai progressi nei settori delle tecnologie elettroniche e microelettroniche e alla drastica riduzione dei costi di produzione su larga scala. zione arriva sino ai giorni nostri ed è caratterizzata dall’avvento dei sistemi integrati su larga scala VLSI e UVLSI; nasce il personal computer e vengono sviluppate famiglie (quali INTEL e Motorola) di circuiti elettronici digitali integrati (IC). Migliorano notevolmente le prestazioni in termini di velocità di calcolo e di precisione nei calcoli in virgola mobile, migliora la facilità d’uso del calcolatore (grazie al potenziamento della programmazione e l’avvento dell’era del software) e si moltiplicano le interfacce esterne che possono Mauro Ennas Creative Commons 2013 4 essere controllate attraverso il calcolatore e che ne hanno potenziato le prestazioni e la diffusione sino ai giorni nostri. Degno di nota il sistema VAX (1978) della DEC, il primo supermini a 32 bit ancora in funzione in molti centri di calcolo. Per avere nuovi sviluppi nel progetto delle architetture dei calcolatori si devono attendere gli anni ottanta con il progetto delle macchine RISC 4 cosı̀ denominate in contrapposizione alle macchine CISC (Complex Instruction Set Computer) ossia le IBM-360, i DEC-VAX, INTEL-X86 e i Motorola68030. Il nuovo paradigma di progettazione propone una revisione completa ed una riduzione di complessità delle tecniche di progettazione in uso sino agli anni ottanta. Il dibattito sulle strategie legate all’introduzione di tecnologie avanzate muove da ragioni dominate da inferenze di tipo ecomonico, determinate dalla globalizzazione della competitizione industriale. Col passare del tempo i microprocessori raggiungono complessità crescenti che appiattiscono, dal punto di vista delle prestazioni, le diverse classi di calcolatori che avevano dominato il ventennio precedente a causa della maturazione delle tecnologie, della diffusione sempre crescente dei calcolatori in tutti i settori produttivi e della conseguente riduzione dei loro costi (figura (1.2)). Spesso si assume che in origine tutti i processori fossero macchine RISC, con un piccolo numero di istruzioni gerarchiche che potevano essere eseguite in sequenza. Le esigenze sempre crescenti portarono all’introduzione della microprogrammazione per il progetto di processori più sofisticati. Il passo fondamentale per la semplificazione delle archittetture è, paradossalmente, il miglioramento del software, in particolare dei sistemi operativi e dei compilatori [8]. La prima macchina RISC fu il minicalcolatore IBM-801 (1975), ma le più note macchine di questa categoria restano la MIPS di John Hennessy (1984) e la SPARC 5 della Sun Micro- system (1987). Già dagli anni sessanta si era pensato che più calcolatori opportunamente programmati avrebbero potuto risolvere problemi di gran4 Acronimo coniato da gruppo di Berkeley guidato da D. Patterson e C. Séquin che progettarono nel 1980 il VLSI-RISC (Reduced Instruction Set Computer) che portò ai processori RISC I e II. 5 Scalable Processor ARChitecture. Mauro Ennas Creative Commons 2013 5 Cray X-MP Figura 1.3: Evoluzione delle prestazioni delle macchine parallele. de complessità, più velocemente, se avessero potuto funzionare parallelamente cioè applicando gli stessi algoritmi su insiemi diversi di dati, oppure applicando algoritmi differenti contemporaneamente sugli stessi dati. Nel 1964 nasce CDC-6600 a parallelismo interno estensivo, ben dieci volte più veloce della IBM-7094 che dominò il calcolo scientifico negli anni ’60. Il primo supercalcolatore parallelo fu il CRAY-1 del 1974. I supercalcolatori sono stati concepiti per risolvere problemi di calcolo scientifico altamente estensivi ed intensivi; cioè in grado di lavorare su grosse quantità di dati e di massimizzare il numero di operazioni in virgola mobile per secondo FLOPS (FLoating point Operations Per Second). Qualsiasi macchina che non raggiunga prestazioni di 1 Giga-FLOPS non viene considerata un supercalcolatore (figura (1.3)). Generalmente le archittetture parallele vengono progettate per applicazioni molto particolari ma negli ultimi anni si stanno imponendo sempre più sistemi dalle caratteristiche flessibili, applicabili a più ambiti, grazie alle migliorate caratteristiche dei processori. Seymour Cray padre delle macchine CDC, fondò la società che prende il suo nome e che attualmente produ- Mauro Ennas Creative Commons 2013 6 ce il T3D e T3E. Negli anni novanta le macchine a parallelismo massiccio che hanno avuto maggiore successo commerciale sono, oltre alle macchine Cray, la Connection Machine (Thinking Machine Corporation) e l’IBM-SP2. In Italia l’Alenia Spazio ha progettato in collaborazione con il CNR, l’INFN e l’ENEA le macchine denominate QUADRICS, in due modelli QH16 6 e QDeSC 7 , variamente configurabili. In questo primo capitolo verranno introdotte le nozioni base del calcolo parallelo, relativamente ad architetture, linguaggi e compilatori. Verrà data particolare enfasi ai concetti legati al modello di programmazione data parallel ed al linguaggio High Performance FORTRAN, indicando le caratteristiche in base alle quali è stato scelto per il progetto di software scientifico ad alte prestazioni (High Performance Computing). Verranno indicate le caratteristiche salienti del calcolatore parallelo IBM-SP2/30 del CRS4, utilizzata per lo sviluppo e il testing dei codici che verranno descritti dettagliatamente nei capitoli successivi. Nella parte conclusiva del capitolo vengono definiti alcuni importanti indicatori di prestazioni. 6 7 Sino a 200 GFLOPS. Sino ad 1 GFLOPS. Mauro Ennas Creative Commons 2013 Mauro Ennas Nome Costruttore Note 1934 Analytical Engine Babbage Primo calcolatore numerico (non riuscito). 1936 Z1 Zuse Prima macchina a relè funzionante. 1943 COLOSSUS Regno Unito Primo calcolatore completamente elettronico. 1944 Mark I Aiken Primo calcolatore general purpose. 1946 ENIAC I Mauchley/Eckert Primo calcolatore moderno (post bellico). 1949 EDSAC Wilkes Primo calcolatore con programmi in memoria. 1951 Whirlwind M.I.T. Primo calcolatore real time. 1952 UNIVAC I Mauchley/Eckert Primo calcolatore commercializzato. 1960 IAS von Neumann Riferimento per calcolatori di II generazione. 1960 CEP 1960 ELEA 9.300 Olivetti Primo calcolatore commerciale italiano. 1961 PDP-1 DEC Primo minicalcolatore (50 esemplari venduti). 1962 1401 IBM PC record di vendite negli anni ’60. 1963 7094 IBM Calcolatore scientifico dominante negli anni ’60. 1964 B5000 Burroughs Prima macchina con linguaggio di alto livello (Algol-60). 1964 360 IBM Prima famiglia di calcolatori. 1965 6600 CDC Prima macchina a parallelismo interno estensivo. 1970 PDP-8 DEC Primo minicalcolatore di massa (50000 venduti). 1970 PDP-11 DEC Minicalcolatore dominante negli anni ’70. 1974 8080 Intel Prima CPU general purpose integrata. 1974 CRAY-1 Cray primo supercalcolatore. 1978 VAX DEC Primo supermini a 32 bit. Univ. di Pisa Più potente sistema costruito in Europa. 7 Creative Commons 2013 Anno Capitolo 2 Architetture parallele Un calcolatore tradizionale ha una sola CPU che emette richieste sequenziali del bus dati per leggere o scrivere in memoria o nello spazio di InputOutput, ricevendo una risposta per volta. Questa modalità di funzionamento è nota come collo di bottiglia di von Neumann. Ad essa si è pensato di ovviare progettando calcolatori che avessero più unità di controllo, più unità logico aritmetiche (ALU), più memorie in grado di operare in parallelo nella esecuzione di uno o più programmi. Sono numerosi i progetti che aggregano CPU potenti debolmente connesse o numerose ALU e FPU (Floating Point Unit) fortemente interagenti e sincronizzate e tutta una varietà di progetti intermedi che hanno come finalità il progetto di efficaci sistemi di calcolo parallelo. La descrizione dei sistemi di calcolo parallelo richiede la conoscenza della natura, della dimensione e del numero degli elementi di elaborazione e dei moduli di memoria interagenti, nonchè delle strategie per connettere tra loro processori e memorie. In genere gli elementi di elaborazione sono CPU complete oppure ALU minime, con dimensioni largamente variabili, da un chip a varie decine di schede sulle quali sono montati migliaia di elementi 1. Nel caso di CPU complete le tecnologie attuali permettono connessioni di poco più di 1000 elementi. 1 Esistono sistemi con 65536 (CM-2) elementi di elaborazione (ALU) [8] ed esistono progetti con oltre un milione di elementi. Mauro Ennas Creative Commons 2013 9 Gli elementi di memoria sono suddivisi in moduli che operano indipendentemente gli uni da gli altri. Tra gli svariati sistemi esistenti vi sono da un lato quelli con migliaia di elementi di elaborazione e memorie della dimensione di qualche Kbyte (1 Kbyte = 210 byte = 1024 byte), dall’altra vi sono sistemi con poche potenti unità di elaborazione con decine di Mbyte di memoria (220 > un milione di byte). Il problema cruciale è quello della velocità relativa tra sistemi di elaborazione e memoria. Figura 2.1: Topologie di connessione dei processori. Topologia. I sistemi di elaborazione parallela si diversificano, oltre che per il progetto delle CPU e della memoria, soprattutto per le modalità con le quali si mettono insieme i componenti [8][12]. Abbiamo due grosse categorie per gli schemi di interconnessione: • schemi statici: cosidetti perchè cablano tutti i componenti in un grafo fissato (stella, griglia o anello); • schemi dinamici: quando unità di elaborazione e memorie sono agganciati ad una rete di commutazione che guida i messaggi dinamicamente tra processori differenti e memorie. Questa prima classificazione strutturale è tipica di un approccio top-down. Se vogliamo evidenziare quale sia il processo di calcolo che effettivamente deve essere parallelizzato possiamo pensare che esistono problemi che hanno bisogno di svolgere la stessa funzione su un insieme di dati di volta in volta differente (ad esempio l’applicazione di uno stesso operatore locale su diverse sezioni di uno stesso volume) oppure diverse funzioni su uno stesso dataset (interrogazione di uno stesso archivio da parte di più utenti), con la stessa finalità di riduzione del tempo di elaborazione. Un sistema Mauro Ennas Creative Commons 2013 10 parallelo in questo senso può essere visto come un sistema time sharing, ossia relativo ad un parallelismo delle funzioni in esecuzione in un sistema distribito (in rete) tra processori e memoria. Un altro modo di vedere le cose è quello di considerare un calcolatore Figura 2.2: Ipercubo di processori e codice di Gray. Un efficiente meccanismo di comunicazione è il cosidetto modello dei primi vicini ed è basato su una particolare allocazione della memoria dei processori su una matrice, attraverso una codifica binaria (codice Gray) che garantisce la vicinanza dei dati; il codice è tale che due numeri interi consecutivi differiscono per una sola cifra binaria, in questo modo è possibile distribuire i dati in modo tale da mantenere una relazione di stretto vicinato, minimizzando le comunicazioni. parallelo utilizzato per eseguire un unico lavoro costituito da più processi paralleli parzialmente disgiunti che concorrono ad un risultato finale unitario. Ancora, possiamo pensare a sistemi che agiscono sul flusso delle istruzioni smistando le operazioni su più ALU operanti contemporaneamente oppure ad un alevato livello di pipeline (differenti stadi della stessa istruzione vengono eseguiti in modo concorrente); i calcolatori vettoriali ricadono in quest’ultima categoria. Granulatità ed Accoppiamento. Un’altra caratteristica che ci permette di classificare i sistemi paralleli è la cosidetta granularità (grain size). Nei sistemi time sharing e in quelli con più CPU abbiamo una cosidetta unità di parallelismo elevata che coincide col programma eseguibile nella sua interezza. L’esecuzione di grosse porzioni di codice con poca o senza comu- Mauro Ennas Creative Commons 2013 11 nicazione tra unità di elaborazione distinte prende il nome di parallelismo a grana grossa in contrapposizione al parallelismo a grana fine caratterizzato dall’elaborazione di piccole porzioni di codice con una discreta comunicazione tra processori, come avviene nei calcolatori vettoriali. In genere la granularità è un concetto che si riferisce al software ma ha un’analogia immediata nell’hardware [8]. In questo caso si parla più propriamente di accoppiamento 2 stretto oppure di accoppiamento debole, in relazione alla quantità di dati che vengono scambiati in un secondo (banda di accoppiamento). In genere, i problemi con parallelismo a grana grossa lavorano meglio su sistemi ad accoppiamento debole mentre quelli con parallelismo a grana fine su architetture ad accoppiamento stretto, ma gli algoritmi e le architetture esistenti sono talmente varie che una indicazione di questo tipo può risultare fuorviante in molti casi. Tassonomia. Si cerca di mettere ordine in una situazione di questo tipo cercando di costruire delle vere e proprie tassonomie dei sistemi di elaborazione parallela (figura (2.3)). Tra le più note vi è certamente la tassonomia di Flynn 3 (1972), mostrata in figura (2.3). La tassonomia di Flynn è basata su due concetti: • il flusso delle istruzioni, che corrisponde ad un contatore di programma; un sistema con n CPU ha n contatori di programma, quindi n flussi d’istruzione; • il flusso dei dati è costituito da un insieme di operandi; un programma che calcola una funzione su un elenco di dati ha un flusso di dati, quello che calcola la stessa funzione su più elenchi diversi di dati ha più flussi di dati. Poichè il flusso di istruzioni e quello di dati sono indipendenti esistono quattro categorie di macchine parallele: 2 I sistemi con un piccolo numero di potenti CPU indipendenti che hanno una banda di accoppiamento stretta sono dette ad accoppiamento debole, viceversa sistemi con molti processori meno potenti ma con banda di accoppiamento più larga sono detti ad accoppiamenti stretto. 3 Altre sono attribuite a Gayski e Pier e a Treleaven (entrambe nel 1985). Mauro Ennas Creative Commons 2013 12 SISD von Neumann MISD SIMD MIMD ? Vettoriali Cray Cyber 205 NEC SX Paralleli A memoria condivisa Switched ILLIAC IV CM-2, CM-200 Ultracomputer RP3 Butterfly Figura 2.3: A memoria privata Bus Sequent Encore Firefly Switched Bus Workstation su LAN Hypercube Transputer SP2 Tassonomia di Flynn. • SISD (Single Istruction Single Data), come la tipica macchina di von Neumann; • SIMD (Single Istruction Multiple Data), nella quale vi è una sola unità di controllo che esegue una sola istruzione alla volta e più ALU per eseguire simultaneamente la stessa istruzione su diversi data-set; • MISD è una categoria anomala in quanto dovrebbero esserci più istruzioni che operano sugli stessi dati; molti annoverano in questa categoria le macchine a pipeline; • MIMD, cioè macchine costituite da più CPU distinte e indipendenti che operano come parte di un sistema più grande. Molti processori o sistemi paralleli appartengono a questa categoria. La tassonomia di Flynn si ferma qui ma può essere estesa considerando le macchine SIMD divise in due sottogruppi, i supercalcolatori numerici e le macchine vettoriali, inoltre anche la grande categoria delle macchine MIMD (figura (2.4)) può essere suddivisa in macchine che hanno una memoria primaria condivisa (multiprocessori) da quelle che non ce l’hanno (multicalcolatori, o calcolatori a memoria privata o disgiunta). Mauro Ennas Creative Commons 2013 2.1 La Connection Machine - TMC Figura 2.4: 13 Schemi tipici per le archittetture parallele MIMD. [ a] Interconnessione a rete tipica delle macchine MIMD a memoria distribuita; [ b] Interconnessione a BUS per multiprocessori a memoria condivisa (shared-memory). 2.1 La Connection Machine - TMC Un esempio di calcolatore SIMD è la Connection Machine (CM) progettata da W. Daniel Hillis 4 che in seguito fondò la Thinking Machines Corporation per costruire e commercializzare le CM, sin dal 1986. Nel seguito ci riferiremo per semplicità alla CM-2 (figura (2.5)), precursore della più moderna CM-200 5 , allo scopo di evidenziare la complessità e le eccezionali capacità di calcolo messe a disposizione dalle architetture a parallelismo massiccio. La CM-2 è costituita da quattro parti (quadranti), ciascuna delle quali è divisa in due sezioni di 8192 processori (PE-8K) ciascuna. Ogni quadrante contiene un’unità di controllo (sequenziatore) che è in grado di eseguire un programma completo non appena è stato caricato in memoria. Il sistema è caratterizzato dall’assenza di memoria di programma (ovvero è una macchina di back-end), per cui dovrà appoggiarsi ad uno o più host (sino a quattro host, ad esempio DEC-VAX). I programmi vengono editati, compilati e collegati sull’host e quindi caricati sulla CM attraverso 4 Il progetto originario era parte della sua tesi di Ph.D. sull’intelligenza artificiale (M.I.T. 1985). 5 Attualmente la Thinking Machines Corporation progetta e costruisce macchine MIMD a parallelismo massiccio (CM-5) Mauro Ennas Creative Commons 2013 2.1 La Connection Machine - TMC 14 Nome Costruttore Tipo Memoria CM-200 TMC SIMD Distribuita CM-5 TMC MIMD Distribuita T3D (T3E) Cray MIMD Distribuita Paragon Intel MIMD Distribuita CS-2 Meiko MIMD Distribuita SP2 IBM MIMD Distribuita C-90 Cray SIMD Condivisa PowerChallenge SGI MIMD Condivisa Tabella 2.1: Calcolatori paralleli moderni. una griglia di interruttori 4 × 4 e quindi eseguiti. I quattro quadranti possono operare separatamente eseguendo quattro programmi diversi contemporaneamente; è possibile raggruppare più quadranti per formare un unico sistema di 65536 processori operanti all’unisono nella soluzione di un problema di grosse dimensioni. Ogni processore è costituito da un’unità logico aritmetica (ALU) e da 8 Kbyte di memoria privata oltre a 4 bit di flag; le ALU sono riunite in gruppi di 16 (VLSI) e per ogni gruppo è presente un istradatore che si occupa della spedizione dei messaggi tra i processori. L’insieme di 32 gruppi viene riunito in una piastra costituita da 160 chip ed altri circuiti integrati d’interfaccia (figura (2.6)). Sedici piastre costituiscono un sottocubo per un totale di 8196 processori, due sottocubi formano un quadrante e quattro quadranti un cubo di 1.5 metri di lato, costituito complessivamente da 25000 circuiti integrati. La topologia di comunicazione e di tipo ipercubo (figura (2.2)). Un sistema di questo tipo è in grado di effettuare 4 miliardi di operazioni in virgola mobile al secondo. Ogni sottocubo ha il proprio canale di I/O al quale si può collegare un sistema di memorie di massa detto data vault, oltre ad un display grafico ed altre periferiche. Ogni data vault è costituito da ben 39 disk drive e su Mauro Ennas Creative Commons 2013 2.1 La Connection Machine - TMC Figura 2.5: 15 Struttura della CM-2. L’interrutore a griglia permette la configurabilità dell’accesso alle unità di calcolo (quadranti). ALU Figura 2.6: Unità di elaborazione nella CM-2. ognuno di essi puo essere scritto un bit, di una parola di 39, in parallelo. Questo permette di raggiungere velocità di 40 Mbyte/sec per ognuno degli otto sistemi data vault per un totale di 320 Mbyte/sec. La capacità totale dei dischi è compresa tra 40 Gbyte e 80 Gbyte a seconda che si utilizzino unità di 150 o 300 Mbyte. Mauro Ennas Creative Commons 2013 2.2 L’IBM-SP2 16 Caratteristiche Numero di processori 65536 Memoria 512 Mbyte Banda della Memoria 300 Gbyte/sec Banda I/O 320 Mbyte/sec Banda interprocessore 250 milioni di parole/sec Addizione di interi (32 bit) 2500 MIPS Addizione in virgola mobile (32 bit) 4 GFLOPS Dissipazione di energia 28 kW Peso 1200 kg Tabella 2.2: Caratteristiche principali della CM-2. 2.2 L’IBM-SP2 Il sistema parallelo scalabile 6 IBM-SP2 possiede la principale caratteristica della macchine moderne a parallelismo massiccio: la flessibilità. Tradizionalmente il progetto di calcolatori paralleli era orientato ad usi specifici con nicchie di mercato estremamente strette. Attualmente, grazie alla potenza delle prestazioni delle singole unità di elaborazione, vengono progettati calcolatori paralleli general pourpose, capaci di assolvere ad una grande varietà di utilizzi. Il sistema SP2 è un sistema basato su un’architettura message passing a memoria distribuita. Generalmente sono disponibili sistemi con un numero di unità di elaborazione che variano tra 2 e 128 nodi (unità di processo); sono stati sviluppati sistemi con 512 nodi ed oltre per applicazioni particolari. I singoli nodi della SP2 sono processori RISC System/6000 in tecnologia POWER2, interconnessi da una rete a commutazione di pacchetto (packet-switched network) ad alte prestazioni, multistadio, per le comunicazioni interprocessore. Ciascuno dei nodi è dotato di memoria propria e di una copia del sistama operativo standard AIX e di altro software di sistema 6 Configurabile con un numero variabile di processori interagenti. Mauro Ennas Creative Commons 2013 2.2 L’IBM-SP2 17 specifico. Caratteristiche Numero di processori 30 (Thin Node2) Clock 66.7 MHz Memoria 128 Mbyte Bus della memoria 64 bit Cache L1 128 Kbyte (dati) e 32 Kbyte (istruzioni) Velocità del Bus 160 Mbyte/sec Velocità dello Switch 150 Mbyte/sec Peso 340-635 Kg Tabella 2.3: Caratteristiche principali dei processori RS/6000 della SP2/30 del CRS4. 2.2.1 Componenti del sistema Nel seguito verranno descritte con maggiore dettaglio le principali caratteristiche dei componeti del sistema parallelo IBM-SP2 (figura (2.7)). Le caratteristiche dei singoli componenti si riflettono in modo diretto sulle essenziali caratteristiche di scalabilità, di flessibilità e sulla natura general purpose di un sistema di questo tipo. 2.2.2 I processori Il fattore che determina le prestazioni del sistema, in prima analisi, è l’efficienza di ogni singolo processore. Per il sistema SP2 l’IBM [9] ha utilizzato il processore più veloce e robusto che aveva a disposizione, permettendo in questo modo la possibilità di utilizzare il sistema multiprocessore anche in modalità multipla monoprocessore con la stessa affidabilità. I processori RISC System/6000 in tecnologia POWER2 sono processori superscalari (ognuno dei quali è in grado di eseguire più istruzioni concor- Mauro Ennas Creative Commons 2013 Figura 2.7: { 18 { 2.2 L’IBM-SP2 La struttura dell’IBM-SP2/30. rentemente per ogni ciclo) e funzionanti in pipeline spinto (cioè funzionanti con frequenze molto elevate). Vi sono tre diversi tipi di nodo (wide, thin e thin2). Ciascuno dei nodi del primo e secondo tipo hanno due unità in virgola mobile (FPU) ed un’unità di controllo d’istruzione. Il clock di 66.7 M Hz permette ai processori di raggiungere performance di 267 MFLOPS. L’unità di controllo d’istruzione opera sulla decodifica delle istruzioni multiple ottimizzando la loro gestione. Tutto ciò unito ad una memoria gerarchica di grande capacità (da un minimo di 2 Gbyte) e di elevate prestazioni (banda passante di 2.1 Gbyte/sec). La memoria cache è di 256 Kbyte a 4 vie set associative, trasferisce quattro operandi di 64 bit (due linee) per ogni ciclo alla FPU. I nodi dei tre tipi differiscono per la memoria (quantità e tipo) e per la configurabilità. 2.2.3 Il sottosistema di comunicazione Viste le elevate prestazioni del processore [9], le richieste di velocità di comunicazione sono molto elevate, le parole chiave sono larga banda e piccola latenza. I nodi della SP2 sono interconnessi attraverso uno switch ad alte prestazioni (HPS) progettato con caratteristiche di scalabilità, bassa latenza, larga banda, basso overhead, affidabile e flessibile. La sua topologia è del tipo any-to-any packetswitch, multistadio e a rete indiretta (Omega network like) (figura (2.8)), ciò consente di adeguare linearmente la bisezione della banda alla dimensione scalare del sistema (altrettanto non avviene Mauro Ennas Creative Commons 2013 2.2 L’IBM-SP2 19 nelle reti ad anello o in quelle reticolari). La topologia HPS permette di ave- Figura 2.8: Esempio di rete Omega a tre stadi per la comunicazione tra processori e memoria. Sono presemti 12 interruttori a due ingressi (alto (0)) e due uscite per collegare 8 processori a 8 elementi di memoria (in generale sono necessari log2 (n) stadi con n/2 interruttori per stadio). re banda costante tra ogni coppia di nodi indipendente dalla loro posizione reciproca. In generale la banda disponibile in un nodo è pari a: Blink · Nlink N hops nella quale: • Blink è la banda coinvolta nella comunicazione (link band); • Nlink rappresenta il numero di comunicazioni per nodo nello switch; • N hops il numero medio di stadi attraverso lo switch richiesti per l’operazione di comunicazione. In uno switch multistadio come l’HPS sia N hops che Nlink scalano logaritmicamente col numero di nodi e viene resa costante la banda disponibile. Nelle reti dirette il numero di stadi, per una configurazione di comunicazione casuale, cresce col numero di nodi mentre il numero di link per nodo resta costante e quindi la banda media per coppia di nodi comunicanti decresce. Questo punto risulta determinante in quanto evita al programmatore di dover ottimizzare il software per minimizzare N hops . Mauro Ennas Creative Commons 2013 2.2 L’IBM-SP2 20 Ogni nodo della SP2 è connesso alla scheda HPS tramite un adattatore intelligente Micro Channel. Questo adattatore (con microprocessore onboard) è in grado di gestire le transazioni di messaggi direttamente sulla memoria del processore o a partire da essa (tramite Direct Memory Access) e decrementa sensibilmente il tempo di elaborazione dei messaggi con effetti benefici sulla gestione della banda di comunicazione. 2.2.4 Ambiente parallelo L’ambiente parallelo viene denominato SP2-AIX [9] integrato in un insieme di componenti permette lo sviluppo, il debugging ed il parallel tuning di programmi in FORTRAN 7 e C, inoltre permette di inizializzare, controllare e monitorare la loro esecuzione. Le componenti principali dell’ambiente parallelo sono: • la libreria Message-Passing (MPL) libreria avanzata di comunicazione per programmi FORTRAN e C, che utilizza protocollo TCP/IP su una connessione LAN o attraverso lo switch. • l’ambiente operativo parallelo (POE) permette di compilare e di effettuare il collegamento delle librerie disponibili; permette di creare partizioni dei nodi disponibili; carica gli eseguibili sui nodi e permette il controllo dell’esecuzione. • i tool di visualizzazione (VT) permettono il monitoraggio post mortem. • il debugger parallelo (PD) è una versione del sistema UNIX dbx - debugging tool specializzata per il debugging parallelo. Il file system è stato progettato ad hoc e denominato PIOFS (Parallel I/O File System). 7 FORmula TRANslation. Mauro Ennas Creative Commons 2013 Capitolo 3 Programmazione parallela Il programma parallelo è un insieme di processi per i quali esiste un ordine, seppure parziale, non fissato rigorosamente a priori come per i programmi sequenziali. L’obiettivi principale della programmazione parallela è la distribuzione ottimizzata dei carichi di lavoro (load balancing) sui diversi processori con la finalità di ottenere velocità di calcolo più elevate possibile. La disponibilità di programmi applicativi è uno degli elementi più importanti nel successo commerciale di un sistema di calcolo. Nel caso delle piattaforme parallele vengono richiesti applicativi per lo sviluppo di software principalmente nei linguaggi FORTRAN e C. Vi sono esenzialmente tre modelli di programmazione parallela utilizzati nella maggior parte dei sistemi scalabili: • il modello di programmazione message passing; • il modello di programmazione shared memory; • il modello di programmazione data parallel. Mauro Ennas Creative Commons 2013 3.1 Modello message-passing 22 3.1 Modello message-passing Nel modello basato sul passaggio esplicito di messaggi, i processi di un’applicazione parallela hanno ciascuno il proprio spazio d’indirizzamento privato e condividono i dati attraverso l’uso esplicito di messaggi; il processo sorgente esplicitamente manda (primitiva SEND) un messaggio ed il processo target esplicitamente lo riceve (primitiva RECEIVE). I processi evolvono nel senso che seguono il flusso di condivisione dei dati esplicitato direttamente nel programma attraverso le primitive SEND e RECEIVE. I programmi generalmente hanno una struttura SPMD (Single Program Multiple Data), ossia lo stesso programma agisce su porzioni parzialmente disgiunte dei dati. Il programma in esecuzione evolve secondo la modalità non perfettamente sincrona (loosely synchronous style) nella quale si alternano una fase di calcolo con una di comunicazione. Durante la fase di calcolo, ciascuno dei processi effettua i calcoli sulla porzione di dati assegnatagli e nella fase di comunicazione i processi scambiano dati utilizzando le librerie message-passing. Un esempio di linguaggio che supporta la programmazione message passing è l’OCCAM, inoltre attraverso il FORTRAN possono essere costruite librerie, quali MPI e PVM, di supporto al modello di programmazione. Generalmente, tra i maggiori vantaggi espressi dalla programmazione message passing vi è la concreta possibilità di creare implementazioni estremamente veloci degli algoritmi, dipendente strettamente dalla natura del problema e dall’abilità del programmatore. Tra i difetti riconosciuti bisogna ricordare che la portabilità non è garantita e che la programmazione presenta delle difficoltà da non sottovalutare nell’implementazione di codici complessi. 3.2 Modello shared-memory Nel modello a memoria condivisa i processi facenti capo ad una applicazione parallela condividono uno spazio d’indirizzamento ed in esso effettuano le operazioni di ingresso/uscita in modo asincrono; i dati, in questo modo, sono condivisi rispetto allo spazio direttamente referenziato senza bisogno Mauro Ennas Creative Commons 2013 3.3 Modello data-parallel 23 di azioni esplicite per individuare i dati da condividere. La sincronizzazione dei processi deve essere esplicitata utilizzando dei costrutti particolari. Il modello di programmazione shared memory viene spesso associato al controllo dinamico del parallelismo, nel quale porzioni logicamente indipendenti dello stesso flusso di programma possono essere considerati come blocchi funzionali o come cicli di iterazione indipendenti. 3.3 Modello data-parallel Con il nome modello data-parallel s’intende individuare quella classe di linguaggi che permettono di realizzare il parallelismo eseguendo una stessa operazione, ovvero una serie di istruzioni, in modo concorrente su insiemi di dati parzialmente disgiunti, facenti parte di una stessa struttura dati complessiva. In questo modo ciascuna delle operazioni su ciascuno degli elementi del dataset può vedersi come un processo indipendente dagli altri, ciò porta a dire che la naturale granularità di un linguaggio data parallel è una granularità fine. Il modello di programmazione con parallelismo nei dati viene supportato da linguaggi quali l’High Performance FORTRAN (HPF). I programmi sono scritti utilizzando il FORTRAN 90 sequenziale per specificare le operazioni sui dati, attraverso l’uso di costrutti particolari per le operazioni su vettori e matrici oltrechè direttive intrinseche dell’HPF per mappare i dati in modo che possano essere distribuiti sui vari processori. Il preprocessore o il compilatore HPF traducono il codice sorgente scritto utilizzando FORTRAN 90 più le direttive del linguaggio HPF in un codice equivalente SPMD con chiamate message passing (se il sistema supporta un’architettura message passing come nel caso dell’SP2) oppure con le appropriate sincronizzazioni (se il sistema supporta un’architettura time sharing). Il carico di calcolo viene distribuito ai processi paralleli secondo le specificazioni fornite attraverso le direttive di distribuzione HPF. Questo approccio ha il grande vantaggio di liberare il programmatore dal compito di distribuire matrici globali su matrici locali, sostituendo indici e rinominandoli oltre che indicare esplicitamente le chiamate per la trasmissione e Mauro Ennas Creative Commons 2013 3.3 Modello data-parallel 24 la ricezione dei dati o la loro sincronizzazione. Un’altro vantaggio notevole dello scrivere codici in HPF è la compatibilitá con il FORTRAN standard, agevolando il porting e la manutenzione dei codici, oltre che lo sviluppo su workstation monoprocessore. Esempi di linguaggi che supportano la programmazione data parallel sono CM FORTRAN, CRAFT, C ∗ , FORTRAN D e VIENNA FORTRAN. Mauro Ennas Creative Commons 2013 Capitolo 4 Programmazione data-parallel I linguaggi data-parallel forniscono un modello astratto di parallelismo, indipendente dalla macchina. Linguaggi di questa categoria hanno la caratteristica di permettere operazioni parallele a grana fine, devono permettere la condivisione dei dati attraverso operazioni di mapping dei dati ed inoltre la sincronizzazione implicita delle operazioni su di essi. Ciò permette di rendere le operazioni globali, su matrici anche di grandi dimensioni, concettualmente semplici e di semplificare la programmazione scientifica degli algoritmi. Lo svantaggio più rilevante sta nella complicazione dei compilatori. Un approccio di questo tipo distribuisce il lavoro tra programmatore e compilatore: • Il programmatore dovrà concentrare la sua attenzione sui concetti e le strutture di alto livello, aggregando le operazioni operanti su strutture dati di grosse dimensioni e fornendo le informazioni per la mappatura dei dati su matrici globali (array sintax). • I compiti del compilatore sono quelli di tradurre il mapping concettuale in una distribuzione fisica, su un numero finito di processori, permettendo l’efficacia del parallelismo mediante la cura dei dettagli, fornendo all’utilizzatore indicazioni per attuare le direttive di distribuzione dei dati e ottimizzando le comunicazioni. Mauro Ennas Creative Commons 2013 4.1 L’High Performance Fortran 26 4.1 L’High Performance Fortran La necessità di creazione di uno standard per la programmazione dataparallel dei supercalcolatori ha trovato una prima adeguata risposta con la costituzione di un comitato operativo nel Novembre 1991, denominato High Performance FORTRAN Forum (HPFF), che portò all’uscita delle prime note HPF Specification v1.0, nel Maggio 1993. Nel 1994 compaiono i primi compilatori commerciali e nel corso dei due anni successivi molte compagnie, non solo negli ambiti tecnologici affini ma anche importanti società industriali interessate allo spin-off tecnologico promosso da un’iniziativa di questo tipo, aderiscono all’HPF Forum. Attualmente il consorzio di ricerca è costituito da circa 40 tra industrie, università e laboratori di tutto il mondo non ancora legati formalmente con gli organi internazionali per la standardizzazione ma in contato con l’ANSI 1 X3J3 [1]. Gli obiettivi dell’HPF Forum sono quelli di definire un linguaggio con le seguenti caratteristiche: • basato sul modello data parallel; • tale da permettere elevate prestazioni su architetture SIMD e MIMD; • tale da permettere la portabilità dei codici su varie piattaforme architetturali. Questi obiettivi possono essere raggiunti tramite la definizione di nuove caratteristiche del linguaggio, quali: • funzioni intrinseche per il mapping dei dati; • costrutti che operano in parallelo sui dati; • direttive per il compilatore. Il linguaggio HPF poggia sui costrutti propri del FORTRAN 90 [6], al quale unisce direttive per l’allineamento e la distribuzione dei dati estendendo le librerie ed offrendo la possibilità di creare interfacce con altri linguaggi. 1 American National Standards Institute. Mauro Ennas Creative Commons 2013 4.2 Il FORTRAN 90 27 4.2 Il FORTRAN 90 Il FORTRAN 90 è significativamente migliore del FORTRAN 77 [7], in quanto contiene direttive e costrutti che ne semplificano l’uso e migliorano la leggibilità dei codici, carattteristica questa, di grande rilievo nei progetti di grosse dimensioni. I miglioramenti più importanti riguardano le operazioni sulle matrici e sui vettori, la possibilità di definizione dei tipi (come avviene in altri linguaggi di alto livello come il C) e nuovi costrutti di controllo e di allocazione dinamica, l’introduzione dei puntatori e di nuove funzionalità intrinseche. Il FORTRAN 90 (F90) può essere visto come un sottoinsieme del linguaggio HPF, anche se alcune sue funzionalità come i puntatori, le definizioni di tipo e i moduli non sono ancora presenti nei compilatori in commercio; il lavoro di adeguamento è tutt’ora in corso. Le caratteristiche più rilevanti del linguaggio riguardano le operazioni sulle matrici. La sintassi del F90 è molto sintetica e minimizza l’uso degli indici, come puó notarsi dall’esempio seguente: F77 F90 REAL A(100,100) ....... DO i=1, 100 REAL, DIMENSION(100,100) :: A ....... A = 4.0 DO j=1, 100 A(i,j) = 4.0 ENDDO ENDDO Un’altra caratteristica importante è il costrutto di controllo WHERE che equivale ad un IF su ciascuno degli elementi della matrice: REAL, DIMENSION(3,3) :: A ....... WHERE(A < 5.0) A = 5.0 Mauro Ennas Creative Commons 2013 4.2 Il FORTRAN 90 28 ELSE WHERE A = 2*A + 1.0 ENDWHERE che produce il risultato mostrato in figura (4.1). Gli indici possono essere gestiti in modo semplice per individuare insiemi 5 Figura 4.1: Il costrutto WHERE permette di effettuare un IF su ogni elemento della matrice globale (A nell’esempio). all’interno di vettori e matrici nella forma: indice − iniziale : indice − finale : passo come nell’esempio seguente REAL, DIMENSION(100) :: A ....... c A(1) = A(2) = ...= A(100) = 0.0 A(1:100) = 0.0 c A(50) = A(51) = ... = A(100) = 1.0 A(50:100) = 1.0 c A(1) = A(3) = .... = A(49) = 2.0 A(1:50:2) = 2.0 Le operazioni sulle matrici possono essere effettuate se c’è congruenza dimensionale, ovvero: INTEGER :: A(50), B(10) Mauro Ennas Creative Commons 2013 4.2 Il FORTRAN 90 29 ....... c B(1) = A(5), B(2) = A(10), ... ,B(10) = A(50). B = A(1:50:5) c B(1) = B(1)*A(21), B(2) = B(2)*A(22), ... , B(10) = B(10)*A(30). B = B*A(21:30) Vi sono direttive per l’allocazione e la deallocazione dinamica della memoria 2 : REAL, DIMENSION(:,:), ALLOCATABLE :: A INTEGER :: nx ....... nx = 100 ALLOCATE ( A(0,nx-1) ) ....... A = SQRT( A ) ....... DEALLOCATE( A ) La forma delle matrici può, in questo modo, non essere dichiarata esplicitamente. Sono disponibili funzioni per determinare le caratteristiche delle matrici (SIZE, LBOUND), per costruire matrici (SPREAD, PACK, RESHAPE), funzioni per calcolare il prodotto tra matrici (DOT PRODUCT, MATMUL), funzioni di riduzione che a partire da una matrice determinano il massimo o la somma degli elementi (MAXVAL, SUM) oppure applicano operatori logici ad insiemi particolari di dati (ANY, ALL), funzioni che determinano la locazione indiciale di massimi e minimi relativi (MAXLOC, MINLOC) e funzioni per manipolare le matrici come oggetti globali (CSHIFT, EOSHIFT, TRANSPOSE). Un esempio di funzione per costruire matrici è la funzione SPREAD che agisce come mostrato in figura (4.2). Per manipolare le matrici (ad esempio le immagini) si fa largo uso della funzione di traslazione ciclica CSHIFT (figura (4.3)). La varietà delle funzioni e delle direttive rendono il linguaggio 2 Contrariamente a quanto avviene in FORTRAN 77. Mauro Ennas Creative Commons 2013 4.2 Il FORTRAN 90 30 Figura 4.2: La direttiva SPREAD. di facile utilizzo e la sua efficacia viene dimostrata dalla facilità d’implementazione di algoritmi complicati. Inoltre, non devono essere trascurate tutte quelle caratteristiche che già appartenevano al F77 e che sono patrimonio comune, almeno nella semantica (non certo nella sintassi), dei linguaggi moderni di alto livello. Questo Figura 4.3: La direttiva CSHIFT. breve paragrafo non ha la pretesa di essere esaustivo 3 ma solo quella di indicare le principali caratteristiche di un linguaggio che a detta di molti dominerà lo scenario della programmazione scientifica avanzata dei prossimi anni, grazie ad altre sue importanti caratteristiche quali la gestione dei puntatori e delle stutture come i più moderni linguaggi di programmazione. 3 Per una completa descrizione del linguaggio si rimanda a testi specifici quali [6]. Mauro Ennas Creative Commons 2013 4.3 Caratteristiche del linguaggio HPF 31 4.3 Caratteristiche del linguaggio HPF La programmazione data-parallel si pone gli ambiziosi obiettivi di ridurre la complessità della programmazione parallela e nel contempo di permettere operazioni a grana fine efficienti nel senso del costo computazionale. L’HPF ha diverse possibilità per muoversi in questa direzione. La prima è senza dubbio quella offerta dal supporto del F90 con le operazioni sulle matrici; un’altra è rappresentata dalla procedura FORALL che permette di utilizzare cicli basati sulla struttura dello spazio degli indici, generalizzando il concetto di assegnamento dei valori ad una matrice tipico delle istruzioni di controllo quali il WHERE. Il FORALL viene eseguito in quattro passi: • calcolo degli indici validi • definizione degli indici attivi • valutazione delle espressioni al secondo membro • valutazione delle espressioni al primo membro Gli elementi di ciascuno stadio vengono valutati in parallelo ed ogni stadio del ciclo deve essere portato a termine prima che inizi il sucessivo; un comportamento non conforme si evidenzia nell’assegnare valori diversi alle stesse locazioni di memoria, per lo stesso stadio del ciclo. Il FORALL risulta utile in diverse situazioni: • negli assegnamenti in funzione degli indici FORALL (i=1:N, j=1:M) A(i,j) = SQRT( 1.0/ REAL(i+j) ) • nella distribuzione di dati a partire da geometrie irregolari: FORALL (i=1:N) B(i) = A(i,i) • nelle operazioni che utilizzano funzioni definite dall’utente: FORALL (i=1:N, j=1:M) A(i,j) = FUNZIONE(DATO1(1,j), DATO2(i,j)) Mauro Ennas Creative Commons 2013 4.3 Caratteristiche del linguaggio HPF 32 begin begin b[1] b[2] b[3] b[1] b[2] b[3] a[1] a[2] a[3] a[1] a[2] a[3] d[1] d[2] d[3] d[1] d[2] d[3] c[1] c[2] c[3] c[1] c[2] c[3] end end Figura 4.4: FORALL e ciclo DO a confronto. Possiamo confrontare un esempio di FORALL con un’esempio di ciclo DO, come mostrato in figura (4.4). Se un’iterazione scrive su una locazione appartenente ad una variabile riutilizzata nel ciclo e vogliamo che ciò non accada, dobbiamo fare uso della direttiva INDIPENDENT (figura (4.5)). Le librerie HPF possiedono un grande numero di funzioni, per la descrizione delle quali si rimanda alla lettura dei manuali dell’attuale versione dello standard del linguaggio (HPF Specifications v x.0) [1]. Un’inportante categoria di funzionalità intrinseche del linguaggio sono quelle per la distribuzione dei dati all’interno dei singoli processori. begin b[1] b[2] b[3] a[1] a[2] a[3] d[1] d[2] d[3] c[1] c[2] c[3] end Figura 4.5: Mauro Ennas La direttiva INDIPENDENT. Creative Commons 2013 4.3 Caratteristiche del linguaggio HPF 33 4.3.1 Il mapping dei dati Il cosidetto mapping consiste nella distribuzione dei dati all’interno dei processori per ottenere un agevole accesso parallelo agli stessi [3][2]. L’HPF utilizza due modalità per il mapping dei dati: • la distribuzione vera e propria viene attuata attraverso la direttiva al compilatore DISTRIBUTE che divide gli elementi di un oggetto tra i vari processori a disposizione, secondo modalità prestabilite; • l’allineamento dei dati ottenuto attraverso la direttiva al compilatore ALIGN che crea una relazione tra gli oggetti utilizzati nel calcolo. Il linguaggio prevede un’ulteriore livello di mapping che può essere proposto a cura dei progettisti delle varie versioni dei compilatori. Altre direttive sono Figura 4.6: Mapping dei dati dal modello astratto ai processori fisici. PROCESSORS che determina la forma della griglia di processori astratti e TEMPLATE che permette di agire sullo spazio degli indici per permettere allineamenti anche complicati [3]. Vi sono anche funzioni d’interrogazione che permettono di conoscere run-time alcune informazioni quali il numero di processori utilizzati e la forma della griglia fisica dei processori. La direttiva di distribuzione si esprime nel modo seguente: !HPF$ Mauro Ennas DISTRIBUTE A(tipo.distribuzione) Creative Commons 2013 4.3 Caratteristiche del linguaggio HPF 34 oppure !HPF$ DISTRIBUTE (tipo.distribuzione) :: A Il tipo.distribuzione può essere BLOCK, CYCLIC oppure * (leggi star). La dichiarazione seguente INTEGER, DIMENSION(100) :: A ....... !HPF$ DISTRIBUTE A(*) significa che tutti i 100 elementi del vettore A devono essere ricopiati (collassati) su ogni processore. Altri esempi di distribuzione sono ripor(BLOCK, *) (BLOCK,BLOCK) (*, CYCLIC) (CYCLIC(2), CYCLIC(4)) Figura 4.7: La direttiva di distribuzione dei dati DISTRIBUTE. tati in figura (4.7). Dalla distribuzione dei dati, oltre che dall’algoritmo, dipendono i tempi di comunicazione tra i processori, questo implica una dipendenza stretta tra la natura del problema che si vuole risolvere e l’implementazione data parallel che si è in grado di realizzare. Ci viene in aiuto la direttiva di allineamento ALIGN che permette di distribuire gli elementi Mauro Ennas Creative Commons 2013 4.3 Caratteristiche del linguaggio HPF 35 di un nuovo oggetto concordemente ad uno già distribuito e col quale si vuole che interagisca nelle varie fasi del calcolo. Per modificare gli assetti gia fissati durante l’esecuzione del programma si utilizzano direttive quali REDISTRIBUTE e REALIGN che, com’è facile supporre, utilizzano grossi intervalli temporali per la comunicazione tra i processori che si scambiano i dati da ridistribuire. Mauro Ennas Creative Commons 2013 Capitolo 5 Compilatori per macchine parallele 5.1 PGHPF Il compilatore utilizzato su IBM-SP2/30 è il compilatore commerciale HPF della Portland Group Inc. (PGI). Esso è implementato per funzionare su una grande varietà di architetture parallele (Intel-Paragon, Cray T3D e T3E, SGI-PowerChallenge) e risulta compatibile con ambienti distribuiti come i cluster di workstation. Il comando principale è pghpf (definito compilation driver); esso controlla le varie fasi della compilazione: la compilazione del linguaggio HPF vera e propria, la pre-elaborazione e la compilazione FORTRAN 77, l’assemblaggio e il collegamento (che include le routine del run time system PGI HPF). L’esecuzione di pghpf può essere effettuata su sistemi differenti e produce output per sistemi differenti, con comandi disponibili variabili da sistema a sistema. In generale, utilizzando pghpf, il processo di sviluppo e compilazione è costituito di tre fasi: • La prima fase è caratterizzata dalla produzione di un programma HPF (con estensione .hpf, .f90, .for, .F o .f) scritto per essere eseguito in parallelo. Mauro Ennas Creative Commons 2013 5.1 PGHPF 37 • La compilazione del programma HPF utilizzando il comando pghpf con le varie opzioni disponibili. Ciò permette di ottenere un file oggetto che include le librerie messe a disposizione dal run time system HPF. • L’esecuzione del modulo oggetto su un sistema target rappresenta la terza ed ultima fase. Il comportamento dell’ esecuzione può essere controllato sulla linea di comando o con variabili d’ambiente. Sono comunque possibile variazioni rispetto a questa sequenza generale di sviluppo che permettono, ad esempio, di fermare la compilazione nelle varie fasi intermedie per esaminare i risultati prodotti. Esistono tutta una serie di opzioni che possono essere abilitate o meno a seconda delle esigenze, queste caratteristiche non verranno evidenziate anche se hanno una grande importanza pratica nel processo di produzione del software. Il modello di riferimento è un modello SPMD (Single Program Multiple Data), ciò significa che ciascuno dei processori esegue lo stesso programma, ma su dati differenti (in pratica l’immagine dello stesso programma viene caricata su ogni processore). Ne consegue una allocazione della porzione di dati assegnata a ciascuno dei processori, in accordo con le direttive di distribuzione, con la dimensione delle matrici da distribuire e col numero di processori, determinata a run-time dal compilatore o utilizzando argomenti attraverso comandi in linea. Le librerie messe a disposizione attraverso pghpf tengono conto delle comunicazioni che devono essere attuate procedendo all’ottimizzazione a due livelli. Un primo livello che tiene conto della dimensione e geometria dei dati e dei processori coinvolti nel processo di calcolo (trasport indipendent level) ed un secondo livello (trasport dipendent level) nel quale si fa riferimento ad un protocollo standard di comunicazione oppure a particolari meccanismi di trasferimento dei dati. Mauro Ennas Creative Commons 2013 5.2 ADAPTOR 38 5.2 ADAPTOR Il traduttore ADAPTOR 1 (Automatic Data Parallelism TranslatOR) è un software applicativo public domain in grado di trasformare programmi scritti secondo il modello data parallel in FORTRAN 77 + estensioni (utilizzando le matrici generalizzate, cicli paralleli e direttive di distribuzione ed allineamento dei dati) in un programma parallelo con passaggio esplicito di messaggi (message passing) [10] [11]. Il linguaggio utilizzato nel programma d’ingresso può essere il CM FORTRAN o l’High Performance FORTRAN 2. Il codice che viene generato è un codice message passing che può esse- re eseguito su differenti sistemi multiprocessore a memoria distribuita ma anche a memoria condivisa o su architetture a memoria virtuale condivisa. ADAPTOR è costituito essenzialmente di due elementi, un nucleo di trasformazione da sorgente a sorgente denominato fadapt e la libreria del run time system DALIB (Distribuited Array LIBrary) [4]. Per compilare e collegare il Figura 5.1: La struttura di ADAPTOR. programma generato, viene utilizzato il compilatore FORTRAN disponibile 1 Progettato e realizzato da Thomas Brandes del GMD (German National Center of Mathematics and Computer Science) di Bonn. 2 Allo stadio attuale dello sviluppo del compilatore non tutte le direttive di questi linguaggi sono supportate. Mauro Ennas Creative Commons 2013 5.3 Prestazioni degli algoritmi paralleli 39 sulla macchina parallela utilizzata; fadapt genera due programmi, un programma host.f che gestisce le operazioni di I/O che devono essere eseguite dal nodo scelto come front-end del sistema e un programma node.f che verrà eseguito su ogni nodo disponibile della macchina. Vi sono anche altre due modalità di funzionamento, una delle quali genera solo il programma node.f utilizzando il primo nodo per le operazioni di I/O, l’altra è la modalità UNIPROC ossia il funzionamento sul nodo singolo, in quest’ultimo caso la traduzione produrrà un codice F77 sequenziale. 5.3 Prestazioni degli algoritmi paralleli Gli algoritmi sequenziali vengono valutati in termini di tempo di esecuzione in funzione della quantità di dati in ingresso. Nelle architetture parallele il tempo di esecuzione non dipende solo dalla mole di dati da elaborare ma soprattutto dal numero di processori e dal modo in cui tali processori interagiscono. La valutazione delle prestazioni degli algoritmi paralleli risulta strettamente legata all’architettura cui si fa riferimento. Un primo importante concetto è la cosidetta scalabilità di un algoritmo eseguito su una certa architettura, che rappresenta una misura della proporzionalità delle prestazioni in funzione del numero di processori che vengono utilizzati. Le prestazioni possono essere valutate in vari modi, attraverso degli indicatori dell’efficienza computazionale; i più usati sono il run-time, lo speed-up, l’efficienza e il costo [12] [5]. Run-Time. Per un programma seriale il run-time rappresenta il tempo totale di esecuzione Ts su un calcolatore sequenziale, mentre il run-time parallelo Tp rappresenta il tempo intercorrente tra l’avvio dell’esecuzione e l’istante in cui l’ultimo dei processori attivi termina l’esecuzione. Speed-up. Può essere indicativo sapere quali vantaggi possono aversi nel parallelizzare un codice implementati in modo sequenziale. Lo speed-up misura il guadagno che si realizza risolvendo il problema in parallelo e viene definito come il rapporto tra il tempo richiesto per risolvere il problema Mauro Ennas Creative Commons 2013 5.3 Prestazioni degli algoritmi paralleli 40 su un singolo processore e quello necessario per risolvere lo stesso problema su un calcolatore parallelo costituito da n processori identici . Dato un problema, possono esistere più soluzioni sequenziali dello stesso algoritmo, non tutte parallelizzabili allo stesso modo. In genere viene preso come riferimento, se esiste, l’algoritmo sequenziale più veloce e lo speed-up viene definito con riferimento ad esso e alla sua parallelizzazione: S(p) = |Ts |min Tp (n) ossia lo speed-up viene definito come il rapporto tra il run-time minimo (cioè relativo all’algoritmo seriale più veloce) ed il run-time parallelo dello stesso algoritmo su p processori identici al singolo processore utilizzato per il test sequenziale. Come esempio consideriamo un algoritmo che somma n numeri con n = 2k e k ∈ N ; consideriamo n processori che operano parallelamente in modo da effettura la somma totale per sucessive somme parziali di 2, 4, 8, ..2k elementi. Il tempo di calcolo seriale sarà una certa funzione di n, diciamo Y (n) mentre per l’algoritmo parallelo in questione sarà Y (log(n)). Lo speed-up lo indicheremo come: S(n) = Y (n) Y (log(n)) Efficienza. Un calcolatore parallelo ideale potrà eseguire un algoritmo operante su N dati con n processori in un tempo t∝ N , n ma ciò significherabbe considerare le comunicazioni istantanee e ciò nella realtà non è realizzabile. L’efficienza viene introdotta come indicatore della quantita di tempo nella quale il processore viene effettivamente utilizzato, definita come il rapporto tra speed-up e numero di processori: E= S . n Dall’esempio precedente risulta E = 1/Y (log(n)). Costo. Il costo necessario per risolvere un problema su un sistema parallelo viene definito come il prodotto tra il run-time ed il numero di processori utilizzati: C = Tp · n; Mauro Ennas Creative Commons 2013 5.3 Prestazioni degli algoritmi paralleli 41 viene anche indicato come lavoro o prodotto tempo-elaborazione. Overhead. La funzione di overhead tiene conto di quella parte del costo che non è dovuta all’elaborazione ma ad altri fenomeni come le comunicazioni. In pratica si considera qualla porzione di tempo in più rispetto al tempo necessario al più veloce algoritmo sequenziale per completare le elaborazioni. Se indichiamo con Tw il tempo del migliore algoritmo sequenziale, l’overhead risulta: To = n · Tp − Tw . Tipo Numero di Processori Velocità di calcolo tipiche Hitachi SR 2201 1024 1 TFLOPS Intel XP/S 3680 700 GFLOPS Cray T3D 1024 500 GFLOPS IBM SP2 512 440 GFLOPS SGI Power Challange 288 110 GFLOPS Cray2 4 1.6 GFLOPS Tabella 5.1: Prestazioni tipiche dei moderni calcolatori paralleli. 5.3.1 Modello semplificato per i tempi di calcolo Per un modello semplificato di programma parallelo avremo un tempo totale di esecuzione dato dall’espressione seguente: Ttot = Tseq + Tpar + Tcom p (5.1) nella quale Tseq tiene conto dell’eventuale presenza di parti esclusivamente sequenziali all’interno del codice (come accade generalmente per l’input e l’output dei dati), Tpar è il tempo impiegato da ciascuno degli n processori utilizzati nell’azione di calcolo, mentre il tempo Tcom tiene conto del tempo impiegato nella comunicazione tra processori e nella sincronizzazione dei processi e dei dispositivi. Mauro Ennas Creative Commons 2013 5.3 Prestazioni degli algoritmi paralleli Figura 5.2: 42 A B C D Comunicazioni: esempio di distribuzione (BLOCK,BLOCK). Le richieste di parallelismo e di minimizzazione del tempo Tcom possono ottenersi in modo spontaneo in certi problemi (embarrassingly parallel problems) come nel caso degli algoritmi di basso livello per l’elaborazione delle immagini o per i metodi di decomposizione (domain decomposition), ma nella maggioranza dei casi sono in conflitto tra loro in quanto il parallelismo estremo richiederebbe un processore per ogni stadio consistente di elaborazione mentre la minimizzazione delle comunicazioni richiederebbe di avere tutti i dati necessari ad una elaborazione distribuiti su un unico processore [3]. Soddisfare entrambe le condizioni significa rendere l’algoritmo sequenziale. I problemi di conflitto hanno la loro causa nella natura del problema, nell’architettura della macchina cui si fa riferimento e nel compilatore (soprattutto se in continua evoluzione, come nel caso dei compilatori HPF). Mauro Ennas Creative Commons 2013 Bibliografia [1] A.A.V.V. HPF - language specifications. Rice University, Huston Texas, 1993. [2] Erwing A.K., Richiardson H., Simpson A.D., and Kulkarni R. Writing Data Parallel Program with HPF. Edinburgh Parallel Computing Center, University of Edinburgh, 1995. [3] Koelbel C. HPF in Pratice. Rice University, 1996. [4] Greco D. and Cabitza G. HPParLib++ : a Run-Time System for High Performance Fortran. CRS4 TECH-REP-95/3, 1995. [5] Baiardi F., Tomasi A., and Vanneschi M. Architetture dei sistemi di elaborazione. Franco Angeli, 1991. [6] Kerrigan J. F. Migrating to Fortran 90. O’Reilly and Associates, Inc., 1993. [7] Hellis T. M. R. Fortran 77. Zanichelli, 1989. [8] Tanenbaum A. S. Architettura del computer - un approccio strutturale. Prentice Hall International - Jackson libri, 1991. [9] Agerwala T., Martin J.L., Mirza J.L., Sadler D.C., Dias D.M., and Snir M. SP2 system architecture. IBM Corporation, Vol. 34, No. 2 - Scalable Parallel Computing, 1995. [10] Brandes T. Compiling Data Parallel Programs to Message Passing, Programs for Massively Parallel MIMD Systems. German National Center of Mathematics and Computer Science, 1993. Mauro Ennas Creative Commons 2013 BIBLIOGRAFIA 44 [11] Brandes T. ADAPTOR - Users Guide - Version 2.0. German National Center of Mathematics and Computer Science, 1994. [12] Kumar V., Grama A., Gupta A., and Karypis G. Introduction to Parallel Computing. University of Minnesota, The Benjamin/Cummings publishing Company - Inc., 1994. Mauro Ennas Finito di stampare il 6 luglio 2013 utilizzando LATEX 2ε Creative Commons 2013