Progetti basati su Fpga con lo standard OpenCL

Agli albori dell'era delle tecnologie programmabili, la programmabilità era limitata a due casi estremi. Il primo era rappresentato dai Dsp e dalle Cpu a core singolo. La programmazione di questi dispositivi avveniva attraverso un software formato da una serie di istruzioni che dovevano essere eseguite. Dal punto di vista concettuale, le istruzioni erano create in modo da risultare sequenziali per il programmatore, sebbene un processore avanzato sarebbe stato in grado di riordinare le istruzioni per estrarre il parallelismo a livello di istruzione da questi programmi sequenziali durante l'esecuzione. L'estremo opposto era rappresentato dagli Fpga. Questi dispositivi sono programmati mediante la creazione di circuiti hardware configurabili, che sono eseguiti in modalità completamente parallela. Un progettista che utilizza un Fpga sta fondamentalmente generando un'applicazione parallela a grana fine. Per molti anni si è assistito a una coesistenza di questi due estremi con ogni tipo di programmabilità applicata a differenti domini applicativi. Le tendenze più recenti nell'ambito del cosiddetto scaling tecnologico hanno favorito quelle tecnologie che abbinano programmabilità e parallelismo. Nel momento in cui è aumentata la richiesta di prestazioni, i dispositivi programmabili via software che eseguono un programma di tipo sequenziale hanno sfruttato alcune tendenze per incrementare le loro prestazioni. Una di queste è legata alla disponibilità di circuiti hardware complessi in grado di estrarre il parallelismo a livello di istruzione da programmi sequenziali. Un'architettura a core singolo, ad esempio, potrebbe ricevere in ingresso un flusso di istruzioni ed eseguirle su un dispositivo che potrebbe avere numerose unità funzionali parallele. Una frazione significativa dell'hardware del processore deve essere dedicato all'estrazione in maniera dinamica del parallelismo dal codice sequenziale. Senza dimenticare che l'hardware deve cercare di compensare le latenze della memoria. Di solito i programmatori creano programmi dimenticandosi della gerarchia di memoria sottostante, che essi assimilano a un dispositivo piatto, di ampie dimensioni e caratterizzato da una velocità costante. Di fatto il processore deve scontrarsi con una realtà fisica concreta: l'elevata latenza e l'ampiezza di banda limitata delle connessioni alla memoria esterna. Al fine di "alimentare" le unità funzionali con i dati necessari, il processore deve anche eseguire il pre-fetch (ovvero il pre-caricamento) in modo speculativo dei dati dalla memoria esterna alle memorie cache on-chip in modo che i dati risultino può vicini al luogo dove avviene l'elaborazione. Dopo parecchi decenni di miglioramento ottenuti grazie a queste tecniche, si è assistito a una graduale diminuzione dei risultati ottenuti da questi tipi di architetture.

L'evoluzione dei dispositivi programmabili

Per questo motivo si è assistito negli ultimi anni a una evoluzione piuttosto significativa nel settore dei dispositivi programmabili via software. L'attenzione si è spostata dall'estrazione automatica del parallelismo a livello di istruzione durante l'esecuzione all'individuazione del parallelismo a livello di thread durante la codifica. Hanno iniziato così ad affacciarsi alla ribalta dispositivi multi-core a elevato grado di parallelismo: essi contengono un certo numero di processori più semplici in cui la maggior parte dei transistor sono preposti a compiti di elaborazione piuttosto che a operazioni di caching ed estrazione del parallelismo. Dispositivi di questo tipo spaziano dalle Cpu multi-core equipaggiate con 2, 4 o 8 core, alle Gpu che contengono centinaia di core semplici ottimizzati per l'elaborazione parallela dei dati. A ogni core deve essere assegnato del lavoro in modo tale che tutti i core presenti possano cooperare all'esecuzione di una determinata elaborazione. Ciò è esattamente la modalità seguita dai progettisti Fpga per generare le loro architetture di sistema ad alto livello. La necessità di creare programmi di natura parallela per l'elaborazione multi-core ha portato alla creazione del linguaggio OpenCL (Open Computing Language), il cui obbiettivo è mettere a disposizione uno standard per la programmazione parallela di tipo cross-platform (non legato cioè a una specifica piattaforma). Lo standard OpenCL intrinsecamente dà la possibilità di descrivere algoritmi paralleli che devono essere implementati su Fpga a un livello di astrazione più elevato rispetto a quello dei tradizionali linguaggi di descrizione dell'hardware o Hdl (Hardware description language) come Vhdl o Verilog. Nonostante siano reperibili numerosi tool per la sintesi ad alto livello in grado di sfruttare i vantaggi derivati da questo elevato livello di astrazione, tutti si trovano ad affrontare il medesimo problema. Essi operano su programmi sequenziali scritti in C e producono un'implementazione Hdl parallela. La difficoltà non risiede tanto nella generazione dell'implementazione Hdl, bensì nell'estrazione del parallelismo a livello di thread che consente all'implementazione Fpga di garantire elevate prestazioni. Poiché gli Fpga sono dispositivi caratterizzati da un elevato grado di parallelismo, il mancato sfruttamento del massimo livello possibile di parallelismo è più penalizzante rispetto ad altri dispositivi. Lo standard OpenCL permette di risolvere molti di questi problemi consentendo al programmatore di specificare in maniera esplicita e controllare il parallelismo. Lo standard OpenCL è quindi più adatto alla natura parallela intrinseca degli Fpga rispetto a quanto lo siano i programmi sequenziali scritti in C.

Lo standard OpenCL

Le applicazioni OpenCL sono formate da due parti. Il programma host OpenCL è una routine software scritta in linguaggio standard C/C++ che gira su qualsiasi tipo di microprocessore. Questo può essere un processore soft integrato in un Fpga, un processore Arm di tipo hard o un processore in architettura x86 esterno.
Durante l'esecuzione nell'host di questa routine software, a un certo punto è possibile che vi sia una funzione, particolarmente onerosa in termini computazionali, che possa trarre vantaggio dall'accelerazione parallela se eseguita su un dispositivo ad alto grado di parallelismo come ad esempio Cpu, Gpu, Fpga e così via. La funzione che deve essere accelerata viene definita kernel OpenCL. Tali kernel, sebbene scritti in linguaggio C standard, sono annotati con costrutti che specificano il parallelismo e la gerarchia di memoria. I thread (ovvero i flussi di esecuzione) paralleli che operano su ciascun elemento del vettore consentono di calcolare il risultato in tempi notevolmente più brevi quando si sfrutta l'accelerazione tipica di un dispositivo caratterizzato da un massiccio parallelismo a grana fine come appunto un Fpga. Il programma host ha accesso alle Api (Application programming interface) OpenCL standard che consentono il trasferimento dei dati all'Fpga mediante la chiamata del kernel sull'Fpga e il trasferimento dei dati risultanti. Negli Fpga le funzioni del kernel possono essere trasformate in circuiti hardware dedicati e di tipo deeply pipelined (pipeline profonda) che sono intrinsecamente multi-threaded grazie all'utilizzo del concetto di parallelismo della pipeline (pipeline parallelism). Ciascuna di queste pipeline può essere replicata molte volte per ottenere un grado di parallelismo più spinto rispetto a quello conseguibile con una singola pipeline.

Implementare lo standard OpenCL su un Fpga

La creazione di progetti basati su Fpga utilizzando una descrizione OpenCL garantisce numerosi vantaggi rispetto alle tradizionali metodologie basate sulla programmazione in linguaggio Hdl. Il flusso per lo sviluppo per dispositivi programmabili via software si articola nelle seguenti fasi: concezione dell'idea, codifica dell'algoritmo in un linguaggio ad alto livello (C ad esempio), utilizzo di un compilatore automatico per creare il flusso di istruzioni. Il kit di sviluppo software per OpenCL di Altera mette a disposizione un ambiente di progettazione che permette di implementare in modo semplice applicazioni OpenCL su Fpga.
Un approccio di questo tipo può essere in contrasto con le tradizionali metodologie di progettazione basate su Fpga in cui i progettisti devono generare le descrizioni ciclo per ciclo dell'hardware che sono impiegate per implementare i loro algoritmi. Il flusso tradizionale prevede la creazione di percorsi dati e di macchine a stati per controllare questi percorsi dati, il collegamento a core IP di basso livello mediante tool a livello di sistema e la gestione delle problematiche relative alla "timing closure" in quanto le interfacce esterne impongono vincoli fissi che devono essere rispettati. L'Sdk per OpenCL di Altera effettua tutte le fasi appena descritte in maniera automatica in modo da consentire ai progettisti di concentrare la loro attenzione sulla definizione degli algoritmi piuttosto che sui dettagli, invero un po' noiosi, del progetto hardware. Un approccio di questo tipo consente ai progettisti di migrare senza problemi su nuovi Fpga caratterizzati da migliori prestazioni e maggiori capacità perché il compilatore OpenCL convertirà la medesima descrizione ad alto livello in pipeline capaci di sfruttare le potenzialità degli Fpga di nuova generazione. L'impiego abbinato dello standard OpenCL e degli Fpga può garantire significativi vantaggi, in termini di maggiori prestazioni e di consumi inferiori, rispetto alle tradizionali architetture hardware. Un sistema eterogeneo (Cpu + Fpga) basato su Fpga che utilizza lo standard OpenCL, inoltre, assicura una notevole riduzione del time-to-market rispetto a uno sviluppo di tipo tradizionale che prevede il ricorso a linguaggi di descrizione dell'hardware di più basso livello come Verilog o Vhdl.

LASCIA UN COMMENTO

Inserisci il tuo commento
Inserisci il tuo nome