L'avvento della GPGPU

CUDA, il nuovo linguaggio di programmazione per le GPU Nvidia, promette grandi risultati e mostra le schede video sotto una nuova luce. Cerchiamo di capire un po' di più cosa ci riserva CUDA.

Avatar di Andrea Ferrario

a cura di Andrea Ferrario

Editor in Chief

L'avvento della GPGPU

L'idea di usare gli acceleratori grafici per i calcoli matematici non è recente, infatti se ne parla già dagli anni novanta. Inizialmente era molto primitiva - limitata ad alcune funzionalità hardware come la rasterizzazione o i calcoli Z-buffers per accelerare lavori come il pathfinding o la creazione di diagrammi Voronoi.

Nel 2003, con l'arrivo di shader evoluti, si raggiunse un nuovo stadio - questa volta era possibile effettuare calcoli di matrici usando l'hardware disponibile. Nacque quindi il termine GPGPU (General-Purpose computation in GPU).

Un altro punto di svolta, in questa area, fu l'arrivo di BrookGPU.

Per capire veramente il ruolo di Brook, è necessario capire com'era la situazione antecedente. L'unico modo per accedere alle risorse della GPU, nel 2003, era usare una delle due API grafiche disponibili - Direct3D od OpenGL, che permettevano di accedere alla potenza grafica della GPU, per i ricercatori interessati. Questi ricercatori, però, non erano necessariamente esperti nella programmazione grafica, motivo per cui l'accesso a tale tecnologia era molto complicato. Dove i programmatori 3D parlavano di shader, texture e fragments, gli specialisti della programmazione parallela parlavano di streams, kernel, scatter e gather. Quindi, la prima difficoltà era trovare delle analogie tra questi due mondi distinti:

  • Uno stream - che è un flusso di elementi dello stesso tipo - può essere presentato ad una GPU come se fosse una texture. Per farvi un'idea, consideratelo come l'equivalente di un array nella programmazione classica.
  • Un kernel - l'applicazione che verrà applicata indipendentemente a ogni elemento dello stream - è l'equivalente del pixel shader. Concettualmente può essere visto come il loop interno di un classico programma - applicato a un enorme numero di elementi.
  • Per leggere il risultato dell'applicazione di un kernel a uno stream, questo deve essere renderizzato in una texture. Ovviamente non esiste un equivalente per la CPU, che ha accesso totale alla memoria.
  • Per controllare la posizione dove viene scritta la memoria (scatter), deve essere effettuata un'operazione vertex shader, poiché il pixel shader non può modificare le coordinate di un pixel già elaborato.

Come potete vedere, anche con queste analogie in mente, l'obiettivo non è semplice, ed qui che entra in gioco Brook. Brook è un set di estensioni del linguaggio C, che propone di integrare tutta la parte gestionale delle API 3D, gestendo la GPU come un coprocessore per i calcoli paralleli. Per far ciò, Brook comprende un compilatore, che prende un file.br, contenente codice C++ e varie estensioni, per generare codice C++ standard da connettere a una libreria run-time che dispone di vari back-end (DirectX, OpenGL ARB, OpenGL NV3x, x86).

Brook ha diversi meriti, il primo dei quali è quello di aver portato le GPGPU fuori dall'ombra e di averle presentate al grande pubblico. Quando fu annunciato il progetto, molti siti web parlarono dell'arrivo di Brook. Alcuni semplificarono anche troppo il concetto: "La CPU è morta! Le GPU sono molto più potenti e presto rimpiazzeranno le CPU!". Cinque anni dopo, invece, non è ancora accaduto, e, diciamolo chiaramente, non accadrà mai. Considerando i successivi cambiamenti delle CPU, che ora sono sempre più orientate verso il parallelismo (sempre più core, tecnologia multi-threading e l'ampliamento delle unità SIMD), e delle GPU, che diversamente stanno diventando sempre più flessibili (supporto per i calcoli single-precision floating-point, calcoli integer e presto calcoli double-precision), sembra ovvio che entrambe si stiano muovendo verso un punto di incontro. Cosa succederà quindi? Le GPU assorbiranno le CPU, magari come coprocessore matematico? Possibile. Intel e AMD stanno lavorando su progetti di questo tipo. Nel frattempo, tuttavia, nulla è cambiato.

Torniamo ora al nostro interesse principale. Con Brook, le API potevano semplificare notevolmente l'accesso alle risorse della GPU, permettendo a molti di studiare un nuovo modello di programmazione. D'altra parte, nonostante le qualità di Brook, c'era ancora molta strada da fare prima che la GPU potesse essere considerata una valida unità di calcolo.

Uno dei problemi riscontrati derivava dai differenti layer d'astrazione, e in particolare dall'eccessivo carico di lavoro generato dalle API 3D. Ma il problema reale era l'incompatibilità, sulla quale gli sviluppatori di Brook non avevano controllo. Non è raro per i produttori di GPU ottimizzare regolarmente i driver, specialmente considerando l'acerrima competizione in questo campo. Queste ottimizzazioni erano (la maggior parte delle volte) molto utili per i giocatori, ma potevano pesare sulla compatibilità di Brook: quindi era difficile immaginare l'uso delle API per creare programmi di ampio respiro. Per lungo tempo Brook rimase solo una curiosità per ricercatori e programmatori.