Scuol aPol i t ecni caedel l eSci enz edi Base Cor sodi Laur eai nI ngegner i aI nf or mat i ca El abor at ofinal ei n PROGRAMMAZI ONEI Aspet t iener get i cii npi at t af or medical col o et er ogeneo AnnoAccademi c o2014/ 2015 Candi dat o: Andr eaScognami gl i o mat r .N46001416 ... Ero così sicuro che al traguardo fossimo io e te ma il quadro è sempre perfetto se lo guardi da cento e un metri ... Ho sempre creduto che avrei condiviso con te la soddisfazione e la gioia di questo giorno. Non preoccuparti, però... una parte di te c'era e ci sarà sempre, indelebile nella mia mente. Ad Antonio... 1 Indice 1 Introduzione 3 1.1 Obiettivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Processi Tecnologici . . . . . . . . . . . . . . . . . . . . . . . . 3 1.3 Performance e Consumi 4 1.4 High Performance Computing 1.5 Architetture Eterogenee 1.6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 . . . . . . . . . . . . . . . . . . . . . 5 Overhead nei Processori Programmabili . . . . . . . . . . . . . 6 2 GPP 8 2.1 Storia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3 CPU Multicore . . . . . . . . . . . . . . . . . . . . . . . . . . 3 GPU 11 12 3.1 Storia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.2 Architettura e Parallelismo . . . . . . . . . . . . . . . . . . . . 14 3.3 Modelli di Programmazione 18 . . . . . . . . . . . . . . . . . . . 4 FPGA 25 4.1 Storia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 4.2 Origini - PLA e CPLD . . . . . . . . . . . . . . . . . . . . . . 25 4.3 Architettura . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 5 Ecienza Energetica 30 5.1 Energy Ecient System Design . . . . . . . . . . . . . . . . . 30 5.2 Consumo Energetico . . . . . . . . . . . . . . . . . . . . . . . 31 6 Energy Awareness nei Compilatori 33 6.1 Riduzione attività di Switching . . . . . . . . . . . . . . . . . 6.2 Allocazione Risorse . . . . . . . . . . . . . . . . . . . . . . . . 33 6.3 Power-Management a Run-Time . . . . . . . . . . . . . . . . . 34 6.4 Ottimizzazione dell'Instruction Set Architecture (ISA) 35 . . . . 7 Conclusioni 7.1 Confronto tra architetture 33 36 . . . . . . . . . . . . . . . . . . . . 8 Bibliograa 36 38 2 1 Introduzione 1.1 Obiettivi Il lavoro arontato da questo elaborato si propone di studiare varie piattaforme di calcolo, comprendendone la storia, la struttura e l'evoluzione. Successivamente vengono esposte le tecniche che ne permettono l'interazione, sotto forma di architetture eterogenee (spesso realizzate con tecnologia System-on-Chip). Dopo un'iniziale studio dell'evoluzione dei diversi processi tecnologici, del ruolo del consumo energetico e dei vantaggi ottenibili dall'uso combinato di dierenti sorgenti di calcolo, in piattaforme eterogenee, vengono arontate nel dettaglio tre diverse piattaforme: GPP, GPU e FPGA. In seguito, l'elaborato tratta l'impatto energetico sulle suddette tecnologie e delle possibili tecniche realizzabili per il miglioramento dei consumi, quali: riduzione attività di switching, allocazione risorse e power-management in fase di compilazione. Inne, anticipando le dovute conclusioni, vengono arontati i processi di Energy progettazione e sviluppo in ottica di risparmio energetico, come l' Eciency Systems Design e l'Energy Awareness nei compilatori. 1.2 Processi Tecnologici Nel 1965, Gordon Moore, co-fondatore della Intel, quanticò la straordinaria crescita della tecnologia dei semiconduttori in una altrettanto straordinaria analisi. Infatti, in seguito ad un approfondito studio durato circa 10 anni, Moore osservò che la densità dei Transistor all'interno dei chip raddoppiava ad intervalli regolari, e che questa crescita sarebbe continuata per lungo tempo. Quest'osservazione, nota come Legge di Moore, si è dimostrata valida per un periodo oltre i 40 anni e si basava sulla continua evoluzione nel campo dei semiconduttori, dei transistor e dei circuiti integrati. L'invenzione del Circuito Integrato, risalente al 1958, permise la realizzazione di un chip composto da diversi transistor. Una proprietà che n da subito colpì l'intero mondo dell'elettronica, perché permise la realizzazione di chip con un sempre crescente numero di transistor pur tenendo praticamente invariato il costo di fabbricazione. Per avere un'idea dell'evoluzione del numero di transistor nei microprocessori negli anni, in Figura 1 riportiamo alcuni prodotti della Intel. Negli ultimi anni, le performance dei processori sono andate stabilizzandosi e sono emersi nuovi fattori che hanno iniziato a mettere in discussione una legge che sembrava essere immutabile. Ad esempio, la Frequenza di Clock nei processori, è rimasta invariata nel corso degli ultimi 5 anni. In realtà, Intel nel 2001 stimò che la frequenza dei processori sarebbe arrivata intorno ai 30GHz, ma nel 2005 l'azienda stessa cambiò radicalmente direzione, bloccando l'evoluzione della frequenza di clock ed adandosi a dierenti tecnologie per evolvere e migliorare i propri processori. La causa principale che ha portato le varie aziende (Intel, AMD) ad interrompere il trend di crescita riguardante la frequenza di clock ha a che fare con il Consumo Energetico dei calcolatori e con la Dissipazione di Calore. 3 Inoltre, con l'introduzione di CPU Multicore è risultato inutile aumentare a dismisura la potenza dei microprocessori quando risultava più semplice raggiungere lo stesso livello di performance aumentandone il numero. Nei Multicore, ogni Core dispone della propria pipeline di esecuzione ed è in grado di portare avanti in maniera autonoma l'esecuzione di un thread. Inoltre, questo tipo di processori sposano perfettamente la losoa Multitasking dei comuni sistemi operativi, nei quali la parallelizzazione delle operazioni trova maggior vantaggio rispetto alla loro esecuzione sequenziale. Figura 1: Numero di transistor nei processori Intel 1.3 Performance e Consumi Al crescere delle Performance, anche i Consumi incominciano ad essere rilevanti, se non per dispositivi per quelli Fissi, quali Desktop PC Mobili, come Smartphone o Mainframe, ma o Portatili. Inoltre il mercato richiede sempre più una stretta collaborazione tra quello che è il mondo dell'informatica e della tecnologia e quello di moda e arte. Uno Smartphone al giorno d'oggi, non deve essere solo funzionale e performante, ma deve essere anche leggero e fashionable . Per soddisfare i sempre più stringenti requisiti dei dispositivi mobili, la crescita della capacità delle batterie è stata fortemente limitata, come si evince dalle speciche degli Iphone degli ultimi 10 anni, in Figura 2. Questo trend ha obbligato i progettisti dei sistemi embedded a sviluppare sistemi HPC (High Perfomance Computer) con una sempre più bassa quota di energia a disposizione, rendendo l' Energy Eciency un aspetto fondamentale del processo di progettazione di sistemi embedded. 4 Figura 2: Speciche di Iphone di diverse generazioni 1.4 High Performance Computing In informatica con il termine High Performance Computing (HPC) ci si riferisce alle tecnologie utilizzate da computer cluster per creare dei sistemi di elaborazione in grado di fornire delle prestazioni molto elevate nell'ordine dei PetaFLOPS, ricorrendo tipicamente al calcolo parallelo. Il termine è molto utilizzato essenzialmente per sistemi di elaborazioni utilizzati in campo scientico. Il modello di calcolo ad alte prestazioni, HPC, è nato a partire dagli anni '90, e si basava sui processori tradizionali, cioè su CPU, che garantivano un continuo miglioramento grazie all'adabilità della legge di Moore. Tuttavia, quando la legge di Moore ha incominciato a mostrare i propri limiti, nell'ultimo decennio circa, ci si è diretti verso soluzioni Multicore e architetture Eterogenee. 1.5 Architetture Eterogenee Architettura Eterogenea più dispositivi HW, spesso saldati su uno o più SoC (system-on-a-chip), interagiscono e collaborano al ne di In una eseguire il maggior numero di task nel più breve tempo possibile. Nelle architetture Eterogenee tipicamente viene aancato al tradizionale processore multicore, un coprocessore (o acceleratore) in grado di fornire elevate prestazioni a consumi contenuti. Questo tipo di soluzioni sono più performanti rispetto ai classici modelli a Singolo Processore, però richiedono un maggior impegno nella fase di progettazione e soprattutto di programmazione. Infatti, basti pensare che non è possibile adottare un unico standard di programmazione ad alto livello (C o C++), che discerne dalla particolare architettura, poiché spesso i programmatori HPC sono riluttanti a sacricare le prestazioni in cambio di una maggiore facilità di programmazione. Un'altra problematica legata alle architetture eterogenee è dovuta all'abitudine dei programmatori a ragionare in modo sequenziale. Infatti, anche se parte della conversione da software applicativo sequenziale a parallelo può essere eseguita in maniera automatica, ai programmatori resta il compito di parallelizzare manualmente quegli algoritmi che sono stati pensati in modo essenzialmente seriale. 5 1.6 Overhead nei Processori Programmabili La Figura 3 mostra il trade-o che c'è tra essibilità ed ecienza nella progettazione di sistemi di calcolo. Figura 3: Trade-o tra l'ecienza e la essibilità Infatti, in funzione di quale dei due aspetti vogliamo maggiormente enfatizzare, la scelta del progettista ricade su una dierente famiglia di architetture. In generale possiamo classicare ogni architettura in due classi: Special Purpose e General Purpose. ASIP e ASIC appartengono alla prima classe e rappresentano degli approcci altamente specici, volti alla risoluzione di un unico problema. Consentono di raggiungere delle prestazioni in termini di velocità di processamento e consumo elettrico dicilmente ottenibili con l'uso di soluzioni general purpose, quali FPGA, GPU e GPP. Per raggiungere un alto livello di ecienza quindi, si implementano circuiti integrati ad-hoc per le varie applicazioni (ASICs - Integrated Circuits). Application Specic In questi circuiti però, l'alto livello di ecienza si contrappone con la quasi totale mancanza di essibilità. Infatti, in architettura ASIC, dopo che il circuito è stato progettato e stampato per una particolare applicazione, non può essere più riadattato per svolgere compiti diversi da quelli per cui è nato. Tale mancanza di essibilità è un punto a sfavore per questo tipo di soluzioni, dal momento che nei moderni dispositivi embedded, uno dei requisiti fondamentali è la capacità di evolvere velocemente in funzione del mercato o degli utenti stessi. L'altra faccia della medaglia è invece composta da piattaforme perfettamente programmabili, che quindi assicurano la massima essibilità possibile, a scapito dell'ecienza stessa. General Purpose Processors, categoria di cui fanno parte anche le CPU, forniscono la miglior essibilità, permettendo l'esecuzione virtuale di ogni tipo di applicazione, al costo di avere performance decisamente minori e costi energetici molto più elevati. Il gap di ecienza energetica tra architetture General Purpose Processors (GPPs) e Application Specic Integrated Circuits (ASICs) è enorme. Infatti le GPPs possono consumare no a qualche ordine di grandezza in più di un ASIC che svolge lo stesso onere computazionale. 6 Quest'enorme divario energetico, dovuto all'overhead presente nell'architettura GPP, risiede nella presenza di risorse e istruzioni che hanno lo scopo di gestire e eseguire operazioni per più e diversi tipi di applicazioni. ASICs e GPPs sono gli estremi di questo compromesso tra ecienza e essibilità. Esistono altri tipi di architetture che orono un compromesso diverso rispetto ai due precedenti. Application Specic Instruction-Set Processors (ASIPs) adattano l'ISA (Instruction Set Architecture) per uno specico set di applicazioni, allo scopo di incrementare l'ecienza di un processore a livelli paragonabili ad un'architettura ASIC. Field Programmable Gate Array (FPGA) ore un'elevata essibilità attraverso un livello hardware strutturato a blocchi ricongurabili. Graphics Processing Units (GPUs), progettate inizialmente per il rendering graco, al giorno d'oggi trovano applicazione anche in altri domini applicativi, specialmente in quelli scientici. 7 2 GPP L'unità di elaborazione centrale (CPU - Central Processing Unit) è una tipologia di processore digitale general purpose. Per semplicità il seguente capitolo non convergerà sulle GPP, ma sulle CPU che sono nient'altro che una loro specializzazione. 2.1 Storia La storia della Central Processing Unit è concentrata in un tempo relativamente breve, e nonostante ciò, ha rivoluzionato quasi ogni aspetto delle nostre vite. Nei primi anni '70, l'Intel produsse l' Intel 4004 (Figura 4 ), il primo microprocessore monolitico (cioè interamente contenuto in un solo circuito integrato) della storia ad essere commercializzato. La massima frequenza di clock raggiungibile da questo rivoluzionario dispositivo era 740KHz, una velocità sorprendente a quei tempi, che permetteva l'esecuzione di 92.000 istruzioni al secondo, e composto da circa 2.300 Transistor. Figura 4: Intel 4004, 1971 L'Intel già dominava il mercato delle CPU quando, nel 1993, uno dei più popolari esemplari di CPU nella storia fu reso disponibile al mercato, il processore Intel Pentium. Figura 6: AMD Am5x86, 1995 Figura 5: Intel Pentium, 19921993 Questo dispositivo leggendario operava ad una frequenza di clock di 60MHz, per un totale di circa 100 milioni di istruzioni al secondo (60 MIPS). L'assoluto predominio del mercato e totale solitudine nell'innovazione tecnologica nel campo dei processori da parte dell'Intel continuò per molti 8 anni, no all'uscita, nel 1995, del competitor, la AMD. AM5x86, processore del suo maggior A seguire, Intel e AMD hanno segnato la storia dei microprocessori, producendo dispositivi sempre più veloci e performanti. La successiva pietra miliare nella storia delle CPU fu il rilascio commerciale del primo processore da 1GHz. AMD Athlon, nel 1999, e a Intel Premium III circa due anni dopo. Questo obiettivo fu raggiunto prima dall' seguire dall' Attualmente è comune avere una CPU la cui frequenza di clock supera di molto 1GHz, anche in dispositivi mobili quali smartphone e tablet. In appena 40 anni infatti siamo passati da una tecnologia che lavorava a 740KHz ad una che raggiunge diversi GHz di velocità, si è ottenuto un incremento del numero di transistor sul singolo chip da 2.300 a piu di un miliardo di unità. In oltre, da qualche anno a questa parte, Intel e AMD hanno smesso di trarre dal singolo processore sempre più prestazioni, e si stanno spingendo verso la computazione parallela, con l'utilizzo di multicore sullo stesso chip. 2.2 Architettura Esistono diversi aspetti primari di cui i progettisti devono tener conto nella creazione di una CPU, e alcuni di questi sono: data paths, control unit, supporti di memorizzazione, circuiteria del clock e logic gate cell library. Il data path è un insieme di unità di calcolo, come ad esempio le unità di elaborazione (ALU), i registri e i moltiplicatori necessari per l'esecuzione delle istruzioni nella CPU. La control unit, invece, è specializzata nel gestire l'interazione tra data paths e la memoria principale. É la componente delle CPU che ha il compito di coordinare tutte le azioni necessarie per l'esecuzione di una o più istruzioni e dà la possibilità al microprocessore di eseguire istruzioni diverse. Per quanto riguarda i supporti di memorizzazione, al giorno d'oggi, le CPU dispongo di diversi tipi di moduli di memoria integrati sul chip. Tra queste le più popolari sono i Registri e le Cache, entrambe memorie ad alta velocità, di tipo SRAM (Static Random Access Memory). I registri sono celle di memoria strutturate stesso all'interno della CPU e contengono dati vitali per il corretto svolgimento delle operazioni eseguite dalle stesse. Le cache, tipicamente, sono delle memorie interposte tra la CPU e la memoria principale. Possono essere di livello uno (L1) e di livello due (L2), sono di capienza inferiore rispetto alla memoria principale e il loro utilizzo è più conveniente in termini di tempo di accesso e/o carico sul sistema. Quando è necessario l'accesso ad un dato, una sua copia viene prima cercata nella cache. Se è presente e valida, viene utilizzata tale copia. Altrimenti il dato viene recuperato dalla memoria principale, e memorizzato nella cache, nel caso possa servire successivamente. Il clock della CPU è un segnale periodico, tipicamente generato da un oscillatore a cristalli. É ottenuto trasformando un'onda sinusoidale in una quadra e viene utilizzato per sincronizzare le componenti interne della CPU. 9 Inne, con logic gate cell library intendiamo una collezione di porte logiche utilizzate per implementare la logica computazionale nelle CPU, che consistono di alcune funzioni di basso livello quali AND, OR, INVERT, Flip Flop, Latches e Buers. Per dare un'idea, riportiamo in Figura 7 l'architettura dell'AMD K10, prodotto nel 2007. Figura 7: Architettura AMD K10 10 2.3 CPU Multicore Uno degli aspetti principali sui quali si basa l'evoluzione dei microprocessori è l'utilizzo di soluzioni Multi-Core. Il termine multicore viene utilizzato per indicare una CPU composta da 2 o più core, ovvero da più nuclei di processori sici montati sullo stesso package. Attualmente le soluzioni presenti sul mercato comprendono architetture con 2, 4, 8 e 16 core. Questi tipi di architetture, rispetto alla single core, consentono di aumentare la potenza di calcolo di una CPU lasciando invariata la frequenza di clock di lavoro, a tutto vantaggio del calore dissipato (che diminuisce rispetto al caso di più processori separati) così come dell'energia assorbita. I beneci del Multicore derivano dalla possibilità di aumentare le performance attraverso il processing parallelo, basandosi sul principio che un problema grande può essere facilmente risolto scomponendolo in più problemi, minori, risolvibili concorrentemente. In Figura 8, un esempio di architettura quad-core, l'Intel I7 950. Figura 8: Intel I7 950, 2009 In passato, l'uso del calcolo parallelo era attribuito ad applicazioni di fascia alta, per la risoluzione di complessi problemi matematici, o comunque in campi scientici quali la sica, l'ingegneria o la meteorologia. Oggi, invece, grazie all'aumento di applicazioni commerciali e all'abbattimento dei costi per la produzione dei complessi circuiti integrati, il calcolo parallelo si è diuso anche nei comuni dispositivi elettronici quali smartphone, tablet e PC. 11 3 GPU L'unità di elaborazione graca GPU - Graphics Processing Unit è una tipologia particolare di coprocessore che si contraddistingue per essere specializzata nel rendering di immagini grache. Come è stato dichiarato dal Prof. Jack Dongarra, le GPU si sono evolute al punto che molte applicazioni del mondo reale possono essere facilmente implementate su di esse e possono essere eseguite in maniera signicativamente più veloce rispetto ad un'architettura multicore. I sistemi di calcolo futuri saranno una soluzione basata sul lavoro combinato tra Parallel-Core GPUs e Multi-Core CPUs. 3.1 Storia Le GPU si sono evolute rapidamente negli ultimi 30 anni, dalla loro prima introduzione al mercato. Nonostante l'enorme sviluppo che le ha riguardate, le GPU trovano principale applicazione nel mondo del processing delle immagini. La comparsa delle prime unità grache risale agli anni '80, quando sia Intel che IBM introdussero prodotti specializzati nel mercato. Anche altre compagnie si mossero in tal direzione, come Commodore e Texas Instrument, che aggiunsero semplici funzionalità grache sui loro chip ed introdussero delle prime e basiliari schede esterne. Tali schede erano molto costose e realizzavano funzionalità molto semplici, quali riempire un'area, disegnare una forma e modicare immagini elementari. Figura 9: S3 S386C911, 1991 Gli anni '90 sono stati il vero e proprio punto di partenza per quanto riguarda il decollo delle GPU. Nel 1991, S3 Graphics ha introdotto il primo acceleratore 2D su singolo chip, l'S3 86C911 (Figura 9 ). La corsa alla graca 2D ha caratterizzato questo decennio, imponendo come nuovo obiettivo delle aziende leader nel campo il processing in 3-Dimensioni. Verso la ne degli anni '90, il rendering 3D era possibile, ma solo attraverso l'assistenza delle CPU (soluzione conosciuta come graca 3D-assistita). Per supportare la diusione delle schede grache, in questo stesso periodo, nacquero diverse collezioni di API, quali OpenGL e DirectX. Ben presto, tali librerie implementarono anche funzionalità per il supporto della Trasformazione e Illuminazione (T&L - Transform & Lighting), caratterizzando un enorme salto in avanti nel GPU processing. 12 Transform è il task che permise la produzione di un immagine 2D a partire da una scena tridimensionale. Lighting, invece, consentì l'alterazione dei colori delle varie superci delle scene, in funzione delle informazioni sull'illuminazione. Nel 1999, con l'uscita sul mercato della GeForce 256, fu introdotta la prima generazione di schede grache GeForce prodotte dalla NVIDIA Corporation, pensate appositamente per la graca 3D. Figura 10: NVIDIA GeForce 256, 1999 Dall'uscita delle prime schede ad oggi, sono straordinari i miglioramenti avuti nel rendering 3D delle GPU, spesso guidati da ATI e NVIDIA, che tuttora detengono la maggior parte della quota di mercato nel processing graco e che, di conseguenza, impongono le direzioni in cui evolvere. Un'altra chiave di volta nell'evoluzione delle GPU fu la nascita del PCI Express (Peripheral Component Interconnect Express), ucialmente abbreviato in PCIe (in Figura 11 ). Il PCI Express è uno standard di interfaccia d'espansione a bus seriale per calcolatori che garantì velocità di trasferimento molto superiori e permise l'utilizzo di schede grache con maggior richiesta energetica. Tali beneci portarono alla costruzione di chip graci molto più evoluti dei precedenti ed aprirono la strada ad una sempre più realistica graca, in continuo sviluppo, sia per usi professionali che domestici. Una delle principali e più recenti innovazioni portate dal nuovo millennio, relativa all'uso delle GPU, è stata il GPU (GPGPU). General Purpose Computing on Quest'ultimo nasce dall'idea di porre l'intenso parallelismo e l'elevata potenza di calcolo, messi a disposizione dalle GPU, al servizio, non solo di applicazioni grache, ma anche di applicazioni general purpose, che vanno da un uso scientico ad uno puramente più commerciale. In tale ambito di utilizzo la GPU viene impiegata per elaborazioni estremamente esigenti in termini di potenza di calcolo, e per le quali le tradizionali architetture di CPU non hanno una capacità suciente. Tale tipo di elaborazioni sono, per loro natura, di tipo altamente parallelo, e in grado quindi di beneciare ampiamente dell'architettura tipica delle GPU. A tale caratteristica intrinseca, negli ultimi tempi si è aggiunta l'estrema CUDA e OpenCL), che al succedersi delle generazioni aumentano non solo la programmabilità oerta dalle ultime soluzioni commerciali ( propria potenza elaborativa ma anche la propria versatilità. 13 Figura 11: Partendo dall'alto: Slot PCI Express x4, x16, x1, x16 e uno slot PCI tradizionale a 32 bit 3.2 Architettura e Parallelismo Per comprendere al meglio la seguente sezione, analizzeremo l'architettura di un generico processore graco moderno, in Figura 12. Figura 12: Architettura di una GPU moderna Le GPU sono coprocessori e in quanto tali devono essere connesse ad un processore tradizionale, chiamato Host. Generalmente il collegamento tra i dispositivi è realizzato con un bus PCI Express ad alta velocità, che consente il trasferimento di dati dalla memoria della GPU a quella della CPU e viceversa. In architetture particolari, quali ad esempio gli smartphone, invece, ci sono veri e propri System-on-Chip che incorporano tutti gli elementi in unico package, in modo da massimizzarne la velocità di comunicazione. 14 Le GPU dispongono di un alto grado di parallelismo, in particolare nella struttura dei diversi dispositivi di memorizzazione e nella disposizione dei core d'esecuzione. Ogni GPU è composta da diverse unità di elaborazione, chiamate Streaming Multiprocessor (SM), che rappresentano il primo livello logico di parallelismo. Ogni SM è a sua volta suddiviso in un gruppo di Streaming Processor (SP), ognuno dei quali è un core d'esecuzione reale, in grado di eseguire sequenzialmente un thread. Gli SM sono a loro volta organizzati in una serie di CLuster (TPC). Thread Processing Figura 13: Da sinistra, la struttura di un SM e quella di un TPC In Figura 13, a sinistra è mostrata la struttura di un SM, contenente al suo interno 8 processori scalari, una memoria condivisa, registri, 2 unità (SFU) dedicate all'esecuzione di funzioni speciali e una DPU, un'unità dedicata al calcolo in precisione doppia. A destra è invece mostrato un esempio di Thread Processing Cluster, formato da 3 SM, con memorie cache condivise tra il TPC e memorie dedicate alla gestione di texture. In questo senso l'architettura di una GPU rientra nella classicazione SIMD (Single Instruction Multiple Data), in quanto una singola istruzione viene eseguita parallelamente da più unità di elaborazione che operano su insiemi di dati diversi. Lo Streaming Multiprocessor gestisce una serie di thread raggruppandoli in unità chiamate warp. Ogni Thread all'interno di un warp esegue lo stesso insieme di istruzioni in maniera del tutto indipendente, richiedendo però che tale esecuzione sia sincronizzata. Infatti è presente una forma di sincronizzazione forzata (lockstep ), adata ad un componente chiamato warp scheduler. Ogni GPU ha a disposizione diversi tipi di memoria, ognuna delle quali è localizzata in dierenti aree del dispositivo, possiede caratteristiche diverse e può essere utilizzata per compiti dierenti. L'unità di memoria più capiente è la cosiddetta memoria globale, che nelle GPU di ultima generazione raggiunge dimensioni di diversi GB e comporta una latenza piuttosto elevata. Tutti i Core della GPU possono accedere a questo spazio di memoria, così come può fare anche l'host, collegato direttamente al dispositivo di 15 memorizzazione. Non essendo particolarmente veloce, la memoria globale spesso dispone di meccanismi di ottimizzazione degli accessi o di livelli di cache, che consentono una comunicazione più eciente. Un altro spazio di memoria condivisa da tutti i core è la texture memory, utilizzata dal processore graco in sola lettura. Questo tipo di memoria dispone di specici meccanismi di caching che la rendono eciente nella memorizzazione di strutture bidimensionali (matrici o immagini) e nell'accesso ad elementi spazialmente vicini. All'interno di ogni SM, inoltre, è presente uno spazio di memoria condiviso tra i core che compongono un gruppo di lavoro. Questa memoria è decisamente più veloce di quella globale ma ha dimensioni molto più ridotte, dell'ordine di qualche decina di MB per ogni SM, e viene genericamente utilizzata per memorizzare valori che devono essere usati più volte, da core diversi, limitando il numero di accessi in memoria globale. Gli aspetti negativi della condivisione di questo spazio di memoria riguardano la loro coerenza, che deve essere mantenuta per evitare l'uso di valori errati o non più validi. Inne, ogni SM dispone di un certo numero di registri interni, che rappresentano uno spazio di memorizzazione locale, ad accesso rapido e di dimensioni limitate, che consentono la memorizzazione di valori frequentemente usati da un singolo core. Esempio: Architettura NVIDIA Fermi Come esempio di prodotto commerciale presentiamo l'architettura NVIDIA Fermi. Figura 14: Architettura NVIDIA Fermi Al suo interno sono presenti 16 Streaming Multiprocessor e il supporto di una quantità di memoria DRAM no a 6GB GDDR5 (Graphics Double Data Rate). 16 La GPU è connessa alla CPU tramite un bus PCI Express 2.0 x16 ad alta velocità (no a 8 GB/s). All'interno di ogni SM troviamo 32 core (SP), che permettono a quest'architettura di usufruire in parallelo di un massimo di 512 Cuda Cores (16 SM x 32 SP). É inoltre presente una memoria condivisa, cache L1 da 64 KB totali, per permettere la comunicazione tra i diversi threads, ed una L2, sempre condivisa, di 768 KB. L'architettura Fermi dispone di un Dual Warp Scheduler, che permette l'esecuzione di due warp concorrentemente, delegando ciascuna istruzione di essi ad un gruppo di 16 core. La frequenza di clock di 1.5 GHz permette di raggiungere una prestazione massima di 1.5 TFlop/s, con una larghezza di banda di 192 GB/s. Figura 15: Struttura SM dell'architettura Fermi 17 3.3 Modelli di Programmazione Il paradigma di programmazione che caratterizza il calcolo su GPU è chiamato Stream Processing, perché i dati possono essere visti come un usso omogeneo di valori ai quali vengono applicate in maniera sincrona le stesse operazioni. Le funzioni che processano i dati nello stream e che sono eseguite sulla GPU prendono il nome di kernel e svolgono un insieme abbastanza limitato di operazioni su ogni usso di dati. • Operazioni di copia : tutti gli elementi sono copiati da uno stream ad un altro. • Operazioni di ltraggio : alcuni elementi di uno stream sono selezionati in base a determinate caratteristiche e copiati. • Operazioni di accesso : si accede ad uno specico elemento dello stream utilizzando un indice. • Operazioni di calcolo : vengono eettuati calcoli sugli elementi di uno stream. In tale modello di programmazione, un main è in esecuzione sull'host (CPU) e gestisce il parallelismo assegnando le varie istanze del kernel a stream diversi. La struttura di funzionamento di un kernel segue quasi sempre uno schema preciso. Innanzitutto viene caricato nella memoria della GPU un usso di dati (input) sul quale il kernel applica una serie di operazioni che producono un usso di dati in uscita (output). Sarà poi compito dell'host prelevare l'output generato dalla GPU accedendo alla sua memoria globale. Il grande aumento di performance presentato dalle GPU nell'ultimo decennio, come già sappiamo, ha spinto il mondo scientico a fare uso di questi dispositivi anche per la risoluzione di problemi General Purpose (GPGPU). Questo ha consentito la nascita e il rapido sviluppo di diversi linguaggi di programmazione per l'ambiente graco. Il GPGPU ha preso veramente il via quando, nel 2006, vennero presentati CUDA e Stream, due interfacce per la programmazione graca progettate rispettivamente da NVIDIA e AMD. Qualche anno più tardi nacque anche il progetto OpenCL, con lo scopo di realizzare un framework d'esecuzione eterogeneo sul quale potessero lavorare sia GPU che CPU. Col passare del tempo questi linguaggi si sono evoluti a tal punto da essere simili ai diusi linguaggi di programmazione general purpose quali C, C++, Java, Fortran e simili. Tuttora CUDA e OpenCL rappresentano le soluzioni più ecienti e diuse per la programmazione general purpose di processori graci. CUDA CUDA, acronimo di Computer Unifed Device Architecture, è un framework ideato da NVIDIA nel 2006. É un'architettura di calcolo parallela general purpose che fornisce un'interfaccia di programmazione 18 (API) orientata al calcolo, senza esplicito riferimento ad operazioni grache, nonché un compilatore apposito ( nvcc). Nel toolkit CUDA è presente anche un ambiente di sviluppo integrato ( Nsight) ed una serie di librerie specializzate come cuBLAS per svolgere operazioni di algebra lineare, cuSPARSE per lavorare su matrici sparse, cuFFT per il calcolo della Fast Fourier Transform e THRUST, che è essenzialmente una versione della STL del C++ ottimizzata per GPU. Nonostante CUDA sia una soluzione proprietaria, non è detto che tutte le GPUs che supportano tale framework abbiano la stessa architettura. É possibile, infatti, che esse dieriscano ad esempio per il numero di core presenti sul chip. Per evitare eventuali problemi di portabilità delle applicazioni, NVIDIA propone con CUDA un modello altamente scalabile in grado di adattarsi senza dicoltà a tutti i chip graci che supportano tale framework. Figura 16: Struttura scalabile del paradigma CUDA L'idea di base è quella di suddividere il carico di lavoro partizionando un programma multithread in una serie di blocchi paralleli ed indipendenti tra loro formanti una griglia e contenenti i vari threads. In questo modo ogni programma compilato in CUDA si adatterà runtime all'architettura su cui è in esecuzione, in modo del tutto trasparente rispetto al numero di core presenti. Il programmatore, infatti, setta una congurazione di esecuzione su un certo numero di blocchi, ma solo a tempo di esecuzione la suddivisione logica in blocchi corrisponderà all'assegnazione sica agli Streaming Processors presenti sulla GPU, come mostrato in Figura 16. E' facile intuire che se un chip graco possiede più SM rispetto ad un altro, esso elaborerà i processi in maniera più rapida. La griglia di blocchi in cui è diviso il programma può essere monodimensionale (vettore) o bidimensionale (matrice). Per quanto riguarda il singolo blocco, possiamo trovare una struttura monodimensionale, bidimensionale o tridimensionale (cubo) di thread (no ad un massimo di 1024 unità). 19 Nell'esecuzione i blocchi sono indipendenti tra loro, mentre i thread a loro appartenenti cooperano accedendo agli stessi dati e processandoli in maniera sincrona. A ciascun blocco e a ciascun thread è associato un ID che ne permette l'identicazione. Figura 17: Struttura dei blocchi in CUDA La gerarchia di thread, presente nel paradigma di programmazione CUDA, permette anche una gestione più eciente dei vari strati di memoria. Infatti, come mostrato in Figura 18, anche le memorie assumono una struttura gerarchica. Ogni thread ha un'area di memoria locale, privata e non condivisa. Per ogni blocco, viceversa, c'è una memoria condivisa (Shared Memory ), accessibile da tutti i suoi thread. Inne, è presente un'area di memoria globale, sempre condivisa ed usufruibile da tutti i thread della griglia. In conclusione, la piattaforma CUDA è progettata per essere utilizzata esclusivamente con processori graci prodotti da NVIDIA, caratteristica che ne limita l'impiego in misura considerevole. D'altra parte questo vincolo si trasforma in vantaggio qualora si prendono in considerazione le prestazioni, che sono indiscutibilmente migliori, data la nativa predisposizione di questo paradigma per architetture NVIDIA. 20 Figura 18: Divisione memorie in CUDA OpenCL OpenCL ( Open Computing Language) è un framework per lo sviluppo di applicazioni eseguibili su architetture eterogenee progettate in maniera indipendente rispetto all'hardware scelto. Infatti è possibile eseguire il codice su dispositivi come CPU, GPU, DSP e FPGA, anche se prodotti da aziende diverse. Questa soluzione, sviluppata e tenuta in commercio da un consorzio no-prot chiamato Khronos Group è l'alternativa principale al framework proposto da NVIDIA nel campo del GPU computing (CUDA). Tuttavia, OpenCL basa la sua strategia di mercato su un'idea radicalmente opposta a quella usata da CUDA. Infatti mentre quest'ultima propone come suo punto di forza la specializzazione dei prodotti (architettura ideata, sviluppata e compatibile solo con NVIDIA) garantendo ottime prestazioni a discapito della portabilità su architetture diverse, OpenCL invece propone una soluzione compatibile con più dispositivi plurimarche presenti sul mercato, come ad esempio Intel, NVIDIA, IBM e AMD, ma con prestazioni inferiori. Il modello di programmazione di OpenCL per alcuni versi è molto simile al paradigma introdotto da CUDA, a meno dell'uso di una dierente terminologia. Richiede la presenza di un processore Device. Host collegato ad uno o più OpenCL Compute Units, che a loro volta devono essere viste come una serie di Processing Element. Ciascun device, inoltre, deve essere inteso come un aggregato di Considereremo come Device una GPU, così da associare gli elementi studiati nel paradigma CUDA, con i corrispondenti OpenCL. In particolare, le Compute Unit coincidono con gli Streaming Multiprocessor e i Processing Element con gli Streaming Processor. 21 Figura 19: Architettura OpenCL Il modello di esecuzione proposto da OpenCL si presenta diviso in due parti: il programma Host eseguito dalla CPU e il kernel eseguito dalle Device. Un principio fondamentale su cui si basa tale paradigma è che il kernel deve essere sempre denito all'interno del contesto gestito dall'Host. Il contesto comprende: • Device accessibili dall'host. • Funzioni Kernel con il valore dei relativi argomenti, tutti contenuti all'interno di strutture chiamate Kernel object. • Program objects, consistente del codice sorgente e dell'eseguibile del programma che implementa il Kernel. • Memory objects, ovvero una serie di oggetti di memoria visibili all'host e alle devices durante l'esecuzione del kernel. Le interazioni tra Host e Device avvengono attraverso le code di comandi command-queue), le quali vengono associate una ad ogni device. ( I comandi che possono essere inviati dall'Host si dividono in 3 categorie: kernel enqueue commands (comandi per l'inserimento in coda di un kernel), memory commands (comandi per il trasferimento di dati tra host e device) e synchronization commands (comandi per la sincronizzazione dell'esecuzione). La coda di comandi può essere risolta sia seguendo l'ordine di ricezione in-order execution) e sia in maniera random (out-of-order execution). ( Nell'istante in cui viene inviato il comando di esecuzione di un kernel viene denita anche la sua matrice di esecuzione, ovvero uno spazio di indici N-dimensionale denominato NDRange (N-Dimensional Range con N=1,2,3), la quale permette di suddividere ecientemente l'onere computazionale sul device. Infatti un kernel object, viene eseguito in un numero variabile di work-group, contenenti a loro volta i work-item, ovvero le istanze di esecuzione del kernel. E' possibile identicare i work-item o tramite un ID globale o tramite una coppia di ID formata dall'ID del work-group e dall'ID locale del work-item all'interno del gruppo. 22 Il programmatore può denire l'NDRange tramite 3 vettori di interi: • Grandezza dello spazio globale in ciascuna dimensione (G); • Un oset che setta il valore iniziale degli indici in ciascuna dimensione (F); • La grandezza dei work-group in ogni dimensione (S); Figura 20: Esempio di NDRange L'operazione di suddivisione del carico di lavoro in diversi work-group, tenendo conto della capacità di calcolo parallelo del dispositivo in uso, risulta essere uno dei parametri essenziali per il raggiungimento di ottime performance durante l'esecuzione delle applicazioni. Questa organizzazione elaborativa, inoltre, comporta una gerarchia di private memory e sia un accesso alla local memory, condivisa da tutti gli memoria piuttosto particolare: ogni work-item possiede sia una elementi appartenenti al work-group. memoria globale e sia ad una riservata alle costanti (global/constant memory), Inoltre ogni work-item è in grado di accedere sia ad un'area di entrambe condivise da tutti i devices presenti in uno stesso contesto. Confronto tra CUDA e OpenCL Avendo analizzato con cura entrambi i framework, adesso è possibile discutere sia delle loro forti analogie che delle sostanziali dierenze. Come evidenziato dalla tabella di Figura 21, alcuni elementi dei due framework ricoprono lo stesso ruolo, ma hanno una terminologia dierente. Un aspetto fondamentale da tener conto è la Portabilità. Mentre l'utilizzo di CUDA è limitato a determinate architetture, tutte rigorosamente di casa NVIDIA, OpenCL risulta altamente versatile, permettendo la sua applicazione anche ad architetture eterogenee con molteplici dispositivi, quali: CPU, GPU, DSP o FPGA. 23 Figura 21: Terminologia a confronto: CUDA e OpenCL A suo vantaggio CUDA presenta una maggiore faciltà di programmazione, proponendo al mercato un tool molto più maturo rispetto ad OpenCL, contenente un proprio compilatore, un debugger e diverse librerie dedicate. La presenza del compilatore nvcc, presente nel framewok di casa NVIDIA, inoltre, consente una compilazione statica, molto più performante rispetto alla compilazione run-time di OpenCL. In denitiva, come sempre accade in informatica, non è possibile decretare un assoluto vincitore nel confronto tra CUDA e OpenCL. Entrambi presentano pro e contro, e possono essere più o meno preferiti da programmatori diversi. Infatti, hanno importanza fondamentale, nella scelta del paradigma, l'hardware a disposizione, gli obiettivi preposti e il giudizio del programmatore, ricordando che ogni kernel non sarà mai eseguito con le stesse prestazioni su diverse architetture e che quindi tale scelta può variare di caso in caso. 24 4 FPGA In elettronica digitale, un dispositivo Field Programmable Gate Array, solitamente abbreviato in FPGA, è un circuito integrato le cui funzionalità sono programmabili via software. Tali dispositivi consentono l'implementazione di funzioni logiche anche molto complesse e sono caratterizzati da un'elevata scalabilità. 4.1 Storia Ross Freeman e Bernie Vonderschmitt, fondatori della compagnia Xilinx, inventarono il primo circuito FPGA nel 1984, mentre ancora lavoravano per la Zilog. Tale circuito FPGA era composto solo da poche migliaia di porte logiche e presentava parecchi svantaggi rispetto ai rivali di mercato, ovvero i dispositivi ASIC. In particolare, erano più lenti, consumavano maggior energia e supportavano poche funzionalità. L'industria dei circuiti FPGA crebbe, seppur lentamente, durante gli anni '90, con la realizzazione, da parte del U.S. Naval Surface Warfare Department , di un dispositivo contenente ben 600.000 porte logiche. Fino ad allora, la maggior applicazione di questi circuiti rivoluzionari fu nel campo del Networking e della Telecomunicazione. Con l'arrivo del nuovo millennio, i circuiti FPGA evolsero no a contare Milioni di porte logiche, coprirono una più vasta gamma di applicazioni dierenti e risolsero i principali difetti che li rendevano svantaggiosi rispetto ai dispositivi ASIC. Inoltre, presentavano un'elevata capacità di parallelizzazione e pipelining dei processi, che li rendeva adatti allo svolgimento dei compiti che la CPU aveva dicoltà a gestire. 4.2 Origini - PLA e CPLD Programmable Logic Arrays (PLA) e Complex Programmable Logic Devices L'idea del circuito FPGA ha origine da due dispositivi: (CPLD). Figura 22: Architettura PLA I PLA furono introdotti circa nel 1970 come chip programmabili one-time (solo una volta) con lo scopo di realizzare una particolare funzione logica. 25 Il procedimento di programmazione consisteva nel bruciare dei fusibili posti in prossimità delle porte logiche (AND o OR), al ne di implementare la tabella della verità desiderata. I fattori limiti di questa tecnologia erano il numero di input, AND o OR, presenti. I CPLD, invece, nacquero successivamente, dall'idea di evolvere la struttura di un dispositivo PLA introducendo una matrice di interconnessione tra tutti gli input e output, realizzata tramite l'uso di una on-chip ash memory (memoria ash su unico chip). Tale matrice di interconnessione permette la congurazione delle macrocelle, aventi una struttura simile ad un PLA, al ne di realizzare qualsiasi funzione logica. Figura 23: Architettura CPLD 26 4.3 Architettura Il Field Programmable Gate Array è un dispositivo semiconduttore comprensivo di molti blocchi logici con interconnessioni congurabili tra loro. Tali blocchi logici sono capaci di agire come semplici porte logiche, ad esempio AND o OR, e in più presentano dei canali d'instradamento, programmabili, che ne permettono la connessione. Negli ultimi anni è cresciuto il numero di circuiti implementati attraverso la tecnologia FPGA per applicazioni special purpose, ad esempio i DSP e i moltiplicatori. Le componenti principali dei dispositivi FPGA sono i blocchi logici, presenti in milioni di unità e organizzati in un'unica grande rete all'interno del chip. Questi sono implementati in a Lookup Table (LUT), spesso consistente di 4 pin di input. Le LUT hanno una piccola porzione di memoria programmata per impostare le dipendenze tra la logica di uscita e quella di entrata, essenzialmente una tabella della verità . Figura 24: LUT a tre ingressi Ogni LUT ha una sola uscita, che può essere memorizzata all'interno di un ip op, al ne di preservarne il valore oltre il singolo ciclo di clock e per riutilizzarlo all'interno di una successiva logica implementativa. I canali di instradamento che corrono lungo i dierenti blocchi logici sono utilizzati per collegare varie LUT tra di loro. Figura 25: Switch Block 27 Questi sono controllati da uno Switch Block (Figura 25 ), ovvero un blocco di interruzione che ne permette la programmazione. Tali connessioni permettono di programmare un immenso numero di logiche dierenti e, di conseguenza, realizzare qualsiasi tipo di funzionalità. Figura 26: FPGA Routing Nelle nuove generazioni di dispositivi di FPGA sono stati introdotti altri blocchi per la realizzazione di nuove speciche funzioni. Quest'ultime vengono eseguite da tali blocchi specializzati, anche chiamati Slices, molto più velocemente rispetto al caso in cui l'implementazione avviene per via delle LUT e della rete di interconnessione. Moltiplicatori e i dispositivi DSP, i quali permettono ai dispositivi FPGA di essere più semplici e Due dei principali blocchi oggi diusi sono i contenere un numero inferiore di LUT. Figura 27: Slices Specializzati 28 Per concludere la discussione sull'architettura dei dispositivi FPGA ne mostriamo, in Figura 28, uno degli ultimi di casa Xilinx: il Figura 28: Virtex-7 29 Virtex-7. 5 Ecienza Energetica Finora, quest'elaborato ha trattato le architetture eterogenee, denendone l'utilità e le proprietà, focalizzandosi sulle tre componenti principali e analizzandone dettagliatamente evoluzione ed architettura. Nella sua parte nale, l'elaborato si concentra sulle tecniche che permettono l'uso di queste architetture in condizioni di Ecienza Energetica. 5.1 Energy Ecient System Design I sistemi embedded, quali smartphone, tablet o portatili, sono esempi perfetti di architetture eterogenee, realizzate con le tecnologie mostrate precedentemente, che devono soddisfare restringenti vincoli, quali: risorse limitate di energia e sistemi di rareddamento. Tali fattori obbligano, in fase di progettazione, ad una particolare attenzione all'energia dissipata dal dispositivo, così come al calore da esso Energy Eciency il principale requisito da raggiunto, rendendo l' soddisfare. In Figura 29, un graco nel quale si riassumono (per processori dierenti tra loro) i requisiti di ecienza per due applicazioni particolarmente diuse sui dispositivi mobili: comunicazione Wireless e HD Video. Figura 29: Esempio di Energy Eciency in applicazioni Wireless e HD Video Per raggiungere la massima ecienza possibile, sia energetica che in performance computazionali, la scelta architetturale ricade sicuramente sull'uso di Application Specic Integrated Circuits (ASIC). Il problema di questa soluzione è la totale mancanza di essibilità, a causa della quale il requisito di cambiamento-veloce, voluto dalla continua innovazione richiesta dal mercato, non è soddisfatto. Per questo motivo è nata l'esigenza di utilizzare piattaforme programmabili (GPP, GPU, FPGA), capaci di soddisfare, seppur con minor ecienza, tutti i requisiti di un tipico dispositivo embedded. Il gap energetico tra un un processore General Purpose (GPP) ed un Application Specic Integrated Circuit (ASIC) è enorme, anche di svariati ordini di grandezza. La causa principale di inecienza nei processori è il controllo dell'overhead. In un processore, le risorse generiche sono controllate da istruzioni che eseguono calcoli per dierenti tipi di applicazioni. 30 Paragonato con un ASIC, tale essibilità comporta un overhead molto elevato. Per fortuna in informatica non tutto è assoluto ed esistono tecniche capaci di ottenere, sempre con l'uso di piattaforme di calcolo programmabili, un miglior compromesso tra ecienza e essibilità. Tale equilibrio è ricercato non solo nell'architettura e nell'hardware, ma anche ottimizzando il software, con particolare attenzione alla fase di compilazione. Infatti, per una piattaforma programmabile, il compilatore è cruciale. Se mal progettato può incidere pesantemente sull'ecienza del dispositivo, viceversa può incrementarne la produttività. Inoltre, lo sfruttamento a pieno di un processore dipende anche dalla qualità del codice generato dal compilatore. L'ottimizzazione realizzata da quest'ultimo può avere un grande impatto sui consumi energetici ed è la chiave della progettazione di architetture embedded Low-Power . 5.2 Consumo Energetico Le piattaforme embedded spesso sono costruite utilizzando circuiti digitali CMOS, pertanto è fondamentale combinare tecniche legate al livello architetturale con quelle associate al livello circuitale. Per poter sfruttare a pieno il potenziale del paradigma low-power, le architetture e i sistemi software includono sistemi operativi e compilatori capaci di utilizzare opportune tecniche, quali il Scaling della Frequenza (DVFS). Voltaggio Dinamico e lo Nei circuiti CMOS, la maggior parte dell'energia è dissipata al cambio della porta di uscita. Il consumo di energia di tali circuiti può essere determinato con la formula dell'equazione: P = αCVdd2f + Ileak Vdd Il primo termine rappresenta la dissipazione della componente dinamica del circuito, con fornito e f αC la capacità di commutazione del circuito, Vdd il voltaggio la frequenza. Il secondo termine, invece, è la potenza dispersa, con Ileak la corrente di dispersione. La componente dinamica è tipicamente la maggior fonte di consumo energetico. 2 Inoltre, la presenza del voltaggio elevato al quadrato (Vdd ) suggerisce che è tale costante l'elemento di maggior peso nell'economia del dispositivo CMOS. Per questo motivo, una tecnica usata è quella di scalare il voltaggio frequenza f (VFS - Voltage and Frequency Scaling ) per ridurre notevolmente l'energia consumata. 31 Vdd e la Figura 30: Gap tra l'ecienza computazionale intrinseca (ICE) e l'ecienza reale dei processori Oltre alle tecniche che riducono direttamente l'energia consumata dal circuito, è importante anche incrementare la porzione di energia spesa per lo svolgimento di lavoro utile e quindi migliorare la Computational Eciency. La Figura 30 mostra il valore di Intrinsic Computational Eciency (ICE) per dierenti tecnologie CMOS e il picco di performance ottenibile da vari processori. Tale valore rappresenta il potenziale grezzo del circuito CMOS, una realtà ottenibile solo immaginando di costruire un circuito ad hoc per ogni applicazione. Sempre in gura, la linea più bassa nel graco rappresenta l'ecienza computazionale raggiungibile con un processore general purpose (GPP), e ne mostra l'eettiva distanza dal rispettivo valore ICE. 32 6 Energy Awareness nei Compilatori Il compilatore è lo strumento che traduce il codice sorgente di alto livello nel codice macchina della particolare architettura. Gioca un ruolo fondamentale nello sviluppo del software, consentendo la programmazione machine-indipendent e l'uso di linguaggi ad alto livello quali il C/C++. Storicamente, i compilatori si focalizzano sulla riduzione della dimensione e l'aumento della velocità di generazione del codice. Il requisito della Energy Awareness è abbastanza nuovo, e per questo ancora in via di sviluppo e perfezionamento. Nella progettazione di sistemi a bassa-potenza (low-power), le tecniche che permettono ottimizzazioni energy-aware giocano un ruolo fondamentale e spesso sono correlate ad ottimizzazioni sulla velocità. In questo capitolo verranno arontate alcune delle tecniche utilizzate dai compilatori a supporto dell'ecienza energetica. 6.1 Riduzione attività di Switching La commutazione dei circuiti è la principale causa di dissipazione di potenza. Sebbene un compilatore genericamente lavori ad alto livello, è capace di inuenzare tale attività in larga misura e in molti modi diversi. Per i motivi su citati, una delle prime prerogative di un compilatore è quella di ridurre l'attività di commutazione, ad esempio, organizzando attentamente le istruzioni di un'applicazione. Negli ultimi anni sono stati presentati più articoli che proponevano una loro soluzione per il raggiungimento di tale obiettivo. Lee et al. proposero un algoritmo di scheduling per minimizzare l'attività di switching riducendo la distanza di Hamming tra le istruzioni nei processori VLIM, ottenendo una riduzione del 20% dell'attività dell'instruction bus. [26] Nel 2006, Shao et al. proposero un algoritmo di scheduling ciclico (loop) sempre per processori VLIM che minimizzava sia la lunghezza del programma che l'attività di switching con un miglioramento rispettivamente del 11.5% e del 19.4% rispetto alla soluzione precedente. [29] Sempre nel 2006, Diamond et al. presentarono una tecnica che combina la codica e il riordino delle istruzioni, ottenendo un guadagno del 74% della potenza dinamica senza avere alcuna perdita di prestazioni. [21] Esistono molte altre tecniche, oltre a quelle elencate, che permettono di ottenere miglioramenti energetici dalla fase di compilazione e che possono riguardare sia l'organizzazione delle istruzioni che altri componenti interni del processore, quali i registri e l'uso degli operandi. 6.2 Allocazione Risorse Il compilatore è il responsabile della gestione di molte risorse del processore, specialmente nel caso di sistemi embedded, nei quali la capacità di gestione a tempo di esecuzione è limitata. 33 L'allocazione delle risorse ha un grande impatto sull'ecienza energetica di un dispositivo, soprattutto nel caso in cui tali risorse consumano molta energia, quali ad esempio il le Registro e le memorie in generale. Per questi motivi, nei sistemi embedded spesso viene utilizzata la Scratchpad Memory come alternativa alle cache. Infatti, questa è una memoria ad alta velocità utilizzata per memorizzare dati usati frequentemente dal processore. É considerata molto simile alla cache di un processore, con la sostanziale dierenza che, mentre la cache non è visibile al programmatore, la scratchpad memory lo è. Il compilatore alloca i dati nella scratchpad memory così da incrementare sia le performance che il consumo energetico. Avissar et al. presentarono uno schema per la gestione della scratchpad memory, con il quale ottennero un miglioramento del 40% a tempo d'esecuzione. [17] Wehmeyer et al. mostrarono che l'inserimento della scratchpad memory nel sistema di memorie permetteva un risparmio del 20% dell'energia nel compilatore. [30] Ayala et al. proposero una tecnica di compilazione power-aware, la quale permette l'allocazione dei registri in modo tale da usare una sola parte del le registro, e congurarne la restante in power-save mode (modalità di risparmio energetico). Tale soluzione porta ad un risparmio energetico del 65% senza alcuna perdita in performance. [18] Oltre alla Scratchpad Memory, un'altra memoria presente nei più comuni processori embedded è il Loop Buer. Quest'ultimo è una memoria di piccola dimensione il cui scopo è contenere un numero abbastanza ridotto di istruzioni, solitamente le istruzioni cicliche più frequentemente eseguite. É stato dimostrato che anche quest'ultima tecnica, utilizzata al posto di comuni cache, consente una notevole riduzione dell'energia consumata. 6.3 Power-Management a Run-Time I moderni microprocessori forniscono vari servizi per la gestione dell'energia che possono essere controllati via software. Un compilatore Energy-Aware deve essere capace di sfruttare tutti questi servizi ottenendo un basso overhead in esecuzione. Il Dynamic Voltage and Frequency Scaling (DVFS) è un metodo fondamentale per la gestione della capacità computazionale del processore in ambiente a basso consumo energetico. Wu et al. proposero un sistema di compilazione dinamica che ottenne una sostanziale riduzione del consumo energetico del processore rispetto alla tecnica DVFS, incrementando del 22% il prodotto Energy-Delay (EDP). [33] You et al. presentarono una struttura capace di ridurre la potenza dispersa (leakage power) nei microprocessori, utilizzando la tecnica del Gating. [34] 34 Power 6.4 Ottimizzazione dell'Instruction Set Architecture (ISA) In informatica, un Instruction Set Architecture (ISA), (in lingua italiana insieme d'istruzioni ), descrive quegli aspetti dell'architettura di un calcolatore che sono visibili al programmatore. Si tratta di fatto dell'insieme di istruzioni base che il processore può compiere e che costituiscono dunque il suo linguaggio macchina, a partire dal quale vengono scritti i relativi programmi nei vari linguaggi di programmazione a più alto livello di astrazione. Poiché l'Instruction Set Architecture (ISA) ha grande impatto sull'ecienza del processore, un'approccio comune per la riduzione dei consumi energetici è modicare l'ISA così da ottimizzare l'uso delle sue componenti più ecienti. Un esempio è quello di utilizzare istruzioni Complesse per ridurre il costo di esecuzione di certi modelli di calcolo, migliorando le prestazioni e risparmiando energia. 35 7 Conclusioni 7.1 Confronto tra architetture L'esperienza quotidiana con i calcolatori insegna che l'elaborazione dei dati e delle istruzioni dei programmi è compito specico della CPU. I vari core che la compongono sono ottimizzati per l'esecuzione seriale delle istruzioni, generando un usso di lavoro sequenziale. Le GPU, per loro natura, utilizzano un metodo di lavoro completamente opposto: anziché eseguire una sola operazione alla volta, ne portano avanti diverse migliaia contemporaneamente (in parallelo). Infatti la scheda graca ha molteplici unità di elaborazione, di grandezza e potenza minore rispetto a quella di una CPU, ottimizzate per lavorare parallelamente. Le varie unità possono essere programmate per eseguire porzioni di codice o programma anche di natura dierente grazie all'utilizzo degli Shader. In questo modo si è stati in grado di raggiungere un alto grado di ecienza nella capacità di calcolo delle unità di elaborazione graca, che ha invogliato la diusione di questa tecnologia anche per applicazioni general purpose (GPGPU). L'utilizzo massiccio delle GPU, anche per applicazioni di natura non graca (GPGPU), caratterizzate da un'elevata parallelizzazione, può soddisfare la richiesta di prestazioni sempre più spinte. Va sicuramente precisato, però, che il GPGPU non è la soluzione denitiva in questo senso. Infatti, esistono processi che richiedono cooperazione e dipendenza tra i dati, nonché numerosi salti condizionati, e che si prestano meglio ad un'esecuzione su CPU multi-core, anziché su GPU. Qui in seguito un breve confronto tra CPU e GPU: • Vantaggi Prestazionali. Una GPU è capace di orire una maggiore capacità di elaborazione rispetto ad un normale processore di pari fascia di potenza. Cio è possibile, però, solo nel caso in cui il codice del programma è ottimizzato per l'esecuzione parallela, e in tali casi, le GPU sono in grado di garantire prestazioni anche 100 volte superiori a quelle delle CPU. 36 • Vantaggi sul Costo. Non si notano grandi scostamenti tra CPU e GPU appartenenti alla stessa fascia di mercato. Ricordando, però, che la GPU ha circa 100 volte prestazioni superiori alla CPU della stessa fascia è evidente come queste siano molto più vantaggiose. • Tasso di Aggiornamento Tecnologico. Al giorno d'oggi, le GPU vanno incontro ad aggiornamenti più frequenti rispetto a quelli dei processori. • Consumo/Prestazione. Anche se negli ultimi anni i produttori hanno lavorato molto sull'ottimizzazione dei consumi energetici dei processori, le GPU restano, nella maggioranza dei casi, più convenienti nel rapporto consumi/prestazioni. Come detto, infatti, accade molto raramente che la GPU raggiunga il carico massimo di elaborazione, e di conseguenza, il picco di consumi energetici. Altra analisi meritano invece applicazioni sensibili, in alcuni casi real-time, che richiedono un certo tasso di adabilità e di costanza nelle prestazioni. Spesso queste problematiche vengono risolte con l'uso di tecnologie ad-hoc, quali ASIP, ASIC o FPGA (quest'ultima nel caso in cui ha rilevanza anche la essibilità del dispositivo), che permettono di raggiungere prestazioni nettamente migliori, adattandosi specicamente alla risoluzione del compito per cui vengono create. Inoltre, la società attuale ricerca sempre più dispositivi performanti e, nel caso di strutture mobili, energeticamente ecienti. Questi due requisiti spesso sono contraddittori l'uno con l'altro. Infatti, se si vogliono aumentare le prestazioni, è necessario dare maggior potenza alle varie componenti elettroniche quali, per esempio, il processore, il co-processore graco o il DSP, con un conseguente maggiore consumo energetico. Per questo motivo, tipicamente nei dispositivi di natura mobile, si ricerca un compromesso tra prestazioni ed energia, sfruttando le abilità delle piattaforme eterogenee trattate in quest'elaborato, per ricavare beneci da ogni componente. 37 8 Bibliograa 1. Gordon E. Moore. Cramming more components onto integrated circuits. Electronics Magazine, 1965. 2. Wikipedia: Heterogeneous System Architecture, http: //en.wikipedia.org/wiki/Heterogeneous_System_Architecture 3. U.C. Berkeley CS267/EngC233: Applications of Parallel Computers Lecture Notes, http://www.cs.berkeley.edu/~demmel/cs267_Spr11/Lectures/ lecture01_intro_kay11.ppt 4. David B. Kirk and Wen-mei W. Hwu. Programming Massively Parallel Processors: A Hands-on Approach. Morgan Kaufmann Publishers Inc., 2010. 5. A. S. Tanenbaum, Architettura dei calcolatori. Un approccio strutturale, Prentice Hall, 2006. 6. Alan Watt. 3d Computer Graphics. Addison-Wesley Longman Publishing Co., Inc., 1993. 7. GPGPU.org: General-Purpose computation on Graphics Processing Units http://gpgpu.org/ 8. NVIDIA Fermi Computer Architecture, http://www.nvidia.com/content/PDF/fermi_white_papers/ NVIDIA_Fermi_Compute_Architecture_Whitepaper.pdf 9. Acceleratori GPU Tesla, http://www.nvidia.it/object/tesla-server-gpus-it.html 10. What is CUDA NVIDIA Developer Zone http://developer.nvidia.com/what-cuda 11. OpenCL http://www.khronos.org/opencl/ 12. Wikipedia: OpenCL http://en.wikipedia.org/wiki/OpenCL 13. FPGA Central, 2011. http://www.fpgacentral.com/docs/fpga-tutorial/ history-programmable-logic 14. V.Betz, University of Toronto, http: //www.eecg.toronto.edu/~vaughn/challenge/fpga_arch.html 15. Electrical Engineering Times, October 2008. http://www.eetimes.com/electrical-engineers/ education-training/courses/4000134/Fundamentals-of-FPGAs 38 16. M. Strickland, HEARST Electronic Products, 1 March 2010. http://www2.electronicproducts.com/The_evolution_of_FPGA_ coprocessing-article-FAJH_FPGA_Mar2010-html.aspx 17. Oren Avissar, Rajeev Barua, and Dave Stewart. An Optimal Memory Allocation Scheme for Scratch-Pad-Based Embedded Systems. ACM Transactions on Embedded Computing Systems (TECS), 2002. 18. Jose L. Ayala, Alexander Veidenbaum, and Marisa Lopez-Vallejo. Power-Aware Compilation for Register File Energy Reduction. International Journal of Parallel Programming, 2003. 19. James Balfour, William Dally, David Black-Schaer, Vishal Parikh, and JongSoo Park. An energy-ecient processor architecture for embedded systems. Computer Architecture Letters, 2007. 20. Anantha P. Chandrakasan, Samuel Sheng, and Robert W. Brodersen. Low-power CMOS digital design. IEEE Journal of Solid-State Circuits, 1992. 21. Robert G. Dimond, Oskar Mencer, and Wayne Luk. Combining Instruction Coding and Scheduling to Optimize Energy in System-on-FPGA. Proceedings of the 14th Annual IEEE Symposium on Field-Programmable Custom Computing Machines (FCCM '06). IEEE Computer Society, 2006. 22. Rehan Hameed, Wajahat Qadeer, Megan Wachs, Omid Azizi, Alex Solomatnikov, Benjamin Lee, Stephen Richardson, Christos Kozyrakis, and Mark Horowitz. Understanding Sources of Ineciency in General-Purpose Chips. Proceedings of the 37th Annual International Symposium on Computer Architecture (ISCA '10). ACM, 2010. 23. Yifan He, Yu Pu, Richard Kleihorst, Zhenyu Ye, Anteneh Abbo, Sebastian Londono, and Henk Corporaal. Xetal-Pro: an Ultra-Low Energy and High Throughput SIMD Processor. Proceedings of the 47th Design Automation Conference (DAC '10). ACM, 2010. 24. Mark Hill and Michael Marty. Amdahl's Law in the Multicore Era. Computer, 2008. 25. Chung-Hsing Hsu and Ulrich Kremer. The Design, Implementation, and Evaluation of a Compiler Algorithm for CPU Energy Reduction. Proceedings of the ACM SIGPLAN 2003 Conference on Programming Language Design and Implementation (PLDI '03). ACM, 2003. 26. Chingren Lee, Jenq Kuen Lee, Tingting Hwang, and Shi-Chun Tsai. Compiler Optimization on VLIW Instruction Scheduling for Low Power. 39 ACM Transactions on Design Automation of Electronic Systems (TODAES), 2003. 27. Huzefa Mehta, Rober Michael Owens, Mary Jane Irwin, Rita Chen, and Debashree Ghosh. Techniques for Low Energy Software. Proceedings of the 1997 International Symposium on Low Power Electronics and Design (ISLPED '97). IEEE, 1997. 28. Padmanabhan Pillai and Kang G. Shin. Real-time Dynamic Voltage Scaling for Lowpower Embedded Operating Systems. Proceedings of the 18th ACM Symposium on Operating Systems Principles (SOSP '01). ACM, 2001. 29. Zili Shao, Bin Xiao, Chun Xue, Qingfeng Zhuge, and Edwin H.-M. Sha. Loop Scheduling with Timing and Switching-Activity Minimization for VLIW DSP. ACM Transactions on Dessign Automation of Electronic Systems (TODAES), 2006. 30. Lars Wehmeyer, Urs Helmig, and Peter Marwedel. Compiler-optimized Usage of Partitioned Memories. Proceedings of the 3rd Workshop on Memory Performance Issues (WMPI '04). ACM, 2004. 31. Wikipedia. List of iOS devices. http://en.wikipedia.org/wiki/List_of_iOS_devices 32. Michael Wolfe. How Compilers and Tools Dier for Embedded Systems. Proceedings of the 2005 International Conference on Compilers, Architectures and Synthesis for Embedded Systems (CASES '05). ACM, 2005. 33. Qiang Wu, Margaret Martonosi, Douglas W. Clark, V. J. Reddi, Dan Connors, Youfeng Wu, Jin Lee, and David Brooks. A Dynamic Compilation Framework for Controlling Microprocessor Energy and Performance. Proceedings of the 38th Annual IEEE/ACM International Symposium on Microarchitecture (MICRO-38). IEEE Computer Society, 2005. 34. Yi-Ping You, Chingren Lee, and Jenq Kuen Lee. Compilers for Leakage Power Reduction. ACM Transactions on Design Automation of Electronic Systems (TODAES), 2006. 40