Sei sulla pagina 1di 47

La flessibilita di MatLab e la potenza delle GPU

Piero Lanucara, Fabio Bonaccorso CASPUR Via dei Tizii,6b 00185 Roma Italy http://www.caspur.it E-mail:f.bonaccorso@caspur.it E-mail: p.lanucara@caspur.it

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 2

Sommario
1. 2. 3. 4. 5. 6. La GPU La piattaforma CUDA Esecuzione di programmi CUDA Integrazione con Matlab attraverso i Mex file Jacket Esempi

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 3

La GPU: Graphic Processing Unit


La GPU e' un processore dedicato a calcoli basilari per la grafica
Incorpora hardware specifico per velocizzare operazioni matematiche tipiche in grafica

La GPU scarica la CPU per questi calcoli, raggiungendo un'efficienza non uguagliabile in software
Le vecchie GPU acceleravano operazioni 2d, oggi si occupano di tutto il processo anche nel 3d Hanno capacita' di calcolo intorno ai 1000 GFlop/s
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 4

GPU vs CPU: prestazioni


Performance crescenti nel tempo

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 5

GPU vs CPU: prestazioni


Performance del sistema di memoria
La banda di memoria e' la misura della velocita' con cui la CPU (GPU) legge (o scrive) i dati in memoria
Una banda maggiore permette di trasferire piu' dati per unit di tempo
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 6

GPU vs CPU: architettura interna

Nella CPU molto hardware e dedicato al controllo del flusso di esecuzione e alla cache Architettura flessibile (general purpose)
Scuola Estiva di Calcolo Avanzato 2008

Nella GPU la maggior parte dellhardware e utilizzato per le molte unita' di calcolo Architettura dedicata (special purpose)

Matlab e Cuda: 7

GPU vs CPU
Una CPU (oggi) si sfrutta al massimo massimizzando l'utilizzo della cache
La cache avvicina i dati alla CPU
La memoria ha maggiore latenza e minore banda

Essendo general-purpose e' adatta a tutti gli algoritmi

La GPU nasce per il calcolo data-parallel


Stesso codice su operandi diversi (vettori, matrici) Idonea per algoritmi con alta intensita' numerica
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 8

CUDA: Cos'e'
CUDA e unarchitettura hardware e software per sfruttare la potenza delle moderne GPU per il calcolo (scientifico)
Acronimo di Compute Unified Device Architecture

Supera i problemi dei precedenti approcci GP-GPU


Non usa unAPI grafica (OpenGL, Direct3D)

E' uno standard proprietario di NVIDIA E' multipiattaforma (C con estensioni + runtime)
Linux (32 e 64 bit) Windows (32 e 64 bit)
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 9

CUDA: modello di esecuzione



Il programma inizia sulla CPU (Host) La CPU esegue una parte di codice
Trasferimenti CPU<->GPU

Il codice (sulla CPU) invoca un kernel eseguito dalla GPU (Device)


In parallelo da piu threads

La CPU esegue altro codice


Trasferimenti CPU<->GPU

... Il programma termina sulla CPU

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 10

CUDA: implementazione Hardware


Una GPU e' composta da: Uno o piu' multiprocessori
Il numero dipende dal modello della GPU

Memoria (device memory)


Globale Costante Texture
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 11

CUDA: implementazione Hardware


Ogni multiprocessore ha: Una sola unita per lesecuzione del codice (istruzioni) Memoria condivisa Uno o piu processori Ogni processore consiste di: Una sola unita di calcolo Registri Memoria locale (opzionale)
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 12

CUDA: Definizioni
Thread
Flusso di esecuzione indipendente I thread eseguono lo stesso codice su operandi diversi Ogni thread ha un ID univoco (threadIdx) Permette di selezionare i dati su cui opera il thread

Il blocco e un gruppo di thread


Il blocco e' assegnato ad un unico multiprocessore Se il blocco contiene piu thread del numero di processori, i thread verranno eseguiti in time-slice Puo' essere un insieme lineare, 2D o 3D di thread Ha una sua memoria condivisa Fino al termine dell'esecuzione del blocco di threads da parte del multiprocessore
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 13

CUDA: Definizioni
La griglia CUDA e un gruppo di blocchi
Puo' essere un insieme lineare, 2D o 3D di blocchi Permette di mappare il problema in maniera naturale sui differenti blocchi Ogni blocco ha un ID univoco nella griglia (blockIdx)

CUDA e' progettato per lavorare efficientemente con un alto numero di threads La priorita e far calcolare tutti i processori Bisogna trovare la dimensione ottimale del blocco

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 14

CUDA: Memoria
Condivisa (Shared) Accesso veloce
Visibile da tutti i threads di uno stesso blocco

Globale Accesso costoso (senza cache) Memoria visibile (lettura e/o scrittura) da tutti i threads Costante
Texture
Sfrutta unita' hw per operazioni di filtraggio

Accesso medio (cache)


Accesso medio (cache)

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 15

CUDA: il compilatore nvcc


Per compilare il codice CUDA si usa il compilatore nvcc Supporta le estensioni CUDA al C Compila file sorgenti con sintassi C++
Piu' restrittivo del C sul controllo dei tipi delle variabili La sintassi per la programmazione ad oggetti non e' (ad oggi) supportata
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 16

CUDA: modello di programmazione


Il codice CUDA permette di definire un kernel
Il kernel viene eseguito dalla griglia CUDA
Opera sui dati nelle memorie della GPU (globale, locale)

Bisogna portare i dati dalla CPU alla GPU e viceversa


Funzioni dell'API di CUDA

Alcune funzioni possono eseguire in modo asincrono La CPU puo' lavorare mentre la GPU esegue la chiamata

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 17

CUDA: estensioni al C
Per definire un kernel CUDA si usa la parola chiave __global__ prefisso alla funzione. Esempio:
__global__ void vecAdd(float* A, float* B){
int i = threadIdx.x; B[i] = A[i] + B[i];

In questo modo, nvcc compila il codice per la GPU Le variabili su cui opera il kernel sono sulla GPU
Distinte da quelle sulla CPU Vanno trasferite prima di chiamare il kernel
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 18

CUDA: estensioni al C
Se in un kernel CUDA si vuole chiamare unaltra funzione, questa va dichiarata con la parola chiave __device__ Esempio:
__device__ float scalarAdd(float a, float b){
return a + b;

} __global__ void vecAdd(float* A, float* B){


int i = threadIdx.x; B[i] = scalarAdd(A[i], B[i]);

}
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 19

CUDA: estensioni al C
Per invocare il kernel nel codice si usa l'operatore <<< dimGrid, dimBlock >>> Esempio:
vecAdd <<<1 , N >>> (a_dev, b_dev);

La griglia e' da 1 blocco da N threads Per dimensionare le griglie e i blocchi CUDA c'e' un tipo nuovo, dim3 che specifica un vettore 1D, 2D o 3D
dim3 dimGrid1(10); dim3 dimGrid2(20,10); dim3 dimBlock1(3,3,3); // Griglia di 10 blocchi // Griglia di 20x10 blocchi // Blocco di 3x3x3 thread

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 20

CUDA: principali funzioni dellAPI


Funzioni per allocare/deallocare memoria sulla GPU:
cudaError_t cudaMalloc(void** devPtr, size_t count) cudaError_t cudaFree(void* devPtr)

Funzioni per trasferire dati CPU <-> GPU:


cudaError_t cudaMemcpy( void* dst, const void* src, size_t count, enum cudaMemcpyKind kind) kind puo essere cudaMemcpyHostToDevice oppure cudaMemcpyDeviceToHost

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 21

CUDA: esempio di kernel


__global__ void vecAdd(float* A, float* B) { int x = threadIdx.x; int y = threadIdx.y * blockDim.x; int blSz = blockDim.x * blockDim.y; int bl = (blockIdx.y * gridDim.x + blockIdx.x) * blSz; int i = bl + ( x + y );
if (i < N) B[i] = alpha*A[i] + B[i]; } int main() { dim3 dimBlock(16,8); int grid_x = 16*4; int bloc_x = dimBlock.x; int bloc_y = dimBlock.y; int grid_y = (N + grid_x*bloc_x*bloc_y - 1) / (grid_x * bloc_x*bloc_y); dim3 dimGrid (grid_x, grid_y); float A[N], B[N]; VecInit(A,B, N); const unsigned int mem_size = sizeof(float) * N; void *a_dev, *b_dev; cudaMalloc( (void**) &a_dev, mem_size); // Alloco memoria per A sulla GPU cudaMalloc( (void**) &b_dev, mem_size); // Alloco memoria per A sulla GPU cudaMemcpy( a_dev, A, mem_size, cudaMemcpyHostToDevice); // Copio A sulla GPU cudaMemcpy( b_dev, B, mem_size, cudaMemcpyHostToDevice); // Copio B sulla GPU vecAdd <<<dimGrid,dimBlock>>> (a_dev, b_dev); cudaMemcpy( B, c_dev, mem_size, cudaMemcpyDeviceToHost); PrintVec(B, N); } // Copio B dalla GPU

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 22

CUDA: memoria shared


Laccesso alla memoria globale della GPU e costoso Il blocco puo utilizzare la memoria shared che e piu veloce La parola chiave da utilizzare e __shared__ Esempio:
__shared__ float As[BLOCK_SIZE];

Tutti i processi di uno stesso blocco (fino alla completa esecuzione del kernel) possono leggere/scrivere la memoria condivisa Laccesso da parte dei threads di un blocco deve essere coordinato dal programmatore
Si utilizza la funzione __syncthreads() che rende visibile a tutti i thread una modifica alla memoria condivisa

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 23

CUDA: memoria shared


Esempio:
__global__ void vecIncr(float* A) {
__shared__ float A_blocco[32]; int id = threadIdx.x; // Ogni thread opera su un indice differente A_blocco[id] = A[id]; __syncthreads(); A_blocco[32-id] ++; __syncthreads(); A[id] = A_blocco[id]; // Ogni thread riempie una parte della memoria shared // Ora i cambiamenti sono visibili a tutto il blocco // Ogni thread aggiorna una posizione // Tutti vedranno le modifiche // Ogni thread copia dalla memoria shared alla // memoria globale, altrimenti i cambiamenti verranno // perduti

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 24

CUDA: modalita emulazione


Per verificare il corretto comportamento del programma CUDA, si puo compilarlo utilizzando lopzione deviceemu di nvcc Il codice girera sulla CPU e sara possibile usare un debugger per eseguire le istruzioni un passo alla volta, esaminare variabili, ecc. Il flusso dellalgoritmo sara diverso
La CPU non eseguira tutti i thread in parallelo

In questa modalita nel kernel si possono usare funzioni di stampa, apertura file, ... non disponibili nellesecuzione sulla GPU
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 25

Librerie CUDA
La piattaforma CUDA viene fornita insieme a due librerie, che permettono di utilizzare implementazioni efficienti di algoritmi di base per il calcolo scientifico
CUBLAS CUFFT

Permettono unastrazione maggiore rispetto alla programmazione con i kernel CUDA Nella SDK ci sono numerosi esempi pronti per luso o da prendere a modello
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 26

CUDA: libreria BLAS


NVIDIA fornisce un'implementazione della libreria BLAS (Basic Linear Susbsystem Subroutine), che comprende funzioni tipiche dell'algebra lineare:
Operazioni tra vettori (BLAS1) Operazioni tra matrici e vettori (BLAS2) Operazioni tra matrici (BLAS3)

La libreria e' in C
Vengono forniti i wrapper per il Fortran che si occupano anche dei traferimenti CPU<->GPU
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 27

CUDA: libreria FFT


NVIDIA fornisce un'implementazione di una libreria per calcolare le fft (fast fourier transforms), modellata sulla libreria opensource FFTW (v2):
Trasformate 1D, 2D e 3D

La libreria e' in C
Vengono forniti i wrapper per il Fortran
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 28

CUDA stand-alone
Dopo aver compilato il programma CUDA, si lancia normalmente L'utilizzo della GPU puo' durare al piu' 5 sec
Altrimenti congela il monitor Si mette una scheda video secondaria

Il runtime CUDA deve essere nel path corrente

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 29

CUDA: esempio Blas3


Calcolare prodotto di due matrici con CUBLAS
Demo presente nell'SDK CUDA

Basta chiamare cublas_sgemm invece di sgemm!


Esempio con performance su AMD Opteron 2.8Ghz

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 30

CUDA: esempio Blas3


do n=128,2560,32 ! Initialize the matrices A,B and C A = 1. B = 2. C = 3. ! With the prescribed inputs, each element of the C matrix ! should be equal to c_right c_right= 2*n + 3

call cpu_time(time_start) call cublas_SGEMM ('n','n',n,n,n,alpha,A,n,B,n,beta,C,n)


call cpu_time(time_end) gflops = 1.e-9*(2*n*n*n - n*n)/(time_end-time_start) print "(i5,1x,a,1x,f8.4,2x,a,f12.4)", n, & " time =",time_end-time_start, GFLOPS=", gflops

end do

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 31

CUDA: prestazioni Blas3


CUDA ver 1.1 CUDA ver 2.0 (beta)

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 32

CUDA: reduction
Una reduction e unoperazione che opera su un insieme di dati e restituisce un valore
Minimo, massimo, media, ecc. di un vettore

Nell'SDK ce il codice sorgente di implementazioni CUDA Esempio avanzato da studiare e utilizzare!

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 33

CUDA con Mex


Utilizzando Matlab, l'implementazione CUDA si occupera soltanto del calcolo vero e proprio
Le matrici, vettori, ecc. vengono inizializzati nell'ambiente Matlab Il calcolo viene lanciato sulla GPU attraverso il MEX
Nel MEX dobbiamo trasferire i dati verso la GPU e poi indietro negli array predisposti da Matlab Il tutto sempre ricordando che si lavora in singola precisione floating point (per ora)
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 34

CUDA+Mex: moltiplicazione di matrici


#include "mex.h" #include "mclcppclass.h" void mexFunction(int nlhs, mxArray * plhs[], int nrhs, const mxArray * prhs[]) { float *A, *B, *C; float one = 1.0, zero = 0.0; int m, n, p; char *chn = "N"; /* Retrieve the input data */ A = (float*)mxGetPr(prhs[0]); B = (float*)mxGetPr(prhs[1]); /* Find the dimension of the data */ m = mxGetM(prhs[0]); p = mxGetN(prhs[0]); n = mxGetN(prhs[1]); /* Error checking */ if (p != mxGetM(prhs[1])) mexErrMsgTxt(Dim mismatch"); /* Create an mxArray for the output data */ mwSize dims[2] = {m,n}; mxClassID tipo = mxSINGLE_CLASS; plhs[0] = mxCreateNumericArray(2, dims, tipo, mxREAL); /* Create a pointer to the output data */ C = mxGetPr(plhs[0]); /* Pass all arguments to Fortran by reference */ cublas_sgemm(chn, chn, &m, &n, &p, &one, A, &m, B, &p, &zero, C, &m); }

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 35

CUDA con Mex: prestazioni


Matlab su Opteron La versione sulla GPU raggiunge i 100 Gflop/s In questo caso incide l'overhead del mex file, rispetto alla versione CUDA stand-alone

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 36

Matlab -> Jacket -> CUDA: alto livello e buone prestazioni


L'utilizzo della GPU da un programma Matlab richiede la scrittura di un Mex file e dell'implementazione della routine in CUDA Jacket permette invece un uso trasparente della GPU
Si lavora a livello di vettori e matrici Crea i mex file necessari Lancia il calcolo sulla GPU
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 37

Jacket e Matlab - 1
Jacket e un plugin per Matlab prodotto dalla AccelerEyes (ancora in betaversion).

Jacket, intervenendo ad un livello di astrazione notevolmente superiore ad altri strumenti analoghi, rimpiazza le strutture dati (originarie) di MATLAB, normalmente sulla CPU, in strutture dati sulla GPU. Tutte le operazioni saranno effettuate sulla GPU invece che sulla CPU (in modalit dataparallel). Alla fine del calcolo sar possibile riavere i dati sulla CPU utilizzando le funzionalit gi presenti in MATLAB.

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 38

Jacket e Matlab - 2
Vediamo velocemente luso di Jacket con un primo esempio.
Per utilizzare Jacket dare (dalla linea comandi di MATLAB): >> addpath(/scratch/jacket/engine); Questo comando ci consente di utilizzare i files MEX presenti nella directory e corrispondenti a tutte le funzioni incluse in Jacket. Verifichiamo il nostro ambiente di lavoro: >> ginfo Jacket v0.4 (build ST67) data memory: 0mb used, 1491mb free GPU0 Quadro FX 5600, 1350 MHz, 1535mb VRAM, Capability 1.0

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 39

Jacket e Matlab - 3
>> X=gsingle(magic(3)); >> Y=gsingle(ones(3)); >> A=X*Y A= 15 15 15 15 15 15 15 15 15 >> whos Name Size Bytes Class Attributes A 3x3 496 gsingle X 3x3 496 gsingle Y 3x3 496 gsingle

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 40

Jacket e Matlab - 4
Loutput del comando whos mostra come la matrice A abbia lo stesso tipo delle matrici di input. Il calcolo (prodotto matriciale) stato effettuato, quindi, sulla GPU.
La funzione gsingle consente il cast di una matrice MATLAB in una matrice in singola precisione sulla GPU: >> A=gsingle(B); %push B to the GPU from the CPU

Per tornare indietro sulla CPU dobbiamo utilizzare la funzione builtin MATLAB double (o single): >> B=single(A); >> whos Name Size Bytes Class Attributes B 3x3 36 single

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 41

Jacket e Matlab - 5
Le tecniche per vettorizzare un codice MATLAB mostrate in precedenza sono di aiuto per avere un codice efficiente sulla GPU. Lo stesso codice avr beneficio immediato dallutilizzo di Jacket. Codice vettorizzato MATLAB: >> tic;A=(ones(5000)+eye(5000));B=sqrt(A);max(max(B)),toc ans = 1.4142 Elapsed time is 1.487942 seconds. Le funzioni gones e geye creano due strutture dati sulla GPU analoghe alle funzioni builtin MATLAB. Codice Jacket: >> tic;A=(gones(5000)+geye(5000));B=sqrt(A);max(max(B)),toc ans = 1.4142 Elapsed time is 0.029784 seconds.

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 42

Jacket e Matlab - 6
Non ce speranza di migliorare le prestazioni di un codice che esegue una serie di calcoli su variabili scalari, come quello sotto:
a=2.5;b=3.33;c=6.23; for i = 1:1000000
a=b+c; b=ac; c=b*a; if(a>b) a=bc; else b=b+12.3; end

End

I codici vanno, pertanto, vettorizzati.

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 43

Jacket e Matlab - 7
Il prossimo esempio e la versione Jacket dello script benchdgemm utilizzato per testare le prestazioni del prodoto matriciale built--in in MATLAB. Il codice utilizzato e: addpath('/scratch/jacket/engine) % Warm-up GPU a = gsingle(rand(200)); b = a; c=a*b; gforce(c); % Begin bench icont=1; for n=128:32:2560 a = gsingle(rand(n)); b = a; tic; c=a*b; gforce(c); ttt=toc; jacket(icont) = (2*n^3-n^2)/(ttt*10^9); icont = icont+1; end v=128:32:2560; plot(v,jacket); xlabel('Matrix dimension') ylabel('GFLOP/s)

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 44

Jacket e Matlab - 8
Osservazioni sullo script: Nel modello di programmazione di CUDA e possibile che il calcolo sulla GPU sia dilazionato di modo che questo venga effettuato solo quando il risultato e necessario. La funzione gforce viene utilizzata per forzare il calcolo sulla GPU. In generale puo essere utilizzata per ottimizzare un codice Jacket. E buona norma riscaldare" la GPU chiamando una prima volta la parte di codice di cui vogliamo misurare le prestazioni. Questo consentira di precaricare le librerie per poter prendere il massimo delle prestazioni dal calcolo. Mandiamo in esecuzione il codice: >> addpath('/scratch/jacket/engine'); >> benchdgemm_jacket

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 45

Jacket e Matlab - 9

Come si vede le prestazioni sono eccellenti, con cambiamenti minimi rispetto alla versione Matlab
Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 46

Laboratorio: bilateral image denoising filter con Jacket 1


Riprendiamo l'esempio di Laboratorio relativo all'algoritmo di bilateral image denoising filter e partendo dalla versione vettorizzata mostriamo il codice per GPU: B = bilateral_jacket(A,sd,sr,R); % The bilateral image denoising filter, Jacket version A=gsingle(A); % Jacket #1 B = gzeros(size(A)); % Jacket #2 zsum=gzeros(size(A)); % Jacket #3 ilast=size(A,1); jlast=size(A,2); i = 1:ilast; j = 1:jlast; for m = -R:R ipm=i+m; ip=ipm(ipm>0 & ipm<=ilast); im=i(ipm>0 & ipm<=ilast); for n = -R:R jpn=j+n; jp=jpn(jpn>0 & jpn<=jlast); jm=j(jpn>0 & jpn<=jlast); z = exp(-(A(ip,jp)-A(im,jm)).^2/(2*sd^2)) * exp(-(m^2 + n^2)/(2*sr^2)); B(im,jm) = B(im,jm) + z.*A(ip,jp); zsum(im,jm)=zsum(im,jm)+z; end end B=B./zsum; gforce(B); % Jacket #2

Scuola Estiva di Calcolo Avanzato 2008

Matlab e Cuda: 47

Laboratorio: bilateral image denoising filter con Jacket 2


Mandiamo in esecuzione il nuovo codice: >> A=single(rgb2gray(imread('susi.jpg'))); >> sd=10;sr=10;R=3; >> addpath('/scratch/jacket/engine');
>> tic;Bj=bilateral_jacket(A,sd,sr,R);toc Elapsed time is 0.102315 seconds. >> Bj=double(Bj); >> norm(Bv-Bj,2) ans = 0.0023 Il confronto rispetto alla versione vettorizzata per CPU mostra comunque un buon guadagno anche per questo codice (di un fattore 6) e una leggera degradazione della qualita dell'output che non sembra pregiudicare la bonta del risultato.

Scuola Estiva di Calcolo Avanzato 2008

Potrebbero piacerti anche