SlideShare a Scribd company logo
1 of 71
`
      Universita degli Studi di Trieste
              Facolt` di Ingegneria
                    a
       Corso di Studi in Ingegneria dell’Informazione




Modellazione della dinamica
    di un liquido bifase
    mediante gpu cuda
                      Tesi di Laurea Triennale




Laureanda:                               Relatori:
Alessandra LADERCHI                      prof. Claudio CHIARUTTINI
                                         prof. Gianni SCHENA




               ANNO ACCADEMICO 2010–2011
Ai miei genitori
    e a Isabella
ii
Indice




Introduzione                                                                                                                     1

1 CUDA                                                                                                                            3
  1.1 Di cosa si tratta .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    3
  1.2 Il calcolo parallelo   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
  1.3 I kernel . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    7
  1.4 Tipi di memoria .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
  1.5 La compilazione .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   12

2 Boltzmann e i metodi reticolari                                                                                                15
  2.1 I metodi reticolari . . . . . . . .                    . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   15
  2.2 Il modello D2Q9 . . . . . . . .                        . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   16
  2.3 L’approssimazione BGK . . . .                          . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   18
  2.4 Condizioni al contorno . . . . .                       . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   19
      2.4.1 Rimbalzo . . . . . . . .                         . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   19
  2.5 ILBM e fluidi multifase . . . . .                       . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   21
      2.5.1 Interfaccia e gradiente di                       colore          .   .   .   .   .   .   .   .   .   .   .   .   .   21
      2.5.2 La ricolorazione . . . . .                       . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   22

3 Simulazione mediante CUDA                                                                                                      25
  3.1 Strumenti utilizzati . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
      3.1.1 Specifiche tecniche .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25
  3.2 La simulazione . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   26
  3.3 Il codice . . . . . . . . . . .                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      3.3.1 Diagramma di flusso                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      3.3.2 Inizio . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   30
iv


        3.3.3   I kernel . . . . . . . . . . . . . . . . . . . . . . . . . . 30
        3.3.4   L’animazione grafica . . . . . . . . . . . . . . . . . . . 32

4 Test finali                                                                                                             35
  4.1 La misurazione dei tempi       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
      4.1.1 Eventi CUDA . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   36
  4.2 Il confronto . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   36
  4.3 Altri test . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37

5 Conclusioni                                                                                                            39

A Codice integrale                                                                                                       41
Elenco delle figure




1.1   Differenza di prestazioni tra GPU e CPU. [5] . . . . . . . . .          .   4
1.2   Griglie, blocchi e thread. [2] . . . . . . . . . . . . . . . . . .     .   5
1.3   Rappresentazione schematica del raggruppamento dei core in
      una GPU CUDA. [5] . . . . . . . . . . . . . . . . . . . . . .          .   6
1.4   Indicizzazione di una griglia di blocchi a due dimensioni. [5]         .   8
1.5   Suddivisione della memoria. In rosso sono evidenziate le mem-
      orie a bassa latenza, mentre in arancione quelle a latenza pi´     u
      elevata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     . 10
1.6   Principio di localit´. [3] . . . . . . . . . . . . . . . . . . . . .
                          a                                                  . 11
1.7   Fasi della compilazione. [8] . . . . . . . . . . . . . . . . . . .     . 13

2.1   Esempi di modelli reticolari di Boltzmann . . . . . .        . . . .   .   16
2.2   Il modello D2Q9 . . . . . . . . . . . . . . . . . . . .      . . . .   .   16
2.3   D2Q9, componenti x e y delle velocit´ microscopiche
                                             a                     . . . .   .   17
2.4   Rimbalzo di tipo mid-plane. [4] . . . . . . . . . . . .      . . . .   .   20
2.5   Densit´ nelle zone di interfaccia. [7] . . . . . . . . . .
             a                                                     . . . .   .   21
2.6   Meccanismo di ricolorazione. [7] . . . . . . . . . . . .     . . . .   .   22
2.7   Definizione delle priorit´ delle direzioni mediante il
                                a                                  calcolo
      delle proiezioni del gradiente su di esse. . . . . . . . .   . . . .   . 23

3.1   Simulazione del fenomeno della decomposizione spinodale. . . 26
3.2   Informazioni preliminari. . . . . . . . . . . . . . . . . . . . . . 27
3.3   Diagramma di flusso. . . . . . . . . . . . . . . . . . . . . . . . 29
vi
Elenco delle tabelle




3.1   Alcune specifiche tecniche della scheda grafica. . . . . . . . . . 26

4.1   Confronto tra il programma scritto in MATLAB e lo stesso
      scritto in CUDA, senza la visualizzazione dell’animazione. .         . 36
4.2   Confronto tra il programma scritto in MATLAB e lo stesso
      scritto in CUDA, con la visualizzazione dell’animazione. . . .       . 36
4.3   Confronto tra diverse disposizioni di thread per blocco, senza
      la visualizzazione dell’animazione. . . . . . . . . . . . . . . .    . 37
4.4   Confronto tra diverse disposizioni di thread per blocco, con la
      visualizzazione dell’animazione. . . . . . . . . . . . . . . . .     . 37
4.5   Scalabilit´ del sistema. . . . . . . . . . . . . . . . . . . . . .
                a                                                          . 38
viii
Introduzione




La presente tesi descrive il lavoro svolto durante la modellazione della di-
namica di un liquido bifase mediante l’utilizzo di una GPU con architettura
CUDA. In particolare, il codice prodotto segue la linea di programmazione del
software realizzato dal prof. G. Schena [1] utilizzando l’ambiente di sviluppo
MATLAB. Cos´ facendo, si ` reso possibile testare la differenza di prestazioni
                ı           e
tra il programma eseguito in MATLAB e lo stesso programma realizzato in
CUDA.

    L’elaborato ´ strutturato come segue.
                 e
Il Capitolo 1 introduce l’architettura CUDA e alcune caratteristiche utilizzate
durante lo sviluppo della simulazione.
Nel Capitolo 2 segue una breve spiegazione dei metodi reticolari di Boltzmann
per la simulazione di fluidi.
Il Capitolo 3 descrive in profondit´ il programma sviluppato, mentre nel
                                      a
Capitolo 4 viene dato spazio ai test eseguiti e, nel Capitolo 5, alle relative
conclusioni.
Infine, in Appendice ´ riportato il programma realizzato in CUDA.
                      e
2
CUDA
                                                                                      1
In questo capitolo verranno presentati l’architettura CUDA, il calcolo paral-
lelo e saranno approfondite alcune caratteristiche utilizzate durante la rea-
lizzazione della simulazione.


1.1       Di cosa si tratta
L’unit´ di elaborazione grafica o GPU (acronimo di Graphics Processing
       a
Unit) ´ un microprocessore specializzato nel rendering1 di immagini grafiche
       e
inizialmente processate dalla CPU.
L’avanzamento sul mercato di videogiochi ad alta pretesa grafica, ha provoca-
to un’evoluzione sostanzale della potenza computazionale delle GPU rispetto
a quella delle CPU. Il grafico di Figura 1.1 mostra l’aumento di GFLOP/s2
dal 2003 al 2010 delle GPU NVIDIA rispetto alle CPU Intel.

    Nel Novembre del 2006 (come evidenziato dal grafico), NVIDIA Corpo-
ration lanci´ sul mercato la GeForce 8800 GTX, la prima GPU costruita con
            o
architettura CUDA.
CUDA (acronimo di Compute Unified Device Architecture), ´ un’architettura
                                                               e
hardware incentrata sul calcolo parallelo e rivolta in particolare alla program-
mazione general-purpose3 , supportata da un ambiente di sviluppo indirizzato
   1
     In ambito grafico, il rendering ´ il processo di “resa”, ovvero di generazione di un’im-
                                    e
magine a partire da una descrizione matematica di una scena tridimensionale interpretata
da algoritmi che definiscono il colore di ogni punto dell’immagine.
   2
     Acronimo di FLoating Point Operations Per Second, indica il numero di operazioni in
virgola mobile eseguite in un secondo.
   3
     Con questo termine vengono indicati software non specifici. In particolare, in questo
caso si fa riferimento a programmi di natura non strettamente grafica.
4                                                                                CUDA




            Figura 1.1: Differenza di prestazioni tra GPU e CPU. [5]


a semplificare il lavoro dei programmatori.
L’avvento di tale di tipo di architettura ´ stato reso necessario dalla sem-
                                          e
pre maggiore richiesta di poter utilizzare le GPU per eseguire programmi
general-purpose sfruttando i vantaggi del calcolo parallelo, fino a quel mo-
mento utilizzati solamente in ambito grafico.

   La potenza di CUDA ´ sostenuta dall’ambiente di sviluppo che l’ac-
                           e
compagna. Grazie ad esso infatti, molti complessi problemi computazionali
possono essere risolti con minor difficolt´ e spesso maggior efficienza che
                                         a
tramite CPU, in quanto, grazie all’aggiunta di nuove specifiche funzioni,
permette di programmare ad alto livello utilizzando diversi linguaggi, quali
C/C++ (dai quali deriva CUDA C ), Fortran, Java, Python, o interfacce di
programmazione (API ), come OpenCL e DirectCompute.


1.2       Il calcolo parallelo
Il calcolo parallelo costituisce un’importante evoluzione nel mondo della pro-
grammazione informatica, esso infatti consiste nel far eseguire un codice su
pi´ processori o core4 di uno stesso processore in modo tale da migliorare le
   u
    4
    Il termine inglese core ´ usato anche in italiano per indicare il nucleo elaborativo di
                            e
un calcolatore, ovvero la parte che esegue i calcoli e le funzioni principali.
1.2 Il calcolo parallelo                                                             5


prestazioni del sistema.

    In ambito CUDA, il calcolo parallelo viene implementato attraverso la
suddivisione di ogni problema in sotto-problemi, o thread 5 , risolvibili con-
temporaneamente da un gran numero di core indipendenti. I thread possono
essere raggruppati in blocchi che, a loro volta, possono essere racchiusi all’in-
terno di griglie. In Figura 1.2 sono mostrate le suddivisioni appena descritte.




                     Figura 1.2: Griglie, blocchi e thread. [2]


    Il modello di programmazione CUDA prevede che i thread vengano ese-
guiti su un dispositivo fisicamente separato (come la GPU), il quale opera da
coprocessore nei confronti di un dispositivo principale (la CPU) che elabora
il programma scritto (ad esempio) in C. Si far´ riferimento a questi due di-
                                                  a
spositivi utilizzando i termini inglesi di device e host, rispettivamente.
CUDA prevede inoltre che entrambi i dispositivi possiedano spazi di memoria
   5
    Il termine thread viene usato in informatica per indicare la parte elementare di un
processo.
6                                                                                 CUDA


in DRAM6 separate, alle quali si far´ riferimento nel corso della trattazione
                                     a
con i termini device memory e host memory. Ci´ implica per il programma-
                                                o
tore allocazioni e deallocazioni di memoria, cos´ come trasferimenti di dati
                                                ı
tra host memory e device memory.

    Sebbene programmare in ambiente CUDA non richieda la conoscenza det-
tagliata dell’hardware sottostante, il modo in cui i thread vengono lanciati e
le caratteristiche di elementi come le memorie, riflettono fortemente il modo
in cui sono organizzati i core e le locazioni di memoria all’interno della GPU.
Una scheda grafica di tipo CUDA ´ capace di ospitare al suo interno uno o
                                       e
                                     7
pi´ multiprocessori di tipo SIMD , ognuno composto da un gran numero di
  u
core, per un totale di decine o anche centinaia di core. Pi´ specificatamente,
                                                             u
ogni multiprocessore pu´ ospitare fino a 48 ALU8 e una unit´ di controllo.
                          o                                       a
Quest’ultima pu´ decodificare una sola istruzione alla volta, che verr´ poi
                  o                                                        a
eseguita contemporaneamente da pi´ thread. Ogni multiprocessore pu´ ese-
                                        u                                  o
guire fino a un determianto numero di thread in parallelo. Questo gruppo di
thread ´ chiamato warp 9 .
        e
Quanto descritto finora ´ riassunto in Figura 1.3.
                          e




Figura 1.3: Rappresentazione schematica del raggruppamento dei core in una
            GPU CUDA. [5]


    6
     Dynamic Random Access Memory, un particolare tipo di RAM.
    7
     Acronimo di Single Instruction, Multiple Data, si riferisce ad un’architettura in cui
pi´ unit´ elaborano dati diversi in parallelo. Questo modello ´ composto da un’unica
  u      a                                                         e
unit´ di controllo che esegue una istruzione alla volta controllando pi´ ALU che operano
     a                                                                  u
in maniera asincrona.
   8
     Acronimo di Arithmetic Logic Unit, o Unit´ Aritmetica-Logica, ´ un tipo di processore
                                                 a                   e
                                                                         ´
digitale predisposto all’esecuzione di operazioni aritmetiche o logiche. E una componente
fondamentale della CPU e della GPU.
   9
     Ordito, in italiano. Riferito alla tessitura, ´ un gruppo di fili intrecciati assieme in
                                                   e
modo da formare un tessuto. In inglese, thread significa “filo”, da cui il gioco di parole.
1.3 I kernel                                                                                 7


1.3         I kernel
Il linguaggio di programmazione CUDA C (estensione del classico C/C++)
permette al programmatore di definire funzioni chiamate kernel che, quando
invocate, vengono eseguite N volte in parallelo sul device da N differenti
thread CUDA, e non una volta sola, come accade regolarmente con le fun-
zioni in C. In particolare, un’istanza di un kernel corrisponde a un thread.

       I kernel hanno caratteristiche ben precise:
       • devono avere void come tipo di ritorno (quindi non devono tornare
         alcun valore);

       • non possono essere ricorsivi;

       • non possono avere un numero di parametri variabile;

       • non possono usare variabili di tipo statico10

       • possono accedere solo alla memoria della GPU.
    Per definire un kernel in un programma scritto in CUDA C, si utilizza
l’identificatore global anteposto alla sua dichiarazione. L’invocazione di
un kernel avviene all’interno del codice eseguito dalla CPU, chiamandone
il nome e specificando la configurazione di esecuzione all’interno di appositi
identificatori, <<<...>>>, nel seguente modo:

 kernel<<<gridDim,blockDim>>>(param 1,.., param n);

    Le dimensioni dei blocchi e delle griglie sono a discrezione del program-
matore, purch´ non eccedano i limiti imposti dall’hardware.
               e
La dimensione massima di un blocco di solito non ´ sufficiente a soddisfare le
                                                   e
esigenze delle applicazioni. Ci´ implica che ´ spesso necessario raggruppare
                               o              e
i thread in pi´ blocchi.
              u

    Ogni thread che esegue il kernel possiede un ID unico, accessibile all’in-
terno del kernel stesso attraverso la variabile threadIdx. In questo contesto,
´ anche possibile accedere all’ID univoco del blocco a 1,2 o 3 dimensioni in
e
cui ´ contenuto ogni thread, utilizzando la variabile blockIdx. Grazie a ci´,
    e                                                                          o
´ sempre possibile per ogni thread calcolare l’indirizzo dei dati a cui accedere.
e
Questa operazione pu´ essere implementata con pi´ indici, come mostrato
                       o                               u
  10
    Non possono, cio´, allocare variabili il cui tempo di vita sia esteso a tutto il programma,
                     e
e quindi oltre la durata del kernel stesso.
8                                                                                     CUDA


in Figura 1.4, oppure trasformando un indice a pi´ dimensioni in un indice
                                                 u
monodimensionale (indice assoluto), nel seguente modo:

 int offset = x + y * blockDim.x * gridDim.x;




      Figura 1.4: Indicizzazione di una griglia di blocchi a due dimensioni. [5]


sfruttando le variabili predefinite contenenti le dimensioni di ogni blocco e di
ogni griglia, blockDim e gridDim.

    Ogni blocco ´ assegnato a un multiprocessore che, come gi´ spiegato nella
                  e                                              a
Sezione 1.2, pu´ eseguire simultaneamente solo un certo numero di thread
                  o
alla volta (un warp). Quando il numero di thread ´ maggiore del numero
                                                        e
di core, viene eseguito un cambio di contesto (in gergo informatico, context
switch 11 ), che permette a tutti i thread di essere completati.
Quando un thread pone una richiesta di memoria, che pu´ richiedere diversi
                                                            o
minuti, il cambio di contesto permette l’esecuzione di altri thread mentre il
primo resta in attesa dei dati dalla memoria. Questa soluzione di istanziare
pi´ thread rispetto ai core disponibili, permette di ottenere un elevato rendi-
  u
mento in termini di tempo, in quanto la perdita dovuta alle richieste di
    11 ´
    E un particolare stato del sistema operativo durante il quale avviene il cambiamento
del processo correntemente in esecuzione. Si svolge in due fasi: la prima consiste nel
salvataggio dello stato attuale per consentirne il rispristino; la seconda consiste nella scelta
del nuovo processo da eseguire e nell’apertura del suo contesto.
1.4 Tipi di memoria                                                                     9


memoria ´ coperta da altre computazioni.
          e
Un altro fattore che pu´ influire negativamente sul tempo di esecuzione ´
                         o                                                      e
la divergenza dei thread. Essa avviene quando alcuni thread necessitano di
eseguire alcune istruzioni mentre gli altri no. In normali circostanze, quest’ul-
timi restano inattivi mentre gli altri eseguono le loro istruzioni, ma ´ sempre
                                                                        e
meglio evitare che thread di uno stesso warp divergano.


1.4       Tipi di memoria
L’architettura CUDA mette a disposizione dei programmatori alcuni tipi di
memoria, utilizzabili diversamente a seconda del livello di profondit´ rag-
                                                                       a
giunto nella suddivisione del codice e dello scopo a cui saranno destinati.
In particolare, la suddivisione della memoria ´ la seguente:
                                               e
       Registri: privata, a disposizione di ogni singolo thread.
       Memoria molto veloce, a cui non ´ possibile accedere direttamente. Il
                                            e
       numero totale di registri ´ fissato e deve quindi essere suddiviso tra
                                   e
       tutti i thread, limitando di fatto il numero di thread che possono essere
       eseguiti simultaneamente.
       Memoria locale: privata, a disposizione di ogni singolo thread.
       Questa memoria viene occupata quando non c’´ pi´ spazio all’inter-
                                                           e u
       no dei registri. Essendo conservata nella DRAM, ha un’alta latenza 12 .
       Memoria locale e registri vengono utilizzati solitamente per memoriz-
       zare variabili locali e intermedie di ogni singolo thread.
       Memoria condivisa: a disposizione di tutti i thread di un blocco.
       ´
       E molto veloce (quasi quanto i registri) in quanto interna ad ogni mul-
       tiprocessore (o pi´ tecnicamente, on chip). Per ottenere la massima
                         u
       larghezza di banda13 durante i trasferimenti di dati, questa memoria ´e
       suddivisa in moduli di uguale grandezza, chiamati banchi (o banks in
       inglese), che possono essere acceduti simultaneamente. Viene spesso
       utilizzata per condividere risultati tra tutti i thread del blocco.
       Memoria globale: a disposizione di tutti i blocchi.
       Tipicamente implementata tramite una DRAM ( e quindi off-chip), ha
       lunga latenza in termini di clock (centinaia di cicli) ed una limitata
       larghezza di banda.

  12
     In informatica, la latenza ´ il tempo che intercorre tra l’inizio dell’esecuzione di
                                  e
un’istruzione e il momento in cui ´ disponibile il suo risultato.
                                    e
  13
     Indica la quantit´ di dati che possono essere trasferiti in un dato periodo di tempo.
                      a
10                                                                             CUDA


Una schematica descrizione di queste divisioni ´ riportata in Figura 1.5.
                                               e




Figura 1.5: Suddivisione della memoria. In rosso sono evidenziate le memorie a
            bassa latenza, mentre in arancione quelle a latenza pi´ elevata.
                                                                  u

   Esistono anche due tipi di memoria a sola lettura accessibili da tutti i
thread:

       Texture memory: memoria a sola lettura. Risiede nella DRAM, ma, a
       differenza della memoria globale, pu´ essere copiata all’interno di ogni
                                            o
       multiprocessore in una memoria cache14 . Se usata in modo consapevo-
       le, permette di ridurre considerevolmente i tempi, eliminando richieste
       di memoria off-chip. In particolare, questo tipo di memoria ´ apposita-
                                                                    e
       mente pensato per tutte quelle applicazioni grafiche in cui l’accesso alla
       memoria avviene secondo il principio di localit´. Per un’applicazione
                                                       a
  14
    La memoria cache ´ una memoria temporanea, non visibile al software, che memorizza
                      e
un insieme di dati in maniera tale da essere velocemente recuperati. In particolare, esse
fanno in modo che letture consecutive di uno stesso indirizzo di memoria non comportino
alcun traffico addizionale.
1.4 Tipi di memoria                                                        11


     general-purpose, questo significa che un thread tende ad accedere a
     spazi di memoria fisicamente vicini a quelli usati dai thread che lo han-
     no preceduto. In Figura 1.6 ´ riportato un esempio di localit´ spaziale
                                 e                                 a
     nelle richieste di memoria.




                    Figura 1.6: Principio di localit´. [3]
                                                    a



     Memoria costante: come suggerisce il nome, ´ una memoria non molto
                                                     e
     grande a sola lettura (per la GPU), riservata a dati destinati a non
     cambiare durante l’esecuzione di un kernel. Considerando che anch’essa
     pu´ essere copiata all’interno di ogni multiprocessore, il suo corretto
        o
     utilizzo permette di risparmiare richieste alla memoria globale in quanto
     una lettura da quella costante pu´ essere trasmessa a thread vicini,
                                          o
     ovvero appartenenti allo stesso mezzo-warp (16 thread), risparmiando
     quindi fino a 15 letture e riducendo (nel migliore dei casi) a 1/16 il
     traffico in memoria.

Le memorie di tipo globale, costante e texture sono persistenti durante l’e-
laborazione dei thread di una stessa applicazione.

    Un particolare molto importante da ricordare ´ che i thread della GPU
                                                   e
non possono accedere direttamente alla memoria dell’host (e viceversa). Il
passaggio di dati (tra memoria globale del device e memoria dell’host) ´  e
comunque reso possibile da particolari funzioni per l’allocazione, la copia
e la deallocazione di spazi di memoria, quali ad esempio cudaMalloc(),
cudaMemcpy() e cudaFree() rispettivamente, per quanto riguarda gli spazi
monodimensionali. L’uso di queste direttive ´ il seguente:
                                            e

 cudaMalloc(**pointer, n bytes)
 cudaMemcpy(*dst, *src, n bytes, direction);
 cudaFree(*pointer);
12                                                                             CUDA


dove n bytes ´ la grandezza in byte dei dati da copiare, mentre direction
               e
specifica la direzione dell’operazione di copia, e pu´ essere cudaMemcpyHostTo
                                                    o
Device, cudaMemcpyDeviceToHost o cudaMemcpyDeviceToDevice.


1.5         La compilazione
La compilazione ´ il processo di trasformazione di un file sorgente scritto in
                  e
un linguaggio ad alto livello, in un file binario comprensibile all’elaboratore.
Il software fornito direttamente da NVIDIA include anche un compilatore
(nvcc), che permette di semplificare il processo di compilazione dei sorgenti
scritti in CUDA C, grazie a semplici e familiari opzioni impartibili a riga di
comando.

   I file sorgenti possono contenere sia codice da eseguire sull’host che codice
da eseguire sul device . Il processo di compilazione con nvcc ´ il seguente:
                                                                e

       • Il codice relativo al device viene separato da quello dell’host.

       • Il codice del device viene compilato in un tipo di assembly detto codice
         PTX 15 e/o in una forma binaria detta CUBIN 16 .

       • Il codice dell’host viene modificato sostituendo ogni <<<...>>> con
         le chiamate di funzione per caricare e lanciare ogni kernel compilato,
         partendo dal PTX e/o dal CUBIN.

       • Il codice dell’host rimasto viene passato ad un normale compilatore C
         prefissato (come gcc su piattaforme Linux o il Microsoft Visual C++
         Compiler in ambienti Windows) e il file binario cos´ ottenuto viene
                                                              ı
         collegato all’oggetto binario CUBIN.

Il file binario ottenuto pu´ quindi essere mandato in esecuzione.
                          o
In Figura 1.7 ´ riassunto il procedimento appena descritto.
               e




  15                            ´
    Parallel Thread eXecution. E una forma di assembly proprietaria, ovvero il linguaggio
macchina specifico delle architetture CUDA, sempre compatibile con quelle di capacit´    a
computazionale superiore.
  16 ´
    E il codice binario per le GPU. Quando un’applicazione CUDA ´ in esecuzione, essa
                                                                   e
carica il file CUBIN nella GPU, se compatibile, altrimenti esegue una compilazione al
momento, per produrre il codice CUBIN appropriato a partire dal PTX.
1.5 La compilazione                                       13




               Figura 1.7: Fasi della compilazione. [8]
14   CUDA
Boltzmann e i metodi reticolari
                                                                                   2
In questo capitolo verranno descritti i metodi reticolari di Boltzmann e il loro
utilizzo nella simulazione dei flussi di fluidi bifase.


2.1       I metodi reticolari
I metodi reticolari di Boltzmann1 sono un utile strumento per la simulazione
della dinamica di fluidi. Essi semplificano ampiamente le equazioni che ne
regolano il movimento, riducendo il numero di possibili posizioni assumibili
dalle particelle, passando cos´ da un modello continuo a uno discreto, in
                                ı
quanto si basa su un approccio di tipo statistico.
In particolare, le posizioni in questione vengono ridotte ai nodi di un reti-
colo (in inglese lattice), motivo per cui si parla di Metodi Reticolari, o pi´
                                                                             u
frequentemente in inglese, di Lattice Boltzmann Methods o LBM.
Il plurale proviene dal fatto che esistono diversi metodi che utilizzano l’e-
quazione di Boltzmann, ognuno differente dall’altro per numero di dimen-
sioni considerate (D) e numero di velocit´ (Q). In Figura 2.1 sono mostrati
                                           a
alcuni esempi.



    I metodi reticolari sono basati su due fenomeni: la collisione e la propa-
gazione.
La collisione ´ il momento in cui le particelle di fluido in un nodo del reti-
               e
colo si rilassano verso uno stato di equilibrio, mentre la propagazione (o, pi´
                                                                              u
   1
     Ludwig Boltzmann (Vienna, 1844 - Duino, 1906), fisico e matematico, famoso per
le sue ricerche in termodinamica e meccanica statistica, tra cui l’equazione fondamentale
della teoria cinetica dei gas e il secondo principio della termodinamica.
16                                             Boltzmann e i metodi reticolari




              Figura 2.1: Esempi di modelli reticolari di Boltzmann


frequentemente, streaming, in inglese) ´ la situazione durante la quale le par-
                                        e
ticelle di un nodo si muovono verso i nodi adiacenti. Queste due fasi verranno
approfondite maggiormente nella Sezione 2.3.


2.2       Il modello D2Q9
Per la realizzazione della simulazione ´ stato utilizzato il modello D2Q9. Esso
                                       e
´ caratterizzato da 2 dimensioni e 9 velocit´.
e                                             a
                                          2
In particolare, le variazioni di momento che avrebbero potuto esserci in un
sistema continuo di direzioni di velocit´, grandezze e diversa massa delle
                                           a
particelle, sono ridotte a 9 direzioni (da 0 a 8), 3 grandezze e una singola
massa, e quindi ad un sistema discreto. Dal momento che la massa delle
particelle ´ uniforme (1 unit´ di massa nel caso pi´ semplice), momenti e
           e                   a                        u
velocit´ microscopiche sono di fatto equivalenti.
       a
In Figura 2.2 ´ mostrato il reticolo di Boltzmann del modello D2Q9.
               e




                            Figura 2.2: Il modello D2Q9

Le velocit´ microscopiche delle particelle in un nodo del reticolo sono indicate
          a
   2
    Nella meccanica classica, il momento, o quantit´ di moto, ´ il vettore ottenuto molti-
                                                   a           e
plicando la massa per la velocit´ dell’oggetto in esame. Esso misura la capacit´ di un
                                 a                                                a
corpo di modificare il movimento di altri corpi con cui interagisce dinamicamente.
2.2 Il modello D2Q9                                                              17


con ea , a = 0, 1, ..., 8, dove e0 = 0 indica la velocit´ della particella a riposo.
                                                        a
Lo schema pi´ frequentemente usato, prevede di attribuire a queste velocit´
               u                                                                   a
valori tali da ottenere le componenti come indicato in Figura 2.3.




       Figura 2.3: D2Q9, componenti x e y delle velocit´ microscopiche
                                                       a

Quindi i moduli saranno i seguenti:
                              
                               0   se a = 0
                      |ea | =   1   se a = 1, 2, 3, 4                         (2.1)
                               √
                                  2 se a = 5, 6, 7, 8


    Il passo successivo consiste nell’incorporare la funzione di distribuzione
(f ), che non viene pi´ considerata una funzione continua, ma costituita da
                      u
soli 9 elementi. Essa rappresenta la frequenza di occorrenza di ogni singola
velocit´, ovvero la densit´ specifica del fluido in ogni direzione.
        a                 a
Di conseguenza, la densit´ macroscopica del un fluido si ottiene cos´
                          a                                           ı:
                                          8
                                    ρ=         fa                             (2.2)
                                         a=0




    La velocit´ macroscopica, invece, si ottiene come risultato della media
               a
delle velocit´ microscopiche pesata secondo le densit´ direzionali fa :
             a                                       a
                                          8
                                     1
                                  u=           fa ea                          (2.3)
                                     ρ   a=0
18                                               Boltzmann e i metodi reticolari


Questa semplice equazione permette di passare dalle velocit´ discrete micro-
                                                           a
scopiche del modello LBM alle velocit´ continue macroscopiche rappresen-
                                     a
tanti il movimento del fluido.

   Introdotti gli elementi principali, verr´ ora presentato un importante
                                           a
metodo di approssimazione delle equazioni che regolano la dinamica dei fluidi.


2.3       L’approssimazione BGK
L’approssimazione BGK (Bhatnagar-Gross-Krook) ´ il metodo pi´ utilizzato
                                                     e            u
nelle simulazioni che fanno uso dei metodi reticolari meno complessi.
Pubblicata nel 1954, essa prevede che le equazioni di propagazione e collisione
vengano semplificate come segue:

                                                          1 eq
           Collisione:       fa (x, t + δt) = fa (x, t) + [fa (x, t) − fa (x, t)] (2.4)
                                                          τ
       Propagazione:         fa (x + ea δt, t + δt) = fa (x, t + δt)              (2.5)

Sebbene possano essere combinate in un’unica equazione, ´ meglio tenerle
                                                              e
separate se nella simulazione sono previsti confini solidi, in quanto il rimbal-
zo delle particelle contro di essi costituisce una condizione al contorno ben
precisa, che dovr´ essere trattata con un termine di collisione differente.
                     a
   La collisione delle particelle di un fluido ´ considerata come il rilassa-
                                                 e
mento verso uno stato di equilibrio locale. Nel modello D2Q9 la funzione di
equilibrio (f eq ) ´ approssimata nel seguente modo:
                   e

                                             ea · u 9 (ea · u)2 3 u2
                 eq
                fa (x) = wa ρ(x) 1 + 3             +           −                        (2.6)
                                               c2    2 c4        2 c2
dove wa sono i pesi, mentre c ´ la velocit´ base3 degli spostamenti lungo il
                                 e         a
reticolo. I pesi sono assegnati in questo modo:
                                    
                                    
                                    
                                        4
                                             se a = 0
                                    
                                    
                                        9
                                    
                                        1
                             wa =            se a = 1, 2, 3, 4                          (2.7)
                                    
                                    
                                        9
                                    
                                    
                                        1
                                        36
                                             se a = 5, 6, 7, 8
   3
    Ipotizzando che la distanza tra due punti adiacenti nel reticolo sia 1 lu (lattice unit) e
che l’unit´ di tempo sia 1 ts (time step), allora la velocit´ base ´ 1 lu ts−1 , considerando
          a                                                 a      e
l’implementazione pi´ semplice.
                     u
2.4 Condizioni al contorno                                                   19

´
E da notare che se la velocit´ macroscopica u = 0, la funzione di equilibrio
                             a
risulta essere semplicemente il prodotto dei pesi per la densit´ macroscopica
                                                               a
del fluido.


2.4      Condizioni al contorno
I metodi reticolari di Boltzmann hanno riscosso molto successo nell’ambito
delle simulazioni di fluidi per la loro semplicit´ di utilizzo. In particolare,
                                                a
permettono di implementare con notevole facilit´ le condizioni al contorno
                                                  a
di ogni problema.

    Le condizioni al contorno sono tutte quelle situazioni che deveno essere
gestite in modo diverso dal resto della simulazione.
Ne esistono di vario genere e per ognuna ´ stato sviluppato un metodo di
                                            e
trattamento specifico. Di seguito alcuni esempi:
      Condizioni al contorno periodiche: permettono di simulare fenomeni a
      sviluppo infinito, come la re-iniezione di fluido all’interno del canale.
      Gradiente di pressione: consente di simulare il flusso di un fluido
      all’interno di un mezzo poroso.
      Condizioni al contorno di Von Neumann: permettono di imporre una
      condizione di velocit´ dalla quale poi ricavare densit´ e pressione, sulla
                           a                                a
      base delle condizioni interne al dominio.
      Condizioni al contorno di Dirichlet: vengono posti dei vincoli su pres-
      sione e densit´ per poi ricavare le velocit´.
                    a                            a
      Condizioni al contorno per il rimbalzo: definiscono la dinamica del
      rimbalzo delle particelle contro i bordi delle superfici solide.
   Quest’ultime, in particolare, verranno approfondite nella prossima sot-
tosezione, in quanto utilizzate ai fini della simulazione.

2.4.1     Rimbalzo
Le condizioni al contorno per il rimbalzo (in inglese bounceback boundaries)
vengono utilizzate per simulare la presenza di superfici solide nel dominio di
simulazione. All’interno di esse, la velocit´ delle particelle viene considerata
                                            a
nulla, permettendo cos´ di distinguere queste aree da quelle occupate da flu-
                       ı
ido.
20                                       Boltzmann e i metodi reticolari


   Quando, ad un certo istante di tempo, una particella arriva ad un nodo
(del reticolo) appartenente ad una superficie solida, al passo successivo viene
rimandata indietro nella stessa direzione da cui ´ arrivata, conservandone le
                                                  e
densit´ e mantendo inalterati il modulo e la direzione della velocit´ di arrivo,
       a                                                            a
ma cambiandone il verso.

    Un modo per ottenere questo consiste nel memorizzare all’interno dei
bordi solidi le distribuzioni di densit´ al tempo t, per poi farle “riemergere”
                                       a
al tempo t + δt. Questa schema procedurale ´ chiamato in inglese mid-plane
                                               e
bounceback, in quanto l’effettiva posizione della parete di rimbalzo si trova a
met´ tra i nodi solidi e il fluido, ed ´ riportato in Figura 2.4.
    a                                 e




                 Figura 2.4: Rimbalzo di tipo mid-plane. [4]
2.5 ILBM e fluidi multifase                                                   21


2.5      ILBM e fluidi multifase
Quanto descritto nelle sezioni precedenti riguarda l’applicazione dei metodi
di Boltzmann ai soli casi di simulazione di fluidi monofase. In realt´, in
                                                                       a
natura ´ molto pi´ comune avere a che fare con flussi di fluidi aventi diverse
       e          u
propriet´, ovvero fluidi multifase.
        a

    Un caso particolare di fluidi multifase sono i fluidi immiscibili, per i quali
esiste un metodo di Boltzmann appropriato, ossia l’Immiscible lattice Boltz-
mann Method o ILBM. Dovendo considerare due fluidi immiscibili, questo
metodo risulta pi´ complesso di quello descritto in precedenza, in quanto ´
                  u                                                           e
necessario tenere in considerazione non solo l’influenza della tensione super-
ficiale che si genera, ma anche la bagnabilit´ relativa di entrambi i fluidi nei
                                              a
confronti delle superfici solide, e le complesse dinamiche che si sviluppano in
corrispondenza delle interfacce di contatto tra le due sostanze.

    Il metodo di Boltzmann per fluidi immiscibili, introdotto nel 1988 da
Rothman e Keller [6], segue la stessa linea procedurale utilizzata per i fluidi
monofase, considerando per´ la presenza di due diversi tipi di particelle. Ci´
                              o                                               o
comporta un raddoppiamento delle informazioni in ogni nodo del reticolo.
Il punto cruciale di questo modello bifase ´ rappresentato dall’interazione
                                              e
tra i due fluidi, la quale viene simulata mediante un’interazione locale tra
particelle dello stesso tipo e una repulsione tra particelle di tipo diverso.


2.5.1     Interfaccia e gradiente di colore
L’interfaccia ´ la zona di contatto tra due fluidi, ovvero tutti quei nodi nei
              e
quali sono presenti presenti valori di densit´ di entrambi i tipi, come mostrato
                                             a
in Figura 2.5. Per scoprire se un nodo del reticolo si trova in questa zona, ´ e
necessario calcolare il gradiente di colore.




               Figura 2.5: Densit´ nelle zone di interfaccia. [7]
                                 a
22                                       Boltzmann e i metodi reticolari


   Il gradiente di colore ´ un vettore le cui componenti in un punto (x, y)
                           e
sono le derivate parziali prime calcolate in quel punto, ovvero:
                              1 R−B
                         Gx =   ρ   − ρR−B                                 (2.8)
                              2 x+1    x−1

                              1 R−B
                         Gy =   ρ   − ρR−B                                 (2.9)
                              2 y+1    y−1


dove R e B corrispondono a rosso e blu, i colori assegnati ai due fluidi im-
miscibili (ad esempio, olio e acqua, rispettivamente), e ρR−B = ρR − ρB . Ai
fini della simulazione, le aree solide (che nel nostro caso sono delimitate dal
perimetro dell’area bagnata) hanno densit´ macroscopica ρS = −1, in modo
                                            a
tale da far concentrare verso l’interno il fluido rosso.

  Con i valori calcolati rispetto agli assi cartesiani, ´ possibile calcolare il
                                                        e
modulo e l’angolo del gradiente:

                              |G| =    G 2 + G2
                                         x    y                          (2.10)
                                          Gy
                           θG = arctan                                   (2.11)
                                          Gx

Il primo consente di stabilire se una determinata particella si trova nella
zona di interfaccia, a seconda che sia minore o maggiore di un certo valore
di soglia minima. Questo ´ sensato dal momento che il modulo del gradiente
                           e
´ grande nelle zone appartenenti all’interfaccia ed ´ invece trascurabile nelle
e                                                   e
zone contenenti fluido di un solo tipo.


2.5.2     La ricolorazione
La ricolorazione consiste nella redistribuzione delle densit´ microscopiche
                                                              a
delle particelle appartenenti all’interfaccia lungo le direzioni, in modo tale
da spingerle verso particelle dello stesso fluido, conservandone per´ la massa
                                                                     o
totale. In Figura 2.6 ´ rappresentato questo meccanismo.
                      e




                 Figura 2.6: Meccanismo di ricolorazione. [7]
2.5 ILBM e fluidi multifase                                                    23


    Se un nodo del reticolo risulta essere appartenente ad una zona di interfac-
cia, il suo gradiente di colore sar´ elevato. Tramite il calcolo della proiezione
                                   a
del gradiente lungo le direzioni delle velocit´ microscopiche (Figura 2.7), ´
                                               a                                e
possibile ordinare quest’ultime in base alla maggiore vicinanza con il gradi-
ente, determinando cos´ le direzioni verso cui sono pi´ attratte le particelle
                          ı                              u
dei due fluidi.




Figura 2.7: Definizione delle priorit´ delle direzioni mediante il calcolo delle
                                     a
            proiezioni del gradiente su di esse.

Il calcolo della proiezione ortogonale del gradiente lungo ogni velocit´ micro-
                                                                       a
scopica si ottiene attraverso il prodotto scalare dei due vettori, nel seguente
modo:
                           Ga = G · ea = Gx ex + Gy ey                    (2.12)
24   Boltzmann e i metodi reticolari
Simulazione mediante CUDA
                                                                              3
In questo capitolo verr´ descritta la simulazione oggetto di questa tesi e sar´
                       a                                                      a
quindi presentato e spiegato il codice creato.


3.1      Strumenti utilizzati
Per la realizzazione del codice sono stati utilizzati i seguenti strumenti:
      Hardware
        – Scheda grafica NVIDIA GeForce GTX 460
        – Processore Intel Core i7-990X
      Software
        – Sistema operativo Windows 7 Enterprise, 64-bit
        – CUDA Toolkit 4.1
        – NVIDIA Driver 295.73
        – GLUT 3.7.6
        – Visual Studio x64 Command Prompt (2010)
        – Notepad++

3.1.1     Specifiche tecniche
Scheda grafica
La scheda grafica utilizzata ´ ormai stata superata in termini di prestazioni
                             e
da altre del suo genere, ma ´ risultata comunque efficace ai fini del lavoro
                              e
svolto. Alcune caratteristiche rilevanti sono riportate in Tabella 3.1
26                                                Simulazione mediante CUDA


 Capacit´ computazionale1
         a                                                      2.1
 Memoria globale                                                2GB
 Multiprocessori                                                7
 CUDA core                                                      336 (48x7MP)
 Dimensione cache L2                                            524288 bytes
 Registri per blocco                                            32768
 Grandezza warp                                                 32 thread
 Massimo numero thread per blocco                               1024
 Grandezza massima delle dimensioni di un blocco                1024 x 1024 x 64
 Grandezza massima delle dimensioni di una griglia              65535 x 65535 x 65535

            Tabella 3.1: Alcune specifiche tecniche della scheda grafica.



3.2        La simulazione
Il codice oggetto di questa tesi permette di simulare il fenomeno della decom-
posizione spinodale tra due fluidi immiscibili. La decomposizione spinodale
´ un meccanismo per il quale una miscela di due (o pi´) componenti viene
e                                                          u
separata in due distinte regioni (o fasi), con diverse propriet´ chimico-fisiche.
                                                               a
In questa simulazione sono presenti due fluidi (come potrebbero essere acqua
e olio) rappresentati da due diversi colori (blu e rosso, rispettivamente). In
Figura 3.1 ´ riportato l’avanzamento della simulazione in diversi istanti di
            e
tempo crescenti.




       Figura 3.1: Simulazione del fenomeno della decomposizione spinodale.


   1
    E’ un indice identificativo del tipo di architettura CUDA, costituito da due valori. Il
primo indica il tipo di architettura dei core, mentre il secondo indica un miglioramento
incrementale dell’architettura dei core e/o l’aggiunta di nuove funzionalit´.
                                                                           a
3.3 Il codice                                                             27


3.3     Il codice
In questa sezione verr´ analizzato il codice prodotto.
                      a


3.3.1    Diagramma di flusso
In Figura 3.2 sono riportate alcune informazioni preliminari per una corretta
comprensione del codice, mentre in Figura 3.3 ´ riportato il diagramma di
                                                 e
flusso.




                    Figura 3.2: Informazioni preliminari.
28   Simulazione mediante CUDA
3.3 Il codice                                     29




                Figura 3.3: Diagramma di flusso.
30                                                  Simulazione mediante CUDA


3.3.2        Inizio
Il codice presenta prima di tutto l’inizializzazione delle variabili globali.
Subito dopo vengono implementate tutte le funzioni. Per maggior chiarezza,
il codice integrale ´ riportato in Appendice.
                    e

    L’esecuzione del programma ha inizio all’interno della funzione main. Qui
sono inizializzate le quattro matrici principali, sottoforma di lunghi vettori2 .
In particolare, alla matrice Red vengono assegnati dei valori casuali e di con-
seguenza anche a Blue, essendo quest’ultima calcolata sulla base della prima.
Le matrici bidimensionali RhoR e RhoB, invece, sono calcolate come somma
lungo le nove direzioni di profondit´ di ogni elemento delle altre due matrici.
                                    a

   Le matrici Red e Blue, quindi, corrispondono alle funzioni di distribuzione
(vedi Sezione 2.2) dei due fluidi, mentre RhoR e Blue corrispondono alle loro
densit´ macroscopiche.
      a

    Terminata l’inizializzazione, si procede con l’allocazione della memoria da
utilizzare sul device, e con la copia delle quattro matrici all’interno delle lo-
cazioni appena create, utilizzando le funzioni CUDA descritte nella Sezione 1.4.
Quindi viene richiamato il metodo anim and exit, appartenente alla strut-
tura bitmap. Questo ´ il metodo che permette l’animazione grafica (descritta
                       e
brevemente nella Sezione 3.3.4), il quale richiede l’esecuzione di altre due fun-
zioni: anim gpu, che contiene le chiamate ai kernel, e anim exit, che contiene
le direttive di deallocazione della memoria precedentemente istanziata sul de-
vice.

   All’inizio della funzione anim gpu, vengono dichiarate le variabili grid e
threads, che contengono rispettivamente il numero totale di blocchi all’in-
terno della griglia e di thread all’interno di ogni blocco. dim3 ´ un tipo di
                                                                  e
dato predefinito di CUDA. In particolare, ´ un tipo di vettore tridimensionale
                                           e
che permette di specificare fino a tre valori per la variabile dichiarata3 .


3.3.3        I kernel
I primi quattro kernel realizzati hanno lo scopo di eseguire i calcoli previsti
dal metodo di Boltzmann descritto nella Sezione 2.5, mentre l’ultimo ´ impli-
                                                                       e
cato nella resa grafica e verr´ quindi brevemente descritto nella Sezione 3.3.4.
                             a

  2
      Ci si riferir´ comunque a questi vettori utilizzando il termine “matrici”.
                   a
  3
      Valori eventualmente non dichiarati vengono automaticamente posti a 1.
3.3 Il codice                                                                           31


    Non esistendo delle direttive apposite, ´ stato deciso di dividere i kernel
                                               e
per ottenere la certezza che tutti i thread di tutti i blocchi fossero sincroniz-
zati tra loro4 , cos´ da evitare conflitti di tipo RAW (lettura dopo scrittura),
                    ı
WAR (scrittura dopo lettura) oppure WAW (scrittura dopo scrittura).

   Ogni kernel ´ costruito per essere eseguito su ogni pixel dell’immagine
                e
finale, ovvero per calcolare ogni singolo elemento delle matrici RhoR e RhoB.

Collision
In questo kernel viene trattata la collisione delle particelle di fluido all’inter-
no di ogni nodo5 del reticolo.
All’inizio della sua esecuzione, vengono copiate alcune variabili dalla memo-
ria globale a quella locale, permettendo cos´ di evitare continue richieste di
                                              ı
memoria off-chip. Tra queste variabili ci sono anche due vettori (R e B) che
servono a memorizzare i valori contenuti in Red e Blue nella stessa posizione
assunta dal thread (che lo sta eseguendo) rispetto alla griglia. Questa po-
sizione ´ facilmente ricavabile sfruttando le variabili predisposte da CUDA,
        e
come descritto nella Sezione 1.3.
La collisione consiste nel rilassamento verso l’equilibrio, per cui viene im-
plementata tramite il calcolo della funzione di equilibrio lungo tutte le nove
direzioni e la correzione delle funzioni di densit´ locali R e B.
                                                  a
Infine, vengono ricalcolate RhoR e RhoB per poterne calcolare la differenza
(memorizzandola direttamente nella memoria globale nella matrice puntata
dal puntatore ptRhoR B) da utilizzare nel kernel successivo.

Recoloring
Questo ´ il kernel in cui avviene il trattamento delle zone di interfaccia se-
         e
condo quanto descritto nelle Sezioni 2.5.1 e 2.5.2.
Per il calcolo del gradiente di colore, vengono utilizzati i valori delle differenze
di densit´ macroscopiche delle posizioni adiacenti in verticale e in orizzontale
          a
alla posizione di ogni thread. Questo ´ uno dei casi in cui ´ assolutamente
                                          e                       e
necessario che tutti i thread abbiano concluso le operazioni inserite nel kernel
precedente.
Una volta calcolato il modulo del gradiente, questo viene usato per decidere
se un certo nodo appartiene a una zona di interfaccia oppure no. Se il respon-
   4
     Esistono invece delle funzioni CUDA C per la sincronizzazione di tutti i thread
appartenenti ad un blocco.
   5
     In questo caso, ogni nodo corrisponde a un pixel, ovvero ad una posizione delle matrici
RhoR o RhoB.
32                                                 Simulazione mediante CUDA


so ´ positivo, viene calcolata la tensione superficiale 6 lungo tutte le direzioni,
   e
e viene quindi eseguita la ricolorazione dell’interfaccia. Questa differenza di
esecuzione pu´ causare il fenomeno della divergenza dei thread descritto nella
               o
Sezione 1.3, facendo cos´ aumentare il tempo di esecuzione dell’intero kernel.
                          ı
Infine, vengono eseguite delle operazioni che in realt´ apparterrebbero alla
                                                          a
fase di propagazione. Il motivo di questa scelta riguarda sempre la sin-
cronizzazione dei thread. Le operazioni anticipate sono quelle riguardanti
le condizioni al contorno, ovvero il rimbalzo delle particelle contro i bordi
dell’area di simulazione. Queste condizioni vengono implementate copiando
i valori attuali delle matrici Red e Blue in due matrici temporanee7 , salvando
in Red e Blue i nuovi valori dopo il rimbalzo, secondo lo schema di Figu-
ra 2.4 e Figura 2.2, e poi impostando al valore −1 le direzioni delle matrici
temporanee che hanno sub´ il rimbalzo.
                              ıto


Streaming e Streaming2

La parte iniziale del kernel Streaming ´ occupata dal calcolo degli indici as-
                                         e
soluti delle otto posizioni adiacenti a quella di ogni thread in esecuzione.
Dopodich´ avviene la fase di propagazione vera e propria. Questa consiste
           e
nel copiare i valori contenuti nelle matrici temporanee nelle stesse direzioni
delle locazioni delle matrici Red e Blue adiacenti alla posizione considerata.
Se per´ il valore salvato in una direzione delle matrici temporanee ´ pari a
       o                                                               e
−1, allora la propagazione verso quella direzione non avviene, in quanto gi´ a
trattata dal kernel precedente.
Il kernel denominato Streaming2 si occupa semplicemente del ricalcolo delle
matrici RhoR e RhoB. Anch’esso ´ stato diviso da quello precedente per con-
                                  e
sentire la sincronizzazione delle operazioni sulle matrici Red e Blue.



3.3.4      L’animazione grafica
Non essendo lo scopo di questa tesi, per la resa grafica della simulazione sono
stati usati dei codici predisposti da NVIDIA e reperibili online. Per una
trattazione pi´ esaustiva consultare [3].
              u
Questi codici sono basati sull’interoperabilit´ di CUDA con una tra le pi´
                                               a                             u

   6
      Dal punto di vista fluidodinamico, ´ una particolare tensione meccanica che si sviluppa
                                        e
lungo la superficie di separazione (interfaccia) tra due fluidi.
    7
      In realt´ non sono temporanee, sono allocate nella memoria globale esattamente come
              a
le altre, ma vengono chiamate cos´ ai fini dell’implementazione.
                                   ı
3.3 Il codice                                                                       33


popolari API di resa grafica in tempo reale, ovvero OpenGL8 (e GLUT9 ).

   Per assegnare i colori ad ogni pixel dell’immagine, viene utilizzato il kernel
float to color. A seconda che in una certa posizione prevalga il colore rosso
piuttosto che il blu, viene impostato il colore adeguato sfruttando i quattro
campi10 di ogni elemento della matrice output bitmap, utilizzata per la resa
grafica.




   8
     Open Graphics Library, sviluppata da ATI (ora AMD), ´ una specifica che definisce
                                                            e
una API per pi´ linguaggi e per pi´ piattaforme per scrivere applicazioni che producono
               u                    u
grafica 2D e 3D.
   9
     OpenGL Utility Toolkit, ´ una libreria che semplifica l’accesso alle funzionalit´ di
                               e                                                    a
OpenGL.
  10
     Corrispondenti a rosso, verde, blu e fattore alpha
34   Simulazione mediante CUDA
Test finali
                                                                          4
4.1     La misurazione dei tempi
La misurazione del tempo di esecuzione di un programma ´ sempre un’op-
                                                              e
erazione delicata, in quanto pu´ essere influenzata da diversi fattori, come
                                  o
la schedulazione dei thread da parte del sistema operativo, la precisione dei
contatori disponibili, l’esecuzione asincrona del codice su host e device, ecc.

    Per quanto riguarda i test di seguito riportati, sono stati utilizzati due
metodi di misurazione: uno basato sui tempi d’esecuzione della singola GPU
(descritto nella Sezione 4.1.1), l’altro basato sui tempi totali d’esecuzione.
Quest’ultimo in particolare ´ stato implementato nel codice utilizzando la
                             e
funzione C++ clock() fornita dalla libreria time.h. Questa funzione ritorna
come risultato il numero di cicli di clock trascorsi dall’avvio dell’esecuzione
del programma. Per ottenere il valore medio di esecuzione di ogni schermata
(frame) della simulazione, si ´ proceduto nel seguente modo:
                              e

  1. Prima della chiamata alla funzione anim and exit, viene salvato il
     valore ritornato da clock() nel campo start c della struttura data,
     creato appositamente per lo scopo.

  2. All’interno della funzione anim gpu, al termine dei kernel, viene calco-
     lato il numero di cicli di clock totale (fino a quel momento) e salvato
     all’interno del campo tot di data.

  3. Il valore salvato in tot viene diviso per la costante predefinita CLOCKS
     PER SEC (che in questo caso vale 1000) e poi stampato a video, otte-
     nendo cos´ i secondi totali d’esecuzione.
                ı
36                                                                         Test finali


     4. Una volta raggiunti i 12000 frame, viene bloccata l’esecuzione del pro-
        gramma e il valore totale visualizzato viene diviso per 12000, ottenendo
        cos´ il tempo medio di esecuzione di ogni frame.
           ı

4.1.1       Eventi CUDA
Per misurare il tempo di cui la GPU ha avuto bisogno per calcolare i kernel
di ogni schermata della simulazione, sono state usate delle strutture prede-
finite chiamate eventi. Un evento in CUDA ´ essenzialmente la stampa a
                                                e
video del tempo di esecuzione della GPU, registrato in un punto scelto dal
programmatore.
Per ottenere la stampa del tempo di elaborazione, ´ necessario creare un
                                                       e
evento, permettergli di registrare il tempo e poi chiuderlo, utilizzando alcune
funzioni fornite da CUDA.


4.2       Il confronto
Come primo test, ´ stato eseguito il confronto tra il programma realizza-
                    e
to in CUDA e lo stesso1 programma realizzato in MATLAB [1], facendoli
funzionare sulla stessa macchina e nelle stesse condizioni.

 linguaggio     unit´ di calcolo
                    a                num.frame      video    ms per frame (media)
 MATLAB               CPU              2000          No               19.8
 CUDA C              GPU               2000          No               0.5

Tabella 4.1: Confronto tra il programma scritto in MATLAB e lo stesso scritto
             in CUDA, senza la visualizzazione dell’animazione.




   linguaggio    unit´ di calcolo
                     a                nr.frame     video    ms per frame (media)
   MATLAB              CPU              2000         S´
                                                      ı             180.2
   CUDA C             GPU               2000         S´
                                                      ı              16.7

Tabella 4.2: Confronto tra il programma scritto in MATLAB e lo stesso scritto
             in CUDA, con la visualizzazione dell’animazione.



   1
   Il programma realizzato segue la stessa linea procedurale di quello scritto in MATLAB,
ma con le dovute modifiche, dettate dal linguaggio di programmazione e dall’architettura
CUDA.
4.3 Altri test                                                                     37


4.3      Altri test
In seguito ai risultati ottenuti dal confronto col codice Matlab, sono stati
eseguiti alcuni test per valutare le prestazioni del programma CUDA al va-
riare del numero di blocchi e di thread. In particolare, ms kernel indica il
tempo medio d’esecuzione di tutti i cinque kernel in millisecondi, mentre ms
tot, indica il tempo medio di esecuzione totale di ogni frame, comprendente
i tempi della CPU.


       nr.pixel   nr.blocchi    nr.thread    nr.frame     ms kernel     ms tot
       100x100      10x10        10x10        12000          0.5         0.8
       100x100      20x20          5x5        12000          0.6         0.9
       100x100      25x25          4x4        12000          0.8         1.2
       100x100      50x50          2x2        12000          2.4         2.7

Tabella 4.3: Confronto tra diverse disposizioni di thread per blocco, senza la
             visualizzazione dell’animazione.




       nr.pixel   nr.blocchi    nr.thread    nr.frame     ms kernel     ms tot
       100x100      10x10        10x10        12000          0.5         16.7
       100x100      20x20          5x5        12000          0.6         16.7
       100x100      25x25          4x4        12000          0.8         16.7
       100x100      50x50          2x2        12000          2.4         16.7

Tabella 4.4: Confronto tra diverse disposizioni di thread per blocco, con la
             visualizzazione dell’animazione.



    Infine, sono stati eseguiti dei test per valutare la scalabilit´ 2 del modello,
                                                                  a
relativamente alle dimensioni in pixel delle immagini visualizzate.




   2
   In campo informatico, ´ un concetto generale che indica la capacit´ di un sistema di
                          e                                             a
aumentare o diminuire di scala in funzione delle necessit´ e delle disponibilit´.
                                                         a                     a
38                                                      Test finali




     nr.pixel   nr.blocchi   nr.thread      risultato
      90x90       18x18         5x5            OK
     108x108      18x18         6x6            OK
     110x110      10x10       11x11            OK
     110x110      11x11       10x10            OK
     114x114      19x19         6x6      stackOverflow
     117x117      13x13         9x9      stackOverflow
     120x120      10x10       12x12      stackOverflow
     120x120      12x12       10x10      stackOverflow
     120x120      15x15         8x8      stackOverflow
     121x121      11x11       11x11      stackOverflow
     126x126      18x18         7x7      stackOverflow
     130x130      13x13       10x10      stackOverflow
     150x150      10x10       15x15      stackOverflow
     150x150      15x15       10x10      stackOverflow
     162x162      18x18         9x9      stackOverflow
     180x180      18x18       10x10      stackOverflow

           Tabella 4.5: Scalabilit´ del sistema.
                                  a
Conclusioni
                                                                             5
Com’era prevedibile, i test riguardanti il confronto tra il codice scritto in
MATLAB eseguito su una CPU e il corrispettivo in CUDA, hanno mostrato
una superiorit´ del secondo rispetto al primo di 10 volte con la visualiz-
               a
zazione dell’animazione, e di ben 40 volte senza la visualizzazione. Questo ´
                                                                            e
un ottimo risultato, considerando che il codice CUDA non ´ stato ottimizza-
                                                            e
to, mentre quello MATLAB s´ e che, dal punto di vista hardware, la CPU
                               ı,
utilizzata era una delle pi´ potenti e costose fino a sei mesi fa, mentre la
                           u
GPU ´ stata prodotta quasi due anni fa e venduta ad un prezzo pari ad 1/5
       e
di quello della CPU.

     Per quanto riguarda gli altri test, quelli sulla variazione del numero di
thread mostrano che andando ad eccedere sempre pi´ nel numero di bloc-
                                                          u
chi rispetto al numero di CUDA core disponibili, avviene un rallentamento
nell’esecuzione, probabilmente in quanto rimangono troppi thread in attesa.
Il motivo per cui i millisecondi totali con la visualizzazione restano sem-
pre uguali, potrebbe essere attribuito ad un implicito intervallo di tempo
minimo tra una visualizzazione e l’altra, imposto dall’interfaccia di visualiz-
zazione per una corretta visione dell’animazione. Questo di fatto impedisce
di godere appieno di eventuali ottimizzazioni al codice destinato ad essere
eseguito dalla GPU.
I test sulla scalabilit´ mostrano, invece, che non ´ possibile aumentare di
                       a                               e
molto la dimensione del modello. Questo ´ probabilmente dovuto alla situa-
                                            e
zione di divergenza che si viene a creare nel kernel di ricolorazione, al limitato
numero di registri disponibili e, in generale, alla mancanza di ottimizzazione
delle risorse che CUDA mette a disposizione, in particolare le diverse memo-
rie.
40                                                               Conclusioni


    In conclusione, alcune ottimizzazioni possibili per questo codice potreb-
bero comprendere l’utilizzo della memoria condivisa da parte dei thread di
uno stesso blocco, e di quella costante per la memorizzazione delle costanti
utilizzate da tutti i thread in generale, oppure l’utilizzo di strutture real-
mente bidimensionali e tridimensionali per la memorizzazione delle matrici
utilizzate nel codice, in sostituzione alla loro trasformazione in vettori. Per
quanto riguarda la visualizzazione, invece, sarebbe necessario ridurre l’inter-
vallo di visualizzazione tra un frame e l’altro, in modo tale da rendere utili
le ottimizzazioni effettuate.
A
Codice integrale
42   Appendice A.   Codice integrale
43
44   Appendice A.   Codice integrale
45
46   Appendice A.   Codice integrale
47
48   Appendice A.   Codice integrale
49
50   Appendice A.   Codice integrale
51
52   Appendice A.   Codice integrale
53
54   Appendice A.   Codice integrale
55
56   Appendice A.   Codice integrale
Bibliografia




[1] G. Schena, immiscible LB, codice MATLAB che usa i metodi
    reticolari di Boltzmann (LB) per simulare flussi di fase di flu-
    idi immiscibili (blu e rosso) in 2D secondo lo schema D2Q9,
    (Settembre 2010, ultima revisione). Disponibile online all’indirizzo:
    http://www.mathworks.com/matlabcentral/fileexchange/24824-i
    mmiscible-lb

[2] NVIDIA Corporation,CUDA C Programming Guide Version 4.0,
    reperibile online, (5/6/2011).

[3] J. Sanders, E. Kandrot, CUDA By Example - An Intro-
    duction to General-Purpose GPU programming,           Addison-
    Wesley,   2010.  I   codici sorgente  di   tutti  gli   esem-
    pi presenti nel libro sono disponibili online all’indirizzo:
    http://developer.nvidia.com/cuda-example-introduction-gener
    al-purpose-gpu-programming

[4] M.C. Sukop, D.T. Thorne Jr., Lattice Boltzmann Modeling - An
    Introduction for Geoscientists and Engineers Springer, (2007).

[5] E. Rustico, Fluid dynamics simulations on multi-GPU sys-
    tems, Tesi di dottorato, (2011). Reperibile online all’indirizzo:
    http://www.dmi.unict.it/∼cantone/EsameFinaleDottorato/Tesi/
    RUSTICO.pdf

[6] D.H. Rothman, J.M. Keller, Immiscible cellular-automaton fluids,
    Journal of Statistical Physics, Vol.52, Nos.3/4, (1988).
58                                                  BIBLIOGRAFIA


[7] J.Toelke, Lattice Boltzmann multiphase simulations using GPUs,
    conferenza, GTC 2010, San Jos, CA, (2010). Video reperibile online.

[8] GPGPU.IT, Tutorial CUDA, breve tutorial introduttivo a CUDA,
    (2009). URL: http://www.gpgpu.it/joomla/cuda-tutorial/tutoria
    l-cuda-ultimi-elementi-base.html
Indice analitico




blockDim, 7                   condizioni al contorno, 19
blockIdx, 7                       di Dirichlet, 19
CLOCKS PER SEC, 35                di Von Neumann, 19
clock(), 35                       gradiente di pressione, 19
cudaFree(), 9                     periodiche, 19
cudaMalloc(), 9                   rimbalzo, 19
cudaMemcpy(), 9               conflitti
dim3, 30                          RAW, 30
gridDim, 7                        WAR, 30
nvcc, 12                          WAW, 30
threadIdx, 7                  core, 4
 global , 7                   CUBIN, 12
                              CUDA, 3
 A                            CUDA C, 3, 7
ALU, 4
API, 3                         D
                              D2Q9, 16
 B                            decomposizione spinodale, 26
BGK, 18                       densit´ macroscopica, 16
                                    a
Bhatnagar-Gross-Krook, 18     device, 4
blocco, 4                     divergenza, 7
bounceback boundaries, 19     DRAM, 4
 C                             E
calcolo parallelo, 4          eventi, 36
capacit´ computazionale, 25
        a
collisione, 15, 18             F
compilazione, 12              fluidi immiscibili, 21
60                                          INDICE ANALITICO


fluidi multifase, 21              O
frame, 35                       on chip, 9
funzione di distribuzione, 16   OpenGL, 32
funzione di equilibrio, 18
                                 P
 G                              pesi, 18
GeForce GTX 460, 25             principio di localit´, 9
                                                    a
general-purpose, 3              propagazione, 15, 18
GFLOP/s, 3                      PTX, 12
GLUT, 32
GPU, 3                           R
gradiente di colore, 21         rendering, 3
griglia, 4                      ricolorazione, 22
                                rimbalzo, 19
 H
host, 4                          S
                                scalabilit´, 36
                                          a
 I                              SIMD, 4
ILBM, 21                        streaming, 15
indice assoluto, 7
interfaccia, 21                  T
                                tensione superficiale, 31
 K                              thread, 4
kernel, 7
                                 U
 L                              unit´ di controllo, 4
                                    a
larghezza di banda, 9
lattice Boltzmann methods, 15    V
LBM, 15                         velocit´ macroscopica, 16
                                       a
Ludwig Boltzmann, 15            velocit´ microscopiche, 16
                                       a

 M                               W
memoria, 9                      warp, 4, 7
   condivisa, 9                    mezzo-warp, 9
   costante, 9
   device memory, 4
   globale, 9
   host memory, 4
   locale, 9
   texture memory, 9
metodi reticolari, 15
mid-plane bounceback, 19
multiprocessore, 7
Modellazione della dinamica di un liquido bifase mediante GPU CUDA
Finito di stampare in Marzo 2012
       utilizzando LTEX 2ε
                   A

More Related Content

What's hot

MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARY
MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARYMARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARY
MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARYvantasso
 
Monitoraggio di applicazioni software mediante modelli di Markov
Monitoraggio di applicazioni software mediante modelli di MarkovMonitoraggio di applicazioni software mediante modelli di Markov
Monitoraggio di applicazioni software mediante modelli di Markovrkjp
 
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEM
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEMTesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEM
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEMDavide Ciambelli
 
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...Myrteza Kertusha
 
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D Andrea Bidinost
 
Caratterizzazione di un rivelatore a piatti resistivi (RPC)
Caratterizzazione di un rivelatore a piatti resistivi (RPC)Caratterizzazione di un rivelatore a piatti resistivi (RPC)
Caratterizzazione di un rivelatore a piatti resistivi (RPC)Gerardo Di Iorio
 
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientale
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientaleInterfaccia utente basata su eye-tracking per sistemi di controllo ambientale
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientaleLuigi De Russis
 
Joseki : un server per interrogare risorse RDF attraverso un interfaccia Web
Joseki : un server per interrogare risorse RDF attraverso un interfaccia WebJoseki : un server per interrogare risorse RDF attraverso un interfaccia Web
Joseki : un server per interrogare risorse RDF attraverso un interfaccia WebCyclope86
 
Pattern Recognition Lecture Notes
Pattern Recognition Lecture NotesPattern Recognition Lecture Notes
Pattern Recognition Lecture NotesRobertoMelfi
 
Un metodo di progettazione di reti locali con esigenze di qualità del servizio
Un metodo di progettazione di reti locali con esigenze di qualità del servizioUn metodo di progettazione di reti locali con esigenze di qualità del servizio
Un metodo di progettazione di reti locali con esigenze di qualità del servizioClaudio Bortone
 
Inoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linuxInoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linuxCe.Se.N.A. Security
 
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...maik_o
 
GaPiL - Guida alla Programmazione in Linux
GaPiL - Guida alla Programmazione in LinuxGaPiL - Guida alla Programmazione in Linux
GaPiL - Guida alla Programmazione in LinuxAmmLibera AL
 
CaputiDomenicoMagistrale
CaputiDomenicoMagistraleCaputiDomenicoMagistrale
CaputiDomenicoMagistraleDomenico Caputi
 
Tesi Triennale - X509 e PGP
Tesi Triennale - X509 e PGPTesi Triennale - X509 e PGP
Tesi Triennale - X509 e PGPFabio Pustetto
 
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...danielenicassio
 

What's hot (20)

MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARY
MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARYMARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARY
MARKETING ED ECOMMERCE NELL’EDITORIA: IL CASO TRADING LIBRARY
 
Monitoraggio di applicazioni software mediante modelli di Markov
Monitoraggio di applicazioni software mediante modelli di MarkovMonitoraggio di applicazioni software mediante modelli di Markov
Monitoraggio di applicazioni software mediante modelli di Markov
 
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEM
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEMTesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEM
Tesi Triennale - Grid Credit System: un portale per la sostenibilità di COMPCHEM
 
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...
Progetto e realizzazione di un kernel linux per il controllo dinamico degli s...
 
A.Dionisi Thesis
A.Dionisi ThesisA.Dionisi Thesis
A.Dionisi Thesis
 
domenicoCaputiTriennale
domenicoCaputiTriennaledomenicoCaputiTriennale
domenicoCaputiTriennale
 
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D
Sviluppo e confronto di tecniche di stima della traiettoria di sensori 3D
 
Caratterizzazione di un rivelatore a piatti resistivi (RPC)
Caratterizzazione di un rivelatore a piatti resistivi (RPC)Caratterizzazione di un rivelatore a piatti resistivi (RPC)
Caratterizzazione di un rivelatore a piatti resistivi (RPC)
 
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientale
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientaleInterfaccia utente basata su eye-tracking per sistemi di controllo ambientale
Interfaccia utente basata su eye-tracking per sistemi di controllo ambientale
 
Joseki : un server per interrogare risorse RDF attraverso un interfaccia Web
Joseki : un server per interrogare risorse RDF attraverso un interfaccia WebJoseki : un server per interrogare risorse RDF attraverso un interfaccia Web
Joseki : un server per interrogare risorse RDF attraverso un interfaccia Web
 
Pattern Recognition Lecture Notes
Pattern Recognition Lecture NotesPattern Recognition Lecture Notes
Pattern Recognition Lecture Notes
 
Un metodo di progettazione di reti locali con esigenze di qualità del servizio
Un metodo di progettazione di reti locali con esigenze di qualità del servizioUn metodo di progettazione di reti locali con esigenze di qualità del servizio
Un metodo di progettazione di reti locali con esigenze di qualità del servizio
 
Inoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linuxInoltro di pacchetti ip in sistemi linux
Inoltro di pacchetti ip in sistemi linux
 
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...
Progetto e sviluppo di un'applicazionemobile multipiattaforma per il supporto...
 
Tesi
TesiTesi
Tesi
 
GaPiL - Guida alla Programmazione in Linux
GaPiL - Guida alla Programmazione in LinuxGaPiL - Guida alla Programmazione in Linux
GaPiL - Guida alla Programmazione in Linux
 
CaputiDomenicoMagistrale
CaputiDomenicoMagistraleCaputiDomenicoMagistrale
CaputiDomenicoMagistrale
 
Tesi Triennale - X509 e PGP
Tesi Triennale - X509 e PGPTesi Triennale - X509 e PGP
Tesi Triennale - X509 e PGP
 
Monitoraggio di rete con nagios
Monitoraggio di rete con nagiosMonitoraggio di rete con nagios
Monitoraggio di rete con nagios
 
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...
Progetto e Realizzazione di un Software per la Rilevazione Automatica di Codi...
 

Similar to Modellazione della dinamica di un liquido bifase mediante GPU CUDA

Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...
Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...
Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...michael_mozzon
 
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...Implementazione di un sistema di misura di tipo quantitativo per sensori a na...
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...Pasquale Naclerio
 
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...Daniele Ciriello
 
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...guest85785c7
 
Learning of non-homogeneous Continuous Times Bayesian Networks Thesis
Learning of non-homogeneous Continuous Times Bayesian Networks ThesisLearning of non-homogeneous Continuous Times Bayesian Networks Thesis
Learning of non-homogeneous Continuous Times Bayesian Networks ThesisGuido Colangiuli
 
Anomaly detection in network traffic flows with big data analysis techniques
Anomaly detection in network traffic flows with big data analysis techniques Anomaly detection in network traffic flows with big data analysis techniques
Anomaly detection in network traffic flows with big data analysis techniques Maurizio Cacace
 
Banovaz Diego - Tesi
Banovaz Diego - TesiBanovaz Diego - Tesi
Banovaz Diego - TesiDiego Banovaz
 
Realizzazione di un modello di router ottico in ambiente open source.
Realizzazione di un modello di router ottico in ambiente open source.Realizzazione di un modello di router ottico in ambiente open source.
Realizzazione di un modello di router ottico in ambiente open source.Raul Cafini
 
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - Tesi
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - TesiAnalisi di prestazione dell'interprete tuProlog su piattaforma Java - Tesi
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - TesiMicheleDamian
 
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...Domenico Schillaci
 
Il tutorial di Python
Il tutorial di PythonIl tutorial di Python
Il tutorial di PythonAmmLibera AL
 
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...Gianluca Ritrovati
 
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...Reti di partecipazione fra società di capitale in Italia: presenza di topolog...
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...Andrea Cavicchini
 
Abstract Domenico Brigante
Abstract   Domenico BriganteAbstract   Domenico Brigante
Abstract Domenico Brigantedox82
 
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...Davide Ciambelli
 

Similar to Modellazione della dinamica di un liquido bifase mediante GPU CUDA (16)

Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...
Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...
Implementazione di protocolli e simulatori MATLAB per lo sviluppo del livello...
 
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...Implementazione di un sistema di misura di tipo quantitativo per sensori a na...
Implementazione di un sistema di misura di tipo quantitativo per sensori a na...
 
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...
Reti neurali di convoluzione per la visione artificiale - Tesi di Laurea Magi...
 
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...
Progetto e realizzazione di un sistema per la caratterizzazione su larga scal...
 
Learning of non-homogeneous Continuous Times Bayesian Networks Thesis
Learning of non-homogeneous Continuous Times Bayesian Networks ThesisLearning of non-homogeneous Continuous Times Bayesian Networks Thesis
Learning of non-homogeneous Continuous Times Bayesian Networks Thesis
 
Anomaly detection in network traffic flows with big data analysis techniques
Anomaly detection in network traffic flows with big data analysis techniques Anomaly detection in network traffic flows with big data analysis techniques
Anomaly detection in network traffic flows with big data analysis techniques
 
Banovaz Diego - Tesi
Banovaz Diego - TesiBanovaz Diego - Tesi
Banovaz Diego - Tesi
 
Realizzazione di un modello di router ottico in ambiente open source.
Realizzazione di un modello di router ottico in ambiente open source.Realizzazione di un modello di router ottico in ambiente open source.
Realizzazione di un modello di router ottico in ambiente open source.
 
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - Tesi
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - TesiAnalisi di prestazione dell'interprete tuProlog su piattaforma Java - Tesi
Analisi di prestazione dell'interprete tuProlog su piattaforma Java - Tesi
 
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...
Sviluppo di un sistema per il monitoraggio ambientale basato su reti di senso...
 
Il tutorial di Python
Il tutorial di PythonIl tutorial di Python
Il tutorial di Python
 
Andrea_Gangemi_tesi
Andrea_Gangemi_tesiAndrea_Gangemi_tesi
Andrea_Gangemi_tesi
 
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
 
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...Reti di partecipazione fra società di capitale in Italia: presenza di topolog...
Reti di partecipazione fra società di capitale in Italia: presenza di topolog...
 
Abstract Domenico Brigante
Abstract   Domenico BriganteAbstract   Domenico Brigante
Abstract Domenico Brigante
 
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...
Tesi Specialistica - L'ottimizzazione delle risorse della Grid di EGEE median...
 

Modellazione della dinamica di un liquido bifase mediante GPU CUDA

  • 1. ` Universita degli Studi di Trieste Facolt` di Ingegneria a Corso di Studi in Ingegneria dell’Informazione Modellazione della dinamica di un liquido bifase mediante gpu cuda Tesi di Laurea Triennale Laureanda: Relatori: Alessandra LADERCHI prof. Claudio CHIARUTTINI prof. Gianni SCHENA ANNO ACCADEMICO 2010–2011
  • 2. Ai miei genitori e a Isabella
  • 3. ii
  • 4. Indice Introduzione 1 1 CUDA 3 1.1 Di cosa si tratta . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Il calcolo parallelo . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3 I kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.4 Tipi di memoria . . . . . . . . . . . . . . . . . . . . . . . . . . 9 1.5 La compilazione . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2 Boltzmann e i metodi reticolari 15 2.1 I metodi reticolari . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.2 Il modello D2Q9 . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.3 L’approssimazione BGK . . . . . . . . . . . . . . . . . . . . . 18 2.4 Condizioni al contorno . . . . . . . . . . . . . . . . . . . . . . 19 2.4.1 Rimbalzo . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.5 ILBM e fluidi multifase . . . . . . . . . . . . . . . . . . . . . . 21 2.5.1 Interfaccia e gradiente di colore . . . . . . . . . . . . . 21 2.5.2 La ricolorazione . . . . . . . . . . . . . . . . . . . . . . 22 3 Simulazione mediante CUDA 25 3.1 Strumenti utilizzati . . . . . . . . . . . . . . . . . . . . . . . . 25 3.1.1 Specifiche tecniche . . . . . . . . . . . . . . . . . . . . 25 3.2 La simulazione . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.3 Il codice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.3.1 Diagramma di flusso . . . . . . . . . . . . . . . . . . . 27 3.3.2 Inizio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
  • 5. iv 3.3.3 I kernel . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.3.4 L’animazione grafica . . . . . . . . . . . . . . . . . . . 32 4 Test finali 35 4.1 La misurazione dei tempi . . . . . . . . . . . . . . . . . . . . . 35 4.1.1 Eventi CUDA . . . . . . . . . . . . . . . . . . . . . . . 36 4.2 Il confronto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 4.3 Altri test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 5 Conclusioni 39 A Codice integrale 41
  • 6. Elenco delle figure 1.1 Differenza di prestazioni tra GPU e CPU. [5] . . . . . . . . . . 4 1.2 Griglie, blocchi e thread. [2] . . . . . . . . . . . . . . . . . . . 5 1.3 Rappresentazione schematica del raggruppamento dei core in una GPU CUDA. [5] . . . . . . . . . . . . . . . . . . . . . . . 6 1.4 Indicizzazione di una griglia di blocchi a due dimensioni. [5] . 8 1.5 Suddivisione della memoria. In rosso sono evidenziate le mem- orie a bassa latenza, mentre in arancione quelle a latenza pi´ u elevata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.6 Principio di localit´. [3] . . . . . . . . . . . . . . . . . . . . . a . 11 1.7 Fasi della compilazione. [8] . . . . . . . . . . . . . . . . . . . . 13 2.1 Esempi di modelli reticolari di Boltzmann . . . . . . . . . . . 16 2.2 Il modello D2Q9 . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.3 D2Q9, componenti x e y delle velocit´ microscopiche a . . . . . 17 2.4 Rimbalzo di tipo mid-plane. [4] . . . . . . . . . . . . . . . . . 20 2.5 Densit´ nelle zone di interfaccia. [7] . . . . . . . . . . a . . . . . 21 2.6 Meccanismo di ricolorazione. [7] . . . . . . . . . . . . . . . . . 22 2.7 Definizione delle priorit´ delle direzioni mediante il a calcolo delle proiezioni del gradiente su di esse. . . . . . . . . . . . . . 23 3.1 Simulazione del fenomeno della decomposizione spinodale. . . 26 3.2 Informazioni preliminari. . . . . . . . . . . . . . . . . . . . . . 27 3.3 Diagramma di flusso. . . . . . . . . . . . . . . . . . . . . . . . 29
  • 7. vi
  • 8. Elenco delle tabelle 3.1 Alcune specifiche tecniche della scheda grafica. . . . . . . . . . 26 4.1 Confronto tra il programma scritto in MATLAB e lo stesso scritto in CUDA, senza la visualizzazione dell’animazione. . . 36 4.2 Confronto tra il programma scritto in MATLAB e lo stesso scritto in CUDA, con la visualizzazione dell’animazione. . . . . 36 4.3 Confronto tra diverse disposizioni di thread per blocco, senza la visualizzazione dell’animazione. . . . . . . . . . . . . . . . . 37 4.4 Confronto tra diverse disposizioni di thread per blocco, con la visualizzazione dell’animazione. . . . . . . . . . . . . . . . . . 37 4.5 Scalabilit´ del sistema. . . . . . . . . . . . . . . . . . . . . . a . 38
  • 10. Introduzione La presente tesi descrive il lavoro svolto durante la modellazione della di- namica di un liquido bifase mediante l’utilizzo di una GPU con architettura CUDA. In particolare, il codice prodotto segue la linea di programmazione del software realizzato dal prof. G. Schena [1] utilizzando l’ambiente di sviluppo MATLAB. Cos´ facendo, si ` reso possibile testare la differenza di prestazioni ı e tra il programma eseguito in MATLAB e lo stesso programma realizzato in CUDA. L’elaborato ´ strutturato come segue. e Il Capitolo 1 introduce l’architettura CUDA e alcune caratteristiche utilizzate durante lo sviluppo della simulazione. Nel Capitolo 2 segue una breve spiegazione dei metodi reticolari di Boltzmann per la simulazione di fluidi. Il Capitolo 3 descrive in profondit´ il programma sviluppato, mentre nel a Capitolo 4 viene dato spazio ai test eseguiti e, nel Capitolo 5, alle relative conclusioni. Infine, in Appendice ´ riportato il programma realizzato in CUDA. e
  • 11. 2
  • 12. CUDA 1 In questo capitolo verranno presentati l’architettura CUDA, il calcolo paral- lelo e saranno approfondite alcune caratteristiche utilizzate durante la rea- lizzazione della simulazione. 1.1 Di cosa si tratta L’unit´ di elaborazione grafica o GPU (acronimo di Graphics Processing a Unit) ´ un microprocessore specializzato nel rendering1 di immagini grafiche e inizialmente processate dalla CPU. L’avanzamento sul mercato di videogiochi ad alta pretesa grafica, ha provoca- to un’evoluzione sostanzale della potenza computazionale delle GPU rispetto a quella delle CPU. Il grafico di Figura 1.1 mostra l’aumento di GFLOP/s2 dal 2003 al 2010 delle GPU NVIDIA rispetto alle CPU Intel. Nel Novembre del 2006 (come evidenziato dal grafico), NVIDIA Corpo- ration lanci´ sul mercato la GeForce 8800 GTX, la prima GPU costruita con o architettura CUDA. CUDA (acronimo di Compute Unified Device Architecture), ´ un’architettura e hardware incentrata sul calcolo parallelo e rivolta in particolare alla program- mazione general-purpose3 , supportata da un ambiente di sviluppo indirizzato 1 In ambito grafico, il rendering ´ il processo di “resa”, ovvero di generazione di un’im- e magine a partire da una descrizione matematica di una scena tridimensionale interpretata da algoritmi che definiscono il colore di ogni punto dell’immagine. 2 Acronimo di FLoating Point Operations Per Second, indica il numero di operazioni in virgola mobile eseguite in un secondo. 3 Con questo termine vengono indicati software non specifici. In particolare, in questo caso si fa riferimento a programmi di natura non strettamente grafica.
  • 13. 4 CUDA Figura 1.1: Differenza di prestazioni tra GPU e CPU. [5] a semplificare il lavoro dei programmatori. L’avvento di tale di tipo di architettura ´ stato reso necessario dalla sem- e pre maggiore richiesta di poter utilizzare le GPU per eseguire programmi general-purpose sfruttando i vantaggi del calcolo parallelo, fino a quel mo- mento utilizzati solamente in ambito grafico. La potenza di CUDA ´ sostenuta dall’ambiente di sviluppo che l’ac- e compagna. Grazie ad esso infatti, molti complessi problemi computazionali possono essere risolti con minor difficolt´ e spesso maggior efficienza che a tramite CPU, in quanto, grazie all’aggiunta di nuove specifiche funzioni, permette di programmare ad alto livello utilizzando diversi linguaggi, quali C/C++ (dai quali deriva CUDA C ), Fortran, Java, Python, o interfacce di programmazione (API ), come OpenCL e DirectCompute. 1.2 Il calcolo parallelo Il calcolo parallelo costituisce un’importante evoluzione nel mondo della pro- grammazione informatica, esso infatti consiste nel far eseguire un codice su pi´ processori o core4 di uno stesso processore in modo tale da migliorare le u 4 Il termine inglese core ´ usato anche in italiano per indicare il nucleo elaborativo di e un calcolatore, ovvero la parte che esegue i calcoli e le funzioni principali.
  • 14. 1.2 Il calcolo parallelo 5 prestazioni del sistema. In ambito CUDA, il calcolo parallelo viene implementato attraverso la suddivisione di ogni problema in sotto-problemi, o thread 5 , risolvibili con- temporaneamente da un gran numero di core indipendenti. I thread possono essere raggruppati in blocchi che, a loro volta, possono essere racchiusi all’in- terno di griglie. In Figura 1.2 sono mostrate le suddivisioni appena descritte. Figura 1.2: Griglie, blocchi e thread. [2] Il modello di programmazione CUDA prevede che i thread vengano ese- guiti su un dispositivo fisicamente separato (come la GPU), il quale opera da coprocessore nei confronti di un dispositivo principale (la CPU) che elabora il programma scritto (ad esempio) in C. Si far´ riferimento a questi due di- a spositivi utilizzando i termini inglesi di device e host, rispettivamente. CUDA prevede inoltre che entrambi i dispositivi possiedano spazi di memoria 5 Il termine thread viene usato in informatica per indicare la parte elementare di un processo.
  • 15. 6 CUDA in DRAM6 separate, alle quali si far´ riferimento nel corso della trattazione a con i termini device memory e host memory. Ci´ implica per il programma- o tore allocazioni e deallocazioni di memoria, cos´ come trasferimenti di dati ı tra host memory e device memory. Sebbene programmare in ambiente CUDA non richieda la conoscenza det- tagliata dell’hardware sottostante, il modo in cui i thread vengono lanciati e le caratteristiche di elementi come le memorie, riflettono fortemente il modo in cui sono organizzati i core e le locazioni di memoria all’interno della GPU. Una scheda grafica di tipo CUDA ´ capace di ospitare al suo interno uno o e 7 pi´ multiprocessori di tipo SIMD , ognuno composto da un gran numero di u core, per un totale di decine o anche centinaia di core. Pi´ specificatamente, u ogni multiprocessore pu´ ospitare fino a 48 ALU8 e una unit´ di controllo. o a Quest’ultima pu´ decodificare una sola istruzione alla volta, che verr´ poi o a eseguita contemporaneamente da pi´ thread. Ogni multiprocessore pu´ ese- u o guire fino a un determianto numero di thread in parallelo. Questo gruppo di thread ´ chiamato warp 9 . e Quanto descritto finora ´ riassunto in Figura 1.3. e Figura 1.3: Rappresentazione schematica del raggruppamento dei core in una GPU CUDA. [5] 6 Dynamic Random Access Memory, un particolare tipo di RAM. 7 Acronimo di Single Instruction, Multiple Data, si riferisce ad un’architettura in cui pi´ unit´ elaborano dati diversi in parallelo. Questo modello ´ composto da un’unica u a e unit´ di controllo che esegue una istruzione alla volta controllando pi´ ALU che operano a u in maniera asincrona. 8 Acronimo di Arithmetic Logic Unit, o Unit´ Aritmetica-Logica, ´ un tipo di processore a e ´ digitale predisposto all’esecuzione di operazioni aritmetiche o logiche. E una componente fondamentale della CPU e della GPU. 9 Ordito, in italiano. Riferito alla tessitura, ´ un gruppo di fili intrecciati assieme in e modo da formare un tessuto. In inglese, thread significa “filo”, da cui il gioco di parole.
  • 16. 1.3 I kernel 7 1.3 I kernel Il linguaggio di programmazione CUDA C (estensione del classico C/C++) permette al programmatore di definire funzioni chiamate kernel che, quando invocate, vengono eseguite N volte in parallelo sul device da N differenti thread CUDA, e non una volta sola, come accade regolarmente con le fun- zioni in C. In particolare, un’istanza di un kernel corrisponde a un thread. I kernel hanno caratteristiche ben precise: • devono avere void come tipo di ritorno (quindi non devono tornare alcun valore); • non possono essere ricorsivi; • non possono avere un numero di parametri variabile; • non possono usare variabili di tipo statico10 • possono accedere solo alla memoria della GPU. Per definire un kernel in un programma scritto in CUDA C, si utilizza l’identificatore global anteposto alla sua dichiarazione. L’invocazione di un kernel avviene all’interno del codice eseguito dalla CPU, chiamandone il nome e specificando la configurazione di esecuzione all’interno di appositi identificatori, <<<...>>>, nel seguente modo: kernel<<<gridDim,blockDim>>>(param 1,.., param n); Le dimensioni dei blocchi e delle griglie sono a discrezione del program- matore, purch´ non eccedano i limiti imposti dall’hardware. e La dimensione massima di un blocco di solito non ´ sufficiente a soddisfare le e esigenze delle applicazioni. Ci´ implica che ´ spesso necessario raggruppare o e i thread in pi´ blocchi. u Ogni thread che esegue il kernel possiede un ID unico, accessibile all’in- terno del kernel stesso attraverso la variabile threadIdx. In questo contesto, ´ anche possibile accedere all’ID univoco del blocco a 1,2 o 3 dimensioni in e cui ´ contenuto ogni thread, utilizzando la variabile blockIdx. Grazie a ci´, e o ´ sempre possibile per ogni thread calcolare l’indirizzo dei dati a cui accedere. e Questa operazione pu´ essere implementata con pi´ indici, come mostrato o u 10 Non possono, cio´, allocare variabili il cui tempo di vita sia esteso a tutto il programma, e e quindi oltre la durata del kernel stesso.
  • 17. 8 CUDA in Figura 1.4, oppure trasformando un indice a pi´ dimensioni in un indice u monodimensionale (indice assoluto), nel seguente modo: int offset = x + y * blockDim.x * gridDim.x; Figura 1.4: Indicizzazione di una griglia di blocchi a due dimensioni. [5] sfruttando le variabili predefinite contenenti le dimensioni di ogni blocco e di ogni griglia, blockDim e gridDim. Ogni blocco ´ assegnato a un multiprocessore che, come gi´ spiegato nella e a Sezione 1.2, pu´ eseguire simultaneamente solo un certo numero di thread o alla volta (un warp). Quando il numero di thread ´ maggiore del numero e di core, viene eseguito un cambio di contesto (in gergo informatico, context switch 11 ), che permette a tutti i thread di essere completati. Quando un thread pone una richiesta di memoria, che pu´ richiedere diversi o minuti, il cambio di contesto permette l’esecuzione di altri thread mentre il primo resta in attesa dei dati dalla memoria. Questa soluzione di istanziare pi´ thread rispetto ai core disponibili, permette di ottenere un elevato rendi- u mento in termini di tempo, in quanto la perdita dovuta alle richieste di 11 ´ E un particolare stato del sistema operativo durante il quale avviene il cambiamento del processo correntemente in esecuzione. Si svolge in due fasi: la prima consiste nel salvataggio dello stato attuale per consentirne il rispristino; la seconda consiste nella scelta del nuovo processo da eseguire e nell’apertura del suo contesto.
  • 18. 1.4 Tipi di memoria 9 memoria ´ coperta da altre computazioni. e Un altro fattore che pu´ influire negativamente sul tempo di esecuzione ´ o e la divergenza dei thread. Essa avviene quando alcuni thread necessitano di eseguire alcune istruzioni mentre gli altri no. In normali circostanze, quest’ul- timi restano inattivi mentre gli altri eseguono le loro istruzioni, ma ´ sempre e meglio evitare che thread di uno stesso warp divergano. 1.4 Tipi di memoria L’architettura CUDA mette a disposizione dei programmatori alcuni tipi di memoria, utilizzabili diversamente a seconda del livello di profondit´ rag- a giunto nella suddivisione del codice e dello scopo a cui saranno destinati. In particolare, la suddivisione della memoria ´ la seguente: e Registri: privata, a disposizione di ogni singolo thread. Memoria molto veloce, a cui non ´ possibile accedere direttamente. Il e numero totale di registri ´ fissato e deve quindi essere suddiviso tra e tutti i thread, limitando di fatto il numero di thread che possono essere eseguiti simultaneamente. Memoria locale: privata, a disposizione di ogni singolo thread. Questa memoria viene occupata quando non c’´ pi´ spazio all’inter- e u no dei registri. Essendo conservata nella DRAM, ha un’alta latenza 12 . Memoria locale e registri vengono utilizzati solitamente per memoriz- zare variabili locali e intermedie di ogni singolo thread. Memoria condivisa: a disposizione di tutti i thread di un blocco. ´ E molto veloce (quasi quanto i registri) in quanto interna ad ogni mul- tiprocessore (o pi´ tecnicamente, on chip). Per ottenere la massima u larghezza di banda13 durante i trasferimenti di dati, questa memoria ´e suddivisa in moduli di uguale grandezza, chiamati banchi (o banks in inglese), che possono essere acceduti simultaneamente. Viene spesso utilizzata per condividere risultati tra tutti i thread del blocco. Memoria globale: a disposizione di tutti i blocchi. Tipicamente implementata tramite una DRAM ( e quindi off-chip), ha lunga latenza in termini di clock (centinaia di cicli) ed una limitata larghezza di banda. 12 In informatica, la latenza ´ il tempo che intercorre tra l’inizio dell’esecuzione di e un’istruzione e il momento in cui ´ disponibile il suo risultato. e 13 Indica la quantit´ di dati che possono essere trasferiti in un dato periodo di tempo. a
  • 19. 10 CUDA Una schematica descrizione di queste divisioni ´ riportata in Figura 1.5. e Figura 1.5: Suddivisione della memoria. In rosso sono evidenziate le memorie a bassa latenza, mentre in arancione quelle a latenza pi´ elevata. u Esistono anche due tipi di memoria a sola lettura accessibili da tutti i thread: Texture memory: memoria a sola lettura. Risiede nella DRAM, ma, a differenza della memoria globale, pu´ essere copiata all’interno di ogni o multiprocessore in una memoria cache14 . Se usata in modo consapevo- le, permette di ridurre considerevolmente i tempi, eliminando richieste di memoria off-chip. In particolare, questo tipo di memoria ´ apposita- e mente pensato per tutte quelle applicazioni grafiche in cui l’accesso alla memoria avviene secondo il principio di localit´. Per un’applicazione a 14 La memoria cache ´ una memoria temporanea, non visibile al software, che memorizza e un insieme di dati in maniera tale da essere velocemente recuperati. In particolare, esse fanno in modo che letture consecutive di uno stesso indirizzo di memoria non comportino alcun traffico addizionale.
  • 20. 1.4 Tipi di memoria 11 general-purpose, questo significa che un thread tende ad accedere a spazi di memoria fisicamente vicini a quelli usati dai thread che lo han- no preceduto. In Figura 1.6 ´ riportato un esempio di localit´ spaziale e a nelle richieste di memoria. Figura 1.6: Principio di localit´. [3] a Memoria costante: come suggerisce il nome, ´ una memoria non molto e grande a sola lettura (per la GPU), riservata a dati destinati a non cambiare durante l’esecuzione di un kernel. Considerando che anch’essa pu´ essere copiata all’interno di ogni multiprocessore, il suo corretto o utilizzo permette di risparmiare richieste alla memoria globale in quanto una lettura da quella costante pu´ essere trasmessa a thread vicini, o ovvero appartenenti allo stesso mezzo-warp (16 thread), risparmiando quindi fino a 15 letture e riducendo (nel migliore dei casi) a 1/16 il traffico in memoria. Le memorie di tipo globale, costante e texture sono persistenti durante l’e- laborazione dei thread di una stessa applicazione. Un particolare molto importante da ricordare ´ che i thread della GPU e non possono accedere direttamente alla memoria dell’host (e viceversa). Il passaggio di dati (tra memoria globale del device e memoria dell’host) ´ e comunque reso possibile da particolari funzioni per l’allocazione, la copia e la deallocazione di spazi di memoria, quali ad esempio cudaMalloc(), cudaMemcpy() e cudaFree() rispettivamente, per quanto riguarda gli spazi monodimensionali. L’uso di queste direttive ´ il seguente: e cudaMalloc(**pointer, n bytes) cudaMemcpy(*dst, *src, n bytes, direction); cudaFree(*pointer);
  • 21. 12 CUDA dove n bytes ´ la grandezza in byte dei dati da copiare, mentre direction e specifica la direzione dell’operazione di copia, e pu´ essere cudaMemcpyHostTo o Device, cudaMemcpyDeviceToHost o cudaMemcpyDeviceToDevice. 1.5 La compilazione La compilazione ´ il processo di trasformazione di un file sorgente scritto in e un linguaggio ad alto livello, in un file binario comprensibile all’elaboratore. Il software fornito direttamente da NVIDIA include anche un compilatore (nvcc), che permette di semplificare il processo di compilazione dei sorgenti scritti in CUDA C, grazie a semplici e familiari opzioni impartibili a riga di comando. I file sorgenti possono contenere sia codice da eseguire sull’host che codice da eseguire sul device . Il processo di compilazione con nvcc ´ il seguente: e • Il codice relativo al device viene separato da quello dell’host. • Il codice del device viene compilato in un tipo di assembly detto codice PTX 15 e/o in una forma binaria detta CUBIN 16 . • Il codice dell’host viene modificato sostituendo ogni <<<...>>> con le chiamate di funzione per caricare e lanciare ogni kernel compilato, partendo dal PTX e/o dal CUBIN. • Il codice dell’host rimasto viene passato ad un normale compilatore C prefissato (come gcc su piattaforme Linux o il Microsoft Visual C++ Compiler in ambienti Windows) e il file binario cos´ ottenuto viene ı collegato all’oggetto binario CUBIN. Il file binario ottenuto pu´ quindi essere mandato in esecuzione. o In Figura 1.7 ´ riassunto il procedimento appena descritto. e 15 ´ Parallel Thread eXecution. E una forma di assembly proprietaria, ovvero il linguaggio macchina specifico delle architetture CUDA, sempre compatibile con quelle di capacit´ a computazionale superiore. 16 ´ E il codice binario per le GPU. Quando un’applicazione CUDA ´ in esecuzione, essa e carica il file CUBIN nella GPU, se compatibile, altrimenti esegue una compilazione al momento, per produrre il codice CUBIN appropriato a partire dal PTX.
  • 22. 1.5 La compilazione 13 Figura 1.7: Fasi della compilazione. [8]
  • 23. 14 CUDA
  • 24. Boltzmann e i metodi reticolari 2 In questo capitolo verranno descritti i metodi reticolari di Boltzmann e il loro utilizzo nella simulazione dei flussi di fluidi bifase. 2.1 I metodi reticolari I metodi reticolari di Boltzmann1 sono un utile strumento per la simulazione della dinamica di fluidi. Essi semplificano ampiamente le equazioni che ne regolano il movimento, riducendo il numero di possibili posizioni assumibili dalle particelle, passando cos´ da un modello continuo a uno discreto, in ı quanto si basa su un approccio di tipo statistico. In particolare, le posizioni in questione vengono ridotte ai nodi di un reti- colo (in inglese lattice), motivo per cui si parla di Metodi Reticolari, o pi´ u frequentemente in inglese, di Lattice Boltzmann Methods o LBM. Il plurale proviene dal fatto che esistono diversi metodi che utilizzano l’e- quazione di Boltzmann, ognuno differente dall’altro per numero di dimen- sioni considerate (D) e numero di velocit´ (Q). In Figura 2.1 sono mostrati a alcuni esempi. I metodi reticolari sono basati su due fenomeni: la collisione e la propa- gazione. La collisione ´ il momento in cui le particelle di fluido in un nodo del reti- e colo si rilassano verso uno stato di equilibrio, mentre la propagazione (o, pi´ u 1 Ludwig Boltzmann (Vienna, 1844 - Duino, 1906), fisico e matematico, famoso per le sue ricerche in termodinamica e meccanica statistica, tra cui l’equazione fondamentale della teoria cinetica dei gas e il secondo principio della termodinamica.
  • 25. 16 Boltzmann e i metodi reticolari Figura 2.1: Esempi di modelli reticolari di Boltzmann frequentemente, streaming, in inglese) ´ la situazione durante la quale le par- e ticelle di un nodo si muovono verso i nodi adiacenti. Queste due fasi verranno approfondite maggiormente nella Sezione 2.3. 2.2 Il modello D2Q9 Per la realizzazione della simulazione ´ stato utilizzato il modello D2Q9. Esso e ´ caratterizzato da 2 dimensioni e 9 velocit´. e a 2 In particolare, le variazioni di momento che avrebbero potuto esserci in un sistema continuo di direzioni di velocit´, grandezze e diversa massa delle a particelle, sono ridotte a 9 direzioni (da 0 a 8), 3 grandezze e una singola massa, e quindi ad un sistema discreto. Dal momento che la massa delle particelle ´ uniforme (1 unit´ di massa nel caso pi´ semplice), momenti e e a u velocit´ microscopiche sono di fatto equivalenti. a In Figura 2.2 ´ mostrato il reticolo di Boltzmann del modello D2Q9. e Figura 2.2: Il modello D2Q9 Le velocit´ microscopiche delle particelle in un nodo del reticolo sono indicate a 2 Nella meccanica classica, il momento, o quantit´ di moto, ´ il vettore ottenuto molti- a e plicando la massa per la velocit´ dell’oggetto in esame. Esso misura la capacit´ di un a a corpo di modificare il movimento di altri corpi con cui interagisce dinamicamente.
  • 26. 2.2 Il modello D2Q9 17 con ea , a = 0, 1, ..., 8, dove e0 = 0 indica la velocit´ della particella a riposo. a Lo schema pi´ frequentemente usato, prevede di attribuire a queste velocit´ u a valori tali da ottenere le componenti come indicato in Figura 2.3. Figura 2.3: D2Q9, componenti x e y delle velocit´ microscopiche a Quindi i moduli saranno i seguenti:   0 se a = 0 |ea | = 1 se a = 1, 2, 3, 4 (2.1)  √ 2 se a = 5, 6, 7, 8 Il passo successivo consiste nell’incorporare la funzione di distribuzione (f ), che non viene pi´ considerata una funzione continua, ma costituita da u soli 9 elementi. Essa rappresenta la frequenza di occorrenza di ogni singola velocit´, ovvero la densit´ specifica del fluido in ogni direzione. a a Di conseguenza, la densit´ macroscopica del un fluido si ottiene cos´ a ı: 8 ρ= fa (2.2) a=0 La velocit´ macroscopica, invece, si ottiene come risultato della media a delle velocit´ microscopiche pesata secondo le densit´ direzionali fa : a a 8 1 u= fa ea (2.3) ρ a=0
  • 27. 18 Boltzmann e i metodi reticolari Questa semplice equazione permette di passare dalle velocit´ discrete micro- a scopiche del modello LBM alle velocit´ continue macroscopiche rappresen- a tanti il movimento del fluido. Introdotti gli elementi principali, verr´ ora presentato un importante a metodo di approssimazione delle equazioni che regolano la dinamica dei fluidi. 2.3 L’approssimazione BGK L’approssimazione BGK (Bhatnagar-Gross-Krook) ´ il metodo pi´ utilizzato e u nelle simulazioni che fanno uso dei metodi reticolari meno complessi. Pubblicata nel 1954, essa prevede che le equazioni di propagazione e collisione vengano semplificate come segue: 1 eq Collisione: fa (x, t + δt) = fa (x, t) + [fa (x, t) − fa (x, t)] (2.4) τ Propagazione: fa (x + ea δt, t + δt) = fa (x, t + δt) (2.5) Sebbene possano essere combinate in un’unica equazione, ´ meglio tenerle e separate se nella simulazione sono previsti confini solidi, in quanto il rimbal- zo delle particelle contro di essi costituisce una condizione al contorno ben precisa, che dovr´ essere trattata con un termine di collisione differente. a La collisione delle particelle di un fluido ´ considerata come il rilassa- e mento verso uno stato di equilibrio locale. Nel modello D2Q9 la funzione di equilibrio (f eq ) ´ approssimata nel seguente modo: e ea · u 9 (ea · u)2 3 u2 eq fa (x) = wa ρ(x) 1 + 3 + − (2.6) c2 2 c4 2 c2 dove wa sono i pesi, mentre c ´ la velocit´ base3 degli spostamenti lungo il e a reticolo. I pesi sono assegnati in questo modo:    4 se a = 0   9  1 wa = se a = 1, 2, 3, 4 (2.7)   9    1 36 se a = 5, 6, 7, 8 3 Ipotizzando che la distanza tra due punti adiacenti nel reticolo sia 1 lu (lattice unit) e che l’unit´ di tempo sia 1 ts (time step), allora la velocit´ base ´ 1 lu ts−1 , considerando a a e l’implementazione pi´ semplice. u
  • 28. 2.4 Condizioni al contorno 19 ´ E da notare che se la velocit´ macroscopica u = 0, la funzione di equilibrio a risulta essere semplicemente il prodotto dei pesi per la densit´ macroscopica a del fluido. 2.4 Condizioni al contorno I metodi reticolari di Boltzmann hanno riscosso molto successo nell’ambito delle simulazioni di fluidi per la loro semplicit´ di utilizzo. In particolare, a permettono di implementare con notevole facilit´ le condizioni al contorno a di ogni problema. Le condizioni al contorno sono tutte quelle situazioni che deveno essere gestite in modo diverso dal resto della simulazione. Ne esistono di vario genere e per ognuna ´ stato sviluppato un metodo di e trattamento specifico. Di seguito alcuni esempi: Condizioni al contorno periodiche: permettono di simulare fenomeni a sviluppo infinito, come la re-iniezione di fluido all’interno del canale. Gradiente di pressione: consente di simulare il flusso di un fluido all’interno di un mezzo poroso. Condizioni al contorno di Von Neumann: permettono di imporre una condizione di velocit´ dalla quale poi ricavare densit´ e pressione, sulla a a base delle condizioni interne al dominio. Condizioni al contorno di Dirichlet: vengono posti dei vincoli su pres- sione e densit´ per poi ricavare le velocit´. a a Condizioni al contorno per il rimbalzo: definiscono la dinamica del rimbalzo delle particelle contro i bordi delle superfici solide. Quest’ultime, in particolare, verranno approfondite nella prossima sot- tosezione, in quanto utilizzate ai fini della simulazione. 2.4.1 Rimbalzo Le condizioni al contorno per il rimbalzo (in inglese bounceback boundaries) vengono utilizzate per simulare la presenza di superfici solide nel dominio di simulazione. All’interno di esse, la velocit´ delle particelle viene considerata a nulla, permettendo cos´ di distinguere queste aree da quelle occupate da flu- ı ido.
  • 29. 20 Boltzmann e i metodi reticolari Quando, ad un certo istante di tempo, una particella arriva ad un nodo (del reticolo) appartenente ad una superficie solida, al passo successivo viene rimandata indietro nella stessa direzione da cui ´ arrivata, conservandone le e densit´ e mantendo inalterati il modulo e la direzione della velocit´ di arrivo, a a ma cambiandone il verso. Un modo per ottenere questo consiste nel memorizzare all’interno dei bordi solidi le distribuzioni di densit´ al tempo t, per poi farle “riemergere” a al tempo t + δt. Questa schema procedurale ´ chiamato in inglese mid-plane e bounceback, in quanto l’effettiva posizione della parete di rimbalzo si trova a met´ tra i nodi solidi e il fluido, ed ´ riportato in Figura 2.4. a e Figura 2.4: Rimbalzo di tipo mid-plane. [4]
  • 30. 2.5 ILBM e fluidi multifase 21 2.5 ILBM e fluidi multifase Quanto descritto nelle sezioni precedenti riguarda l’applicazione dei metodi di Boltzmann ai soli casi di simulazione di fluidi monofase. In realt´, in a natura ´ molto pi´ comune avere a che fare con flussi di fluidi aventi diverse e u propriet´, ovvero fluidi multifase. a Un caso particolare di fluidi multifase sono i fluidi immiscibili, per i quali esiste un metodo di Boltzmann appropriato, ossia l’Immiscible lattice Boltz- mann Method o ILBM. Dovendo considerare due fluidi immiscibili, questo metodo risulta pi´ complesso di quello descritto in precedenza, in quanto ´ u e necessario tenere in considerazione non solo l’influenza della tensione super- ficiale che si genera, ma anche la bagnabilit´ relativa di entrambi i fluidi nei a confronti delle superfici solide, e le complesse dinamiche che si sviluppano in corrispondenza delle interfacce di contatto tra le due sostanze. Il metodo di Boltzmann per fluidi immiscibili, introdotto nel 1988 da Rothman e Keller [6], segue la stessa linea procedurale utilizzata per i fluidi monofase, considerando per´ la presenza di due diversi tipi di particelle. Ci´ o o comporta un raddoppiamento delle informazioni in ogni nodo del reticolo. Il punto cruciale di questo modello bifase ´ rappresentato dall’interazione e tra i due fluidi, la quale viene simulata mediante un’interazione locale tra particelle dello stesso tipo e una repulsione tra particelle di tipo diverso. 2.5.1 Interfaccia e gradiente di colore L’interfaccia ´ la zona di contatto tra due fluidi, ovvero tutti quei nodi nei e quali sono presenti presenti valori di densit´ di entrambi i tipi, come mostrato a in Figura 2.5. Per scoprire se un nodo del reticolo si trova in questa zona, ´ e necessario calcolare il gradiente di colore. Figura 2.5: Densit´ nelle zone di interfaccia. [7] a
  • 31. 22 Boltzmann e i metodi reticolari Il gradiente di colore ´ un vettore le cui componenti in un punto (x, y) e sono le derivate parziali prime calcolate in quel punto, ovvero: 1 R−B Gx = ρ − ρR−B (2.8) 2 x+1 x−1 1 R−B Gy = ρ − ρR−B (2.9) 2 y+1 y−1 dove R e B corrispondono a rosso e blu, i colori assegnati ai due fluidi im- miscibili (ad esempio, olio e acqua, rispettivamente), e ρR−B = ρR − ρB . Ai fini della simulazione, le aree solide (che nel nostro caso sono delimitate dal perimetro dell’area bagnata) hanno densit´ macroscopica ρS = −1, in modo a tale da far concentrare verso l’interno il fluido rosso. Con i valori calcolati rispetto agli assi cartesiani, ´ possibile calcolare il e modulo e l’angolo del gradiente: |G| = G 2 + G2 x y (2.10) Gy θG = arctan (2.11) Gx Il primo consente di stabilire se una determinata particella si trova nella zona di interfaccia, a seconda che sia minore o maggiore di un certo valore di soglia minima. Questo ´ sensato dal momento che il modulo del gradiente e ´ grande nelle zone appartenenti all’interfaccia ed ´ invece trascurabile nelle e e zone contenenti fluido di un solo tipo. 2.5.2 La ricolorazione La ricolorazione consiste nella redistribuzione delle densit´ microscopiche a delle particelle appartenenti all’interfaccia lungo le direzioni, in modo tale da spingerle verso particelle dello stesso fluido, conservandone per´ la massa o totale. In Figura 2.6 ´ rappresentato questo meccanismo. e Figura 2.6: Meccanismo di ricolorazione. [7]
  • 32. 2.5 ILBM e fluidi multifase 23 Se un nodo del reticolo risulta essere appartenente ad una zona di interfac- cia, il suo gradiente di colore sar´ elevato. Tramite il calcolo della proiezione a del gradiente lungo le direzioni delle velocit´ microscopiche (Figura 2.7), ´ a e possibile ordinare quest’ultime in base alla maggiore vicinanza con il gradi- ente, determinando cos´ le direzioni verso cui sono pi´ attratte le particelle ı u dei due fluidi. Figura 2.7: Definizione delle priorit´ delle direzioni mediante il calcolo delle a proiezioni del gradiente su di esse. Il calcolo della proiezione ortogonale del gradiente lungo ogni velocit´ micro- a scopica si ottiene attraverso il prodotto scalare dei due vettori, nel seguente modo: Ga = G · ea = Gx ex + Gy ey (2.12)
  • 33. 24 Boltzmann e i metodi reticolari
  • 34. Simulazione mediante CUDA 3 In questo capitolo verr´ descritta la simulazione oggetto di questa tesi e sar´ a a quindi presentato e spiegato il codice creato. 3.1 Strumenti utilizzati Per la realizzazione del codice sono stati utilizzati i seguenti strumenti: Hardware – Scheda grafica NVIDIA GeForce GTX 460 – Processore Intel Core i7-990X Software – Sistema operativo Windows 7 Enterprise, 64-bit – CUDA Toolkit 4.1 – NVIDIA Driver 295.73 – GLUT 3.7.6 – Visual Studio x64 Command Prompt (2010) – Notepad++ 3.1.1 Specifiche tecniche Scheda grafica La scheda grafica utilizzata ´ ormai stata superata in termini di prestazioni e da altre del suo genere, ma ´ risultata comunque efficace ai fini del lavoro e svolto. Alcune caratteristiche rilevanti sono riportate in Tabella 3.1
  • 35. 26 Simulazione mediante CUDA Capacit´ computazionale1 a 2.1 Memoria globale 2GB Multiprocessori 7 CUDA core 336 (48x7MP) Dimensione cache L2 524288 bytes Registri per blocco 32768 Grandezza warp 32 thread Massimo numero thread per blocco 1024 Grandezza massima delle dimensioni di un blocco 1024 x 1024 x 64 Grandezza massima delle dimensioni di una griglia 65535 x 65535 x 65535 Tabella 3.1: Alcune specifiche tecniche della scheda grafica. 3.2 La simulazione Il codice oggetto di questa tesi permette di simulare il fenomeno della decom- posizione spinodale tra due fluidi immiscibili. La decomposizione spinodale ´ un meccanismo per il quale una miscela di due (o pi´) componenti viene e u separata in due distinte regioni (o fasi), con diverse propriet´ chimico-fisiche. a In questa simulazione sono presenti due fluidi (come potrebbero essere acqua e olio) rappresentati da due diversi colori (blu e rosso, rispettivamente). In Figura 3.1 ´ riportato l’avanzamento della simulazione in diversi istanti di e tempo crescenti. Figura 3.1: Simulazione del fenomeno della decomposizione spinodale. 1 E’ un indice identificativo del tipo di architettura CUDA, costituito da due valori. Il primo indica il tipo di architettura dei core, mentre il secondo indica un miglioramento incrementale dell’architettura dei core e/o l’aggiunta di nuove funzionalit´. a
  • 36. 3.3 Il codice 27 3.3 Il codice In questa sezione verr´ analizzato il codice prodotto. a 3.3.1 Diagramma di flusso In Figura 3.2 sono riportate alcune informazioni preliminari per una corretta comprensione del codice, mentre in Figura 3.3 ´ riportato il diagramma di e flusso. Figura 3.2: Informazioni preliminari.
  • 37. 28 Simulazione mediante CUDA
  • 38. 3.3 Il codice 29 Figura 3.3: Diagramma di flusso.
  • 39. 30 Simulazione mediante CUDA 3.3.2 Inizio Il codice presenta prima di tutto l’inizializzazione delle variabili globali. Subito dopo vengono implementate tutte le funzioni. Per maggior chiarezza, il codice integrale ´ riportato in Appendice. e L’esecuzione del programma ha inizio all’interno della funzione main. Qui sono inizializzate le quattro matrici principali, sottoforma di lunghi vettori2 . In particolare, alla matrice Red vengono assegnati dei valori casuali e di con- seguenza anche a Blue, essendo quest’ultima calcolata sulla base della prima. Le matrici bidimensionali RhoR e RhoB, invece, sono calcolate come somma lungo le nove direzioni di profondit´ di ogni elemento delle altre due matrici. a Le matrici Red e Blue, quindi, corrispondono alle funzioni di distribuzione (vedi Sezione 2.2) dei due fluidi, mentre RhoR e Blue corrispondono alle loro densit´ macroscopiche. a Terminata l’inizializzazione, si procede con l’allocazione della memoria da utilizzare sul device, e con la copia delle quattro matrici all’interno delle lo- cazioni appena create, utilizzando le funzioni CUDA descritte nella Sezione 1.4. Quindi viene richiamato il metodo anim and exit, appartenente alla strut- tura bitmap. Questo ´ il metodo che permette l’animazione grafica (descritta e brevemente nella Sezione 3.3.4), il quale richiede l’esecuzione di altre due fun- zioni: anim gpu, che contiene le chiamate ai kernel, e anim exit, che contiene le direttive di deallocazione della memoria precedentemente istanziata sul de- vice. All’inizio della funzione anim gpu, vengono dichiarate le variabili grid e threads, che contengono rispettivamente il numero totale di blocchi all’in- terno della griglia e di thread all’interno di ogni blocco. dim3 ´ un tipo di e dato predefinito di CUDA. In particolare, ´ un tipo di vettore tridimensionale e che permette di specificare fino a tre valori per la variabile dichiarata3 . 3.3.3 I kernel I primi quattro kernel realizzati hanno lo scopo di eseguire i calcoli previsti dal metodo di Boltzmann descritto nella Sezione 2.5, mentre l’ultimo ´ impli- e cato nella resa grafica e verr´ quindi brevemente descritto nella Sezione 3.3.4. a 2 Ci si riferir´ comunque a questi vettori utilizzando il termine “matrici”. a 3 Valori eventualmente non dichiarati vengono automaticamente posti a 1.
  • 40. 3.3 Il codice 31 Non esistendo delle direttive apposite, ´ stato deciso di dividere i kernel e per ottenere la certezza che tutti i thread di tutti i blocchi fossero sincroniz- zati tra loro4 , cos´ da evitare conflitti di tipo RAW (lettura dopo scrittura), ı WAR (scrittura dopo lettura) oppure WAW (scrittura dopo scrittura). Ogni kernel ´ costruito per essere eseguito su ogni pixel dell’immagine e finale, ovvero per calcolare ogni singolo elemento delle matrici RhoR e RhoB. Collision In questo kernel viene trattata la collisione delle particelle di fluido all’inter- no di ogni nodo5 del reticolo. All’inizio della sua esecuzione, vengono copiate alcune variabili dalla memo- ria globale a quella locale, permettendo cos´ di evitare continue richieste di ı memoria off-chip. Tra queste variabili ci sono anche due vettori (R e B) che servono a memorizzare i valori contenuti in Red e Blue nella stessa posizione assunta dal thread (che lo sta eseguendo) rispetto alla griglia. Questa po- sizione ´ facilmente ricavabile sfruttando le variabili predisposte da CUDA, e come descritto nella Sezione 1.3. La collisione consiste nel rilassamento verso l’equilibrio, per cui viene im- plementata tramite il calcolo della funzione di equilibrio lungo tutte le nove direzioni e la correzione delle funzioni di densit´ locali R e B. a Infine, vengono ricalcolate RhoR e RhoB per poterne calcolare la differenza (memorizzandola direttamente nella memoria globale nella matrice puntata dal puntatore ptRhoR B) da utilizzare nel kernel successivo. Recoloring Questo ´ il kernel in cui avviene il trattamento delle zone di interfaccia se- e condo quanto descritto nelle Sezioni 2.5.1 e 2.5.2. Per il calcolo del gradiente di colore, vengono utilizzati i valori delle differenze di densit´ macroscopiche delle posizioni adiacenti in verticale e in orizzontale a alla posizione di ogni thread. Questo ´ uno dei casi in cui ´ assolutamente e e necessario che tutti i thread abbiano concluso le operazioni inserite nel kernel precedente. Una volta calcolato il modulo del gradiente, questo viene usato per decidere se un certo nodo appartiene a una zona di interfaccia oppure no. Se il respon- 4 Esistono invece delle funzioni CUDA C per la sincronizzazione di tutti i thread appartenenti ad un blocco. 5 In questo caso, ogni nodo corrisponde a un pixel, ovvero ad una posizione delle matrici RhoR o RhoB.
  • 41. 32 Simulazione mediante CUDA so ´ positivo, viene calcolata la tensione superficiale 6 lungo tutte le direzioni, e e viene quindi eseguita la ricolorazione dell’interfaccia. Questa differenza di esecuzione pu´ causare il fenomeno della divergenza dei thread descritto nella o Sezione 1.3, facendo cos´ aumentare il tempo di esecuzione dell’intero kernel. ı Infine, vengono eseguite delle operazioni che in realt´ apparterrebbero alla a fase di propagazione. Il motivo di questa scelta riguarda sempre la sin- cronizzazione dei thread. Le operazioni anticipate sono quelle riguardanti le condizioni al contorno, ovvero il rimbalzo delle particelle contro i bordi dell’area di simulazione. Queste condizioni vengono implementate copiando i valori attuali delle matrici Red e Blue in due matrici temporanee7 , salvando in Red e Blue i nuovi valori dopo il rimbalzo, secondo lo schema di Figu- ra 2.4 e Figura 2.2, e poi impostando al valore −1 le direzioni delle matrici temporanee che hanno sub´ il rimbalzo. ıto Streaming e Streaming2 La parte iniziale del kernel Streaming ´ occupata dal calcolo degli indici as- e soluti delle otto posizioni adiacenti a quella di ogni thread in esecuzione. Dopodich´ avviene la fase di propagazione vera e propria. Questa consiste e nel copiare i valori contenuti nelle matrici temporanee nelle stesse direzioni delle locazioni delle matrici Red e Blue adiacenti alla posizione considerata. Se per´ il valore salvato in una direzione delle matrici temporanee ´ pari a o e −1, allora la propagazione verso quella direzione non avviene, in quanto gi´ a trattata dal kernel precedente. Il kernel denominato Streaming2 si occupa semplicemente del ricalcolo delle matrici RhoR e RhoB. Anch’esso ´ stato diviso da quello precedente per con- e sentire la sincronizzazione delle operazioni sulle matrici Red e Blue. 3.3.4 L’animazione grafica Non essendo lo scopo di questa tesi, per la resa grafica della simulazione sono stati usati dei codici predisposti da NVIDIA e reperibili online. Per una trattazione pi´ esaustiva consultare [3]. u Questi codici sono basati sull’interoperabilit´ di CUDA con una tra le pi´ a u 6 Dal punto di vista fluidodinamico, ´ una particolare tensione meccanica che si sviluppa e lungo la superficie di separazione (interfaccia) tra due fluidi. 7 In realt´ non sono temporanee, sono allocate nella memoria globale esattamente come a le altre, ma vengono chiamate cos´ ai fini dell’implementazione. ı
  • 42. 3.3 Il codice 33 popolari API di resa grafica in tempo reale, ovvero OpenGL8 (e GLUT9 ). Per assegnare i colori ad ogni pixel dell’immagine, viene utilizzato il kernel float to color. A seconda che in una certa posizione prevalga il colore rosso piuttosto che il blu, viene impostato il colore adeguato sfruttando i quattro campi10 di ogni elemento della matrice output bitmap, utilizzata per la resa grafica. 8 Open Graphics Library, sviluppata da ATI (ora AMD), ´ una specifica che definisce e una API per pi´ linguaggi e per pi´ piattaforme per scrivere applicazioni che producono u u grafica 2D e 3D. 9 OpenGL Utility Toolkit, ´ una libreria che semplifica l’accesso alle funzionalit´ di e a OpenGL. 10 Corrispondenti a rosso, verde, blu e fattore alpha
  • 43. 34 Simulazione mediante CUDA
  • 44. Test finali 4 4.1 La misurazione dei tempi La misurazione del tempo di esecuzione di un programma ´ sempre un’op- e erazione delicata, in quanto pu´ essere influenzata da diversi fattori, come o la schedulazione dei thread da parte del sistema operativo, la precisione dei contatori disponibili, l’esecuzione asincrona del codice su host e device, ecc. Per quanto riguarda i test di seguito riportati, sono stati utilizzati due metodi di misurazione: uno basato sui tempi d’esecuzione della singola GPU (descritto nella Sezione 4.1.1), l’altro basato sui tempi totali d’esecuzione. Quest’ultimo in particolare ´ stato implementato nel codice utilizzando la e funzione C++ clock() fornita dalla libreria time.h. Questa funzione ritorna come risultato il numero di cicli di clock trascorsi dall’avvio dell’esecuzione del programma. Per ottenere il valore medio di esecuzione di ogni schermata (frame) della simulazione, si ´ proceduto nel seguente modo: e 1. Prima della chiamata alla funzione anim and exit, viene salvato il valore ritornato da clock() nel campo start c della struttura data, creato appositamente per lo scopo. 2. All’interno della funzione anim gpu, al termine dei kernel, viene calco- lato il numero di cicli di clock totale (fino a quel momento) e salvato all’interno del campo tot di data. 3. Il valore salvato in tot viene diviso per la costante predefinita CLOCKS PER SEC (che in questo caso vale 1000) e poi stampato a video, otte- nendo cos´ i secondi totali d’esecuzione. ı
  • 45. 36 Test finali 4. Una volta raggiunti i 12000 frame, viene bloccata l’esecuzione del pro- gramma e il valore totale visualizzato viene diviso per 12000, ottenendo cos´ il tempo medio di esecuzione di ogni frame. ı 4.1.1 Eventi CUDA Per misurare il tempo di cui la GPU ha avuto bisogno per calcolare i kernel di ogni schermata della simulazione, sono state usate delle strutture prede- finite chiamate eventi. Un evento in CUDA ´ essenzialmente la stampa a e video del tempo di esecuzione della GPU, registrato in un punto scelto dal programmatore. Per ottenere la stampa del tempo di elaborazione, ´ necessario creare un e evento, permettergli di registrare il tempo e poi chiuderlo, utilizzando alcune funzioni fornite da CUDA. 4.2 Il confronto Come primo test, ´ stato eseguito il confronto tra il programma realizza- e to in CUDA e lo stesso1 programma realizzato in MATLAB [1], facendoli funzionare sulla stessa macchina e nelle stesse condizioni. linguaggio unit´ di calcolo a num.frame video ms per frame (media) MATLAB CPU 2000 No 19.8 CUDA C GPU 2000 No 0.5 Tabella 4.1: Confronto tra il programma scritto in MATLAB e lo stesso scritto in CUDA, senza la visualizzazione dell’animazione. linguaggio unit´ di calcolo a nr.frame video ms per frame (media) MATLAB CPU 2000 S´ ı 180.2 CUDA C GPU 2000 S´ ı 16.7 Tabella 4.2: Confronto tra il programma scritto in MATLAB e lo stesso scritto in CUDA, con la visualizzazione dell’animazione. 1 Il programma realizzato segue la stessa linea procedurale di quello scritto in MATLAB, ma con le dovute modifiche, dettate dal linguaggio di programmazione e dall’architettura CUDA.
  • 46. 4.3 Altri test 37 4.3 Altri test In seguito ai risultati ottenuti dal confronto col codice Matlab, sono stati eseguiti alcuni test per valutare le prestazioni del programma CUDA al va- riare del numero di blocchi e di thread. In particolare, ms kernel indica il tempo medio d’esecuzione di tutti i cinque kernel in millisecondi, mentre ms tot, indica il tempo medio di esecuzione totale di ogni frame, comprendente i tempi della CPU. nr.pixel nr.blocchi nr.thread nr.frame ms kernel ms tot 100x100 10x10 10x10 12000 0.5 0.8 100x100 20x20 5x5 12000 0.6 0.9 100x100 25x25 4x4 12000 0.8 1.2 100x100 50x50 2x2 12000 2.4 2.7 Tabella 4.3: Confronto tra diverse disposizioni di thread per blocco, senza la visualizzazione dell’animazione. nr.pixel nr.blocchi nr.thread nr.frame ms kernel ms tot 100x100 10x10 10x10 12000 0.5 16.7 100x100 20x20 5x5 12000 0.6 16.7 100x100 25x25 4x4 12000 0.8 16.7 100x100 50x50 2x2 12000 2.4 16.7 Tabella 4.4: Confronto tra diverse disposizioni di thread per blocco, con la visualizzazione dell’animazione. Infine, sono stati eseguiti dei test per valutare la scalabilit´ 2 del modello, a relativamente alle dimensioni in pixel delle immagini visualizzate. 2 In campo informatico, ´ un concetto generale che indica la capacit´ di un sistema di e a aumentare o diminuire di scala in funzione delle necessit´ e delle disponibilit´. a a
  • 47. 38 Test finali nr.pixel nr.blocchi nr.thread risultato 90x90 18x18 5x5 OK 108x108 18x18 6x6 OK 110x110 10x10 11x11 OK 110x110 11x11 10x10 OK 114x114 19x19 6x6 stackOverflow 117x117 13x13 9x9 stackOverflow 120x120 10x10 12x12 stackOverflow 120x120 12x12 10x10 stackOverflow 120x120 15x15 8x8 stackOverflow 121x121 11x11 11x11 stackOverflow 126x126 18x18 7x7 stackOverflow 130x130 13x13 10x10 stackOverflow 150x150 10x10 15x15 stackOverflow 150x150 15x15 10x10 stackOverflow 162x162 18x18 9x9 stackOverflow 180x180 18x18 10x10 stackOverflow Tabella 4.5: Scalabilit´ del sistema. a
  • 48. Conclusioni 5 Com’era prevedibile, i test riguardanti il confronto tra il codice scritto in MATLAB eseguito su una CPU e il corrispettivo in CUDA, hanno mostrato una superiorit´ del secondo rispetto al primo di 10 volte con la visualiz- a zazione dell’animazione, e di ben 40 volte senza la visualizzazione. Questo ´ e un ottimo risultato, considerando che il codice CUDA non ´ stato ottimizza- e to, mentre quello MATLAB s´ e che, dal punto di vista hardware, la CPU ı, utilizzata era una delle pi´ potenti e costose fino a sei mesi fa, mentre la u GPU ´ stata prodotta quasi due anni fa e venduta ad un prezzo pari ad 1/5 e di quello della CPU. Per quanto riguarda gli altri test, quelli sulla variazione del numero di thread mostrano che andando ad eccedere sempre pi´ nel numero di bloc- u chi rispetto al numero di CUDA core disponibili, avviene un rallentamento nell’esecuzione, probabilmente in quanto rimangono troppi thread in attesa. Il motivo per cui i millisecondi totali con la visualizzazione restano sem- pre uguali, potrebbe essere attribuito ad un implicito intervallo di tempo minimo tra una visualizzazione e l’altra, imposto dall’interfaccia di visualiz- zazione per una corretta visione dell’animazione. Questo di fatto impedisce di godere appieno di eventuali ottimizzazioni al codice destinato ad essere eseguito dalla GPU. I test sulla scalabilit´ mostrano, invece, che non ´ possibile aumentare di a e molto la dimensione del modello. Questo ´ probabilmente dovuto alla situa- e zione di divergenza che si viene a creare nel kernel di ricolorazione, al limitato numero di registri disponibili e, in generale, alla mancanza di ottimizzazione delle risorse che CUDA mette a disposizione, in particolare le diverse memo- rie.
  • 49. 40 Conclusioni In conclusione, alcune ottimizzazioni possibili per questo codice potreb- bero comprendere l’utilizzo della memoria condivisa da parte dei thread di uno stesso blocco, e di quella costante per la memorizzazione delle costanti utilizzate da tutti i thread in generale, oppure l’utilizzo di strutture real- mente bidimensionali e tridimensionali per la memorizzazione delle matrici utilizzate nel codice, in sostituzione alla loro trasformazione in vettori. Per quanto riguarda la visualizzazione, invece, sarebbe necessario ridurre l’inter- vallo di visualizzazione tra un frame e l’altro, in modo tale da rendere utili le ottimizzazioni effettuate.
  • 51. 42 Appendice A. Codice integrale
  • 52. 43
  • 53. 44 Appendice A. Codice integrale
  • 54. 45
  • 55. 46 Appendice A. Codice integrale
  • 56. 47
  • 57. 48 Appendice A. Codice integrale
  • 58. 49
  • 59. 50 Appendice A. Codice integrale
  • 60. 51
  • 61. 52 Appendice A. Codice integrale
  • 62. 53
  • 63. 54 Appendice A. Codice integrale
  • 64. 55
  • 65. 56 Appendice A. Codice integrale
  • 66. Bibliografia [1] G. Schena, immiscible LB, codice MATLAB che usa i metodi reticolari di Boltzmann (LB) per simulare flussi di fase di flu- idi immiscibili (blu e rosso) in 2D secondo lo schema D2Q9, (Settembre 2010, ultima revisione). Disponibile online all’indirizzo: http://www.mathworks.com/matlabcentral/fileexchange/24824-i mmiscible-lb [2] NVIDIA Corporation,CUDA C Programming Guide Version 4.0, reperibile online, (5/6/2011). [3] J. Sanders, E. Kandrot, CUDA By Example - An Intro- duction to General-Purpose GPU programming, Addison- Wesley, 2010. I codici sorgente di tutti gli esem- pi presenti nel libro sono disponibili online all’indirizzo: http://developer.nvidia.com/cuda-example-introduction-gener al-purpose-gpu-programming [4] M.C. Sukop, D.T. Thorne Jr., Lattice Boltzmann Modeling - An Introduction for Geoscientists and Engineers Springer, (2007). [5] E. Rustico, Fluid dynamics simulations on multi-GPU sys- tems, Tesi di dottorato, (2011). Reperibile online all’indirizzo: http://www.dmi.unict.it/∼cantone/EsameFinaleDottorato/Tesi/ RUSTICO.pdf [6] D.H. Rothman, J.M. Keller, Immiscible cellular-automaton fluids, Journal of Statistical Physics, Vol.52, Nos.3/4, (1988).
  • 67. 58 BIBLIOGRAFIA [7] J.Toelke, Lattice Boltzmann multiphase simulations using GPUs, conferenza, GTC 2010, San Jos, CA, (2010). Video reperibile online. [8] GPGPU.IT, Tutorial CUDA, breve tutorial introduttivo a CUDA, (2009). URL: http://www.gpgpu.it/joomla/cuda-tutorial/tutoria l-cuda-ultimi-elementi-base.html
  • 68. Indice analitico blockDim, 7 condizioni al contorno, 19 blockIdx, 7 di Dirichlet, 19 CLOCKS PER SEC, 35 di Von Neumann, 19 clock(), 35 gradiente di pressione, 19 cudaFree(), 9 periodiche, 19 cudaMalloc(), 9 rimbalzo, 19 cudaMemcpy(), 9 conflitti dim3, 30 RAW, 30 gridDim, 7 WAR, 30 nvcc, 12 WAW, 30 threadIdx, 7 core, 4 global , 7 CUBIN, 12 CUDA, 3 A CUDA C, 3, 7 ALU, 4 API, 3 D D2Q9, 16 B decomposizione spinodale, 26 BGK, 18 densit´ macroscopica, 16 a Bhatnagar-Gross-Krook, 18 device, 4 blocco, 4 divergenza, 7 bounceback boundaries, 19 DRAM, 4 C E calcolo parallelo, 4 eventi, 36 capacit´ computazionale, 25 a collisione, 15, 18 F compilazione, 12 fluidi immiscibili, 21
  • 69. 60 INDICE ANALITICO fluidi multifase, 21 O frame, 35 on chip, 9 funzione di distribuzione, 16 OpenGL, 32 funzione di equilibrio, 18 P G pesi, 18 GeForce GTX 460, 25 principio di localit´, 9 a general-purpose, 3 propagazione, 15, 18 GFLOP/s, 3 PTX, 12 GLUT, 32 GPU, 3 R gradiente di colore, 21 rendering, 3 griglia, 4 ricolorazione, 22 rimbalzo, 19 H host, 4 S scalabilit´, 36 a I SIMD, 4 ILBM, 21 streaming, 15 indice assoluto, 7 interfaccia, 21 T tensione superficiale, 31 K thread, 4 kernel, 7 U L unit´ di controllo, 4 a larghezza di banda, 9 lattice Boltzmann methods, 15 V LBM, 15 velocit´ macroscopica, 16 a Ludwig Boltzmann, 15 velocit´ microscopiche, 16 a M W memoria, 9 warp, 4, 7 condivisa, 9 mezzo-warp, 9 costante, 9 device memory, 4 globale, 9 host memory, 4 locale, 9 texture memory, 9 metodi reticolari, 15 mid-plane bounceback, 19 multiprocessore, 7
  • 71. Finito di stampare in Marzo 2012 utilizzando LTEX 2ε A