Vous êtes sur la page 1sur 34

UNIVERSIDAD NACIONAL AUTNOMA DE MXICO

FACULTAD DE CIENCIAS TTULO DE TESINA Propagacin de ondas en medios heterogneos: simulaciones y aplicaciones usando tarjetas grficas para acelerar el cmputo

QUE PARA OBTENER EL TTULO DE: LICENCIADO EN CIENCIAS DE LA COMPUTACIN

PRESENTA: TINTOR JIMNEZ PABLO ALBERTO

DIRECTORA DE TESINA: DRA. RSULA XIOMARA ITURRARN VIVEROS

2012

Hoja de Datos del Jurado


DATOS DEL ALUMNO Apellido paterno Tintor Apellido materno Jimnez Nombre(s) Pablo Alberto Telfono 55 29 05 65 51 Universidad Nacional Autnoma de Mxico Universidad Nacional Autnoma de Mxico Facultad de Ciencias Facultad de Ciencias Carrera Ciencias de la Computacin Nmero de cuenta 305248336 DATOS DEL TUTOR Grado Dra. Nombre(s) rsula Xiomara Apellido paterno Iturrarn Apellido materno Viveros DATOS DEL SINODAL 1 Grado Dr. Nombre(s) Jos David Apellido paterno Flores Apellido materno Pealoza DATOS DEL SINODAL 2 Grado Dr. Nombre(s) Pablo Apellido paterno Barrera Apellido materno Snchez DATOS DEL SINODAL 3 Grado Dr. Nombre(s) Pedro Apellido paterno Gonzlez Apellido materno Casanova DATOS DEL SINODAL 4 Grado Dr. Nombre(s) Francisco Jos Apellido paterno Snchez Apellido materno Sesma DATOS DEL TRABAJO ESCRITO

Ttulo

Nmero de pginas Ao

Propagacin de ondas en medios heterogneos: simulaciones y aplicaciones usando tarjetas grficas para acelerar el cmputo. 34p 2012

AGRADECIMIENTOS A mis padres Blanca Jimnez e Ignacio Tintor que me han apoyado incondicionalmente para alcanzar mis metas y objetivos. Que me educaron y me orientaron a llevar una vida escolar que ahora alcanza una meta importante. A la Dra. rsula Iturrarn que me permiti trabajar con ella y me orient en la realizacin de este trabajo. Muchas gracias por ayudarme a terminar esta etapa de mi vida acadmica. A toda mi familia, en especial a mis hermanas Jazmn, Azucena y Dalia por haber sido mis principales cmplices y compaeras de juegos infantiles. Y ahora por ser mis principales cmplices y compaeras de vida. A la profesora Sonia Valery por todo su apoyo profesional prestado en estos dos aos de conocerla. A J.G.B.P y Ruth, son dos personas muy especiales en mi vida. A todos los profesores con los que tuve el gusto de tomar clase y aprender de ellos, en especial a Elisa Viso y Aida Byrd que me ensearon a programar. A mis cinco sinodales Dra. rsula Iturrarn, Dr. David Flores, Dr. Pablo Barrera, Dr. Pedro Gonzlez y Dr. Francisco Snchez. A todos mis compaeros y amigos de escuela, en especial a Carlos, Daniel, Leticia, Jessica, Genaro, Guadalupe, Elizabeth con quienes compartimos trabajos, tareas y momentos muy divertidos.

NDICE Introduccin..5 Objetivo.....6 Propiedades de las GPUs.........7 Memoria de Textura........9 Eventos.........9 Solucin de la ecuacin de onda acstica10 Condiciones iniciales.11 Fronteras absorbentes......11 Condicin de Courant12 Definicin de la malla12 Programacin de la ecuacin de onda acstica...13 Animacin15 Diagrama de flujo...17 Cdigo fuente.18 Resultados..26 Conclusiones..27 Apndice A, instalacin y configuracin de CUDA29

INTRODUCCIN Una onda sonora es una onda longitudinal que transmite lo que se asocia con sonido. Si se propaga en un medio elstico y continuo genera una variacin local de presin o densidad, que se propaga en forma de onda esfrica peridica o cuasi peridica. El modelado numrico de este fenmeno fsico se ha desarrollado como un mtodo para crear modelos realistas y controlables de los instrumentos musicales. Con este propsito se han desarrollado numerosos modelos matemticos que describen el comportamiento de las ondas acsticas. Uno de ellos es el mtodo de diferencias finitas que permite aproximar y discretizar la solucin a la ecuacin de onda acstica, este mtodo consiste en un conjunto de condiciones fsicas y un sistema de actualizacin, los cuales calculan el desplazamiento de las ondas acsticas basados en los valores de los tiempos previos, ver [4]. El mtodo de diferencias finitas permite simular con gran precisin, la propagacin de ondas acsticas sobre cualquier espacio definido. Sin embargo hay dos temas importantes que tratar antes de llevar a cabo esta aproximacin. La primera es la complejidad para obtener dichos sistemas fsicos y la derivacin matemtica del sistema. El segundo es la complejidad computacional que se deriva de calcular las soluciones, esta depende del tamao de la malla que a su vez depende de la precisin que se desee, la calidad y el tamao de las imgenes. Afortunadamente la programacin paralela se ha desarrollado mucho durante los ltimos aos. En primera instancia se ha incrementado considerablemente la velocidad de procesamiento de las Unidades de Procesamiento Central por sus siglas en ingls CPUs, adicionalmente se ha incrementado la cantidad de ellas en nuestras computadoras permitiendo que a la fecha se cumpla la llamada ley de Moore [8]. Al mismo tiempo se comenz a hacer uso de las Unidades de Procesamiento Grfico GPUs para cmputo de propsito general, las cuales es sabido contienen cientos de unidades de procesamiento dotadas de un gran poder de cmputo y canales de datos con gran ancho de banda, como se puede observar en las siguientes grficas:

Fig. 1. Operaciones de punto flotante por segundo para CPU y GPU[3].

Fig. 2. Ancho de banda de los canales de datos para CPU y GPU[3].

La diferencia en la capacidad de cmputo entre las CPUs y las GPUs radica en que una GPU est diseada para realizar computo en paralelo, esto es que puede ejecutar el mismo programa sobre varias unidades de datos al mismo tiempo. El procesamiento de imgenes es una de las principales aplicaciones para las GPUs, grandes conjuntos de pixeles y vrtices pueden ser procesados por hilos de ejecucin en paralelo. En Noviembre 2006, NVIDIA introdujo en el mercado CUDATM, una plataforma de propsito general y un modelo de programacin que aprovecha los recursos del motor de computo en paralelo de las GPUs de NVIDIA, solucionando cmputos complejos de una forma ms eficiente que una CPU. CUDA fue lanzado con un ambiente de software que permite a los desarrolladores usar C como lenguaje de programacin de alto nivel, manteniendo baja la curva de aprendizaje para programadores familiarizados con este lenguaje de programacin. En su ncleo hay tres conceptos claves -- grupos de hilos jerrquicos, memoria compartida y sincronizacin -- que pueden ser vistos por el programador como una mnima extensin del lenguaje de programacin. Estos conceptos llevan al programador a dividir el problema en sub-problemas que puedan ser resueltos de manera independiente en bloques paralelos de hilos, y cada sub-problema en pequeas piezas que puedan resolverse cooperativamente en paralelo por todos los hilos dentro de un bloque. De esta manera un programa multi-hilos puede ser dividido en bloques independientes uno de otro, permitiendo aprovechar mejor las capacidades de computo de las diferentes GPUs disponibles en el mercado, es decir una GPU con ms multiprocesadores puede automticamente ejecutar el mismo programa en menor tiempo que una GPU con menos multiprocesadores.

OBJETIVO
En este trabajo exponemos las propiedades de los procesadores grficos, haciendo nfasis en la explotacin de stos mediante la tecnologa CUDA. Esta tecnologa se implementa en la solucin de la ecuacin de onda acstica por el mtodo de diferencias finitas.

PROPIEDADES DE LAS GPUS Normalmente una CPU contiene solo 2, 4, 6 o hasta 8 ncleos (ALUs Unidad Lgica Aritmtica) que comparten una memoria cache y una RAM en comn. En una PC, es posible usar memoria distribuida y modelos de comunicacin entre procesos como OpenMPI o MPI (ver sitio oficial openMPI o la documentacin de la Interfaz de Paso de Mensajes [7]), que utilizan la misma o varias memorias en una o varias computadoras. Cuando nos enfrentamos a la ejecucin de grandes y pesadas rutinas, unos cuantos ncleos por computadora no son suficientes, entonces nos damos a la tarea de unir varias para construir un clster de modo que la carga de trabajo y memoria queda distribuida sobre cada una de ellas. Las GPUs trabajan un poco diferente a las CPUs. Una GPU contiene cientos de unidades lgico-aritmticas, agrupadas en bloques que comparten una gran cantidad de memoria global, sin embargo cada uno contiene memoria local que no puede ser accedida entre bloques. Dependiendo de las necesidades del usuario las unidades lgicoaritmticas por sus siglas en ingls ALUs pueden agruparse en 1, 2 o 3 dimensiones, las imgenes 3 y 4 muestran una agrupacin en 1D y 2D.

Fig.3. Arreglo unidimensional

Fig.4. Arreglo bidimensional

Antes de programar una tarjeta grfica es conveniente conocer sus capacidades y limitaciones fsicas, adems de determinar si es la nica o existen varias de ellas en nuestro equipo de cmputo. Se puede determinar la cantidad de estos dispositivos mediante la funcin cudaGetDeviceCount. El programa completo se muestra al final de este tema.
int count; HANDLE_ERROR( cudaGetDeviceCount( &count ) );

Conocida la cantidad dispositivos dentro del sistema de cmputo, podemos iterar a travs de cada uno de ellos y conocer sus propiedades. Esta informacin se proporciona en una estructura de tipo cudaDeviceProp, las propiedades que contiene esta estructura se muestran en la tabla siguiente.
Propiedad de la GPU char name [256] size_t totalGlobalMem size_t sharedMemPerBlock int regsPerBlock Int warpSize Int size_t mem_pitch int maxThreadsPerBlock int maxThreadsDim[3] int maxGridSize[3] size_t totalConstMem int major int minor size_t textureAlignment int deviceOverlap int multiprocessorCount Int kernelExecTimeoutEnabled int integrated int canMapHostMemory int computeMode int maxTexture1D int maxTexture2D[2] int maxTexture3D[3] int maxTexture2DArray[3] int concurrentKernels Descripcin Una cadena en cdigo ASCII que identifica al dispositivo (Ej.,GeForce GTX 590). Cantidad de memoria global en el dispositivo en bytes. Cantidad mxima en bytes de memoria compartida en un solo bloque. Nmero de registros de 32-bits disponibles por bloque. Nmero de procesos por unidad de cmputo. Tamao en bytes mximo para copiar memoria. Mximo de hilos de ejecucin que un bloque puede contener. Nmero mximo de hilos que un bloque puede contener a lo largo de cada una de sus dimensiones. Mximo nmero de bloques a lo largo de cada dimensin de la malla. Cantidad de memoria constante disponible. Revisin ms a fondo de las capacidades de cmputo del dispositivo. Revisin mnima de las capacidades de cmputo del dispositivo. Requerimiento del dispositivo para el alineamiento de textura. Valor booleano para indicar que se puede realizar simultneamente una llamada a la funcin cudaMemcpy y la ejecucin del kernel. Nmero de multiprocesadores en el dispositivo. Valor booleano, indica que existe un lmite en el tiempo de ejecucin de los kernels ejecutados en el dispositivo. Valor booleano que indica si el dispositivo est integrado a la GPU. Valor booleano que indica si el dispositivo puede mapear memoria de la computadora al espacio de direcciones de CUDA. Valor que representa el modo de cmputo del dispositivo. Por defecto, exclusivo o prohibido. Cantidad mxima de memoria de textura 1D soportada. Dimensiones mximas para memoria de textura 2D soportadas. Dimensiones mximas para memoria de textura 3D soportadas. Dimensiones mximas soportadas para arreglos de memoria de textura 2D. Valor booleano que indica si en un momento determinado, el dispositivo puede ejecutar mltiples kernels dentro del mismo contexto, simultneamente.

Siendo conscientes de esta informacin podremos programar nuestras GPUs, haciendo mejor uso de sus capacidades y sin sobrepasar sus lmites. El cdigo para consultar nuestros dispositivos lucir ms o menos as:
#include "../common/book.h" int main( void ) { cudaDeviceProp prop; int count; HANDLE_ERROR( cudaGetDeviceCount( &count ) ); for (int i=0; i< count; i++) { HANDLE_ERROR( cudaGetDeviceProperties( &prop, i ) ); printf(Numero de procesos por unidad de computo: %i,prop.warpSize); // El resultado es 32 para el caso de una tarjeta GeForce GT 240 } }

Adems de conocer las capacidades de cmputo de nuestros dispositivos, debemos tomar en cuenta que existe dentro de las GPUs memoria de textura que puede ayudar a mejorar el desempeo si se le usa adecuadamente. Memoria de textura La memoria de textura es una variante de memoria de solo lectura que se aloja en la circuitera del dispositivo, esto puede ayudar a su desempeo y reducir el trnsito de datos desde la memoria global externa. Esta memoria fue diseada principalmente para aplicaciones grficas, NVIDIA diseo las unidades de textura para interactuar con los canales de OpenGL y DirectX. Especficamente fue diseada para procesos que requieren acceder continuamente a grandes espacios de memoria. En el caso de la simulacin que se lleva a cabo es necesario actualizar las imgenes ( ) accediendo continuamente a las regiones de memoria que contienen a las imgenes actual ( ) y a la anterior ( ). El acceso a dichas memorias parece ser ms eficiente cuando se alojan en la memoria de textura. En el caso de la propagacin de ondas en 2D ser necesario acceder a los nodos vecinos de la izquierda, derecha, superior e inferior, por lo que el uso de memoria de textura 2D optimiza el indexado de los nodos y por tanto el acceso es ms eficiente que con memoria de textura 1D. Memoria Compartida. La memoria compartida despus de los registros es la ms cercana a los procesos, sin embargo solo es visible durante la ejecucin de un kernel y solo por procesos del mismo bloque, adems de ser muy pequea, a pesar de tener estas desventajas no deja de ser la ms rpida, por ello es conveniente tenerla en cuenta y analizar en qu tipo de problemas es conveniente usarla. El uso de memoria compartida puede presentar problemas de sincronizacin de procesos, los cuales pueden generar incongruencia en los datos, la funcin __syncthreads() 9

sincroniza los procesos, de tal manera que antes de ejecutar la siguiente instruccin en el cdigo todos los proceso del bloque han terminado de ejecutar las instrucciones previas. Eventos Los eventos en CUDA son esencialmente marcas de tiempo del GPU. En la simulacin haremos uso de ellos para marcar el inicio y el fin del cmputo de las imgenes que se mostrarn.

10

SOLUCIN DE LA ECUACIN DE ONDA ACSTICA Sea = [0,1] [0,1], f, u0 C 0(). Hallar la funcin ecuacin de onda. C 2() que satisface la

Podemos discretizar el problema usando un esquema de diferencias finitas para dar solucin al sistema, tomando como la velocidad de propagacin de las ondas. Dividiremos las direcciones , de en puntos con resultando 1024 intervalos en cada direccin. Denotaremos = = = al delta espacial y = , ver al delta temporal. De acuerdo con esto y Laurent Michel 2011[1]. La aproximacin numrica queda de la siguiente manera:

Fig. 5. Valor del punto i,j en el tiempo anterior.

Fig. 6. Valores del punto i,j y sus vecinos en el tiempo actual.

Fig.7. Valor del punto i,j calculado en base a los tiempos anteriores.

Sustituyendo en la primera ecuacin y despejando


(

tenemos que
)

11

Donde

Que para los tiempos t=0.0, t=0.5 y t=1.0 se ve como lo muestran las siguientes figuras.

x y

x y

x y

Fig. 8. f(x,y,t) en el inicio de la simulacin. t=0.0

Fig. 9.f(x,y,t) en el tiempo medio de la simulacin t=0.5

Fig. 10.f(x,y,t) en el fin de la simulacin t=1.0

Condiciones iniciales Para las condiciones iniciales decid graficar un aro en el centro usando la funcin.
( )

Donde
x y Fig. 11. Grfica de la funcin u0 que establece las condiciones iniciales para la simulacin.

Fronteras absorbentes. En el mejor de los casos las ondas incidentes en los bordes deben ser absorbidas en su totalidad, imitando una continuidad en el espacio de propagacin, sin embargo al ser nuestra malla un espacio finito las ondas se ven reflejadas. La forma de hacer frente a este problema ser implementar una zona de absorcin como se muestra en la figura de abajo.
Espacio no absorbente Banda con celdas absorbentes

Fig. 12. Espacio finito de propagacin de las ondas, las bandas absorbentes ayudan a simular una continuidad en el espacio, segn Crjan 1986 [6].

Las barreras absorbentes presentan la siguiente funcin , donde es el ndice del nodo a partir del borde ms cercano y es el tamao de las barreras absorbentes, ver Crjan 1986[6]. 12

Condicin de Courant El mtodo de diferencias finitas tiene la dificultad de los problemas de inestabilidad. Las soluciones inestables se presentan si es relativamente grande respecto a . La relacin a cumplir entre estos dos parmetros se conoce como la condicin de Courant.

donde

es la velocidad de propagacin de las ondas. por tanto cumple la

En el caso de esta simulacin condicin de Courant. Definicin de la malla

Para esta simulacin he definido una imagen de tamao 1024 x 1024, la cual ser dividida en 64 bloques con 16 procesos cada uno, que sern responsables de una regin de memoria representada por los puntos negros de la siguiente imagen.

Fig. 13. Agrupacin de los procesos paralelos en los bloques de memoria definidos.

13

PROGRAMACIN DE LA ECUACIN DE ONDA ACSTICA En el cdigo utilizado para el censo de los dispositivos del sistema, podemos observar que la sintaxis CUDA no es muy diferente a la del lenguaje C. El uso de variables, constantes, estructuras, sentencias de control de flujo, uso de bibliotecas, entre otras cosas es muy similar en ambos lenguajes, tal como podremos apreciar a continuacin. La documentacin completa de CUDA se puede consultar en la pgina oficial de NVIDIA [3].
#include "../common/book.h" #include "../common/gpu_anim.h" /*DEFINIMOS EL NMERO DE THREADS Y EL NMERO DE BLOQUES PARA NUESTROS KERNELS **RESPETANDO: n_blocks = DIM / n_threads */ #define _nthreads 16 #define _nblocks 64 #define DIM 1024 /* ** ** ** ** */

N = DIM-1: h = 1.0/N: tf: Tiempo dt = h/2.0

Tamao de la malla Delta espacial final : Delta temporal

#define #define #define #define

N 1023 h 1.0f/(float)N tf 1.0f dt h/2.0f

float t=0; //Tiempo

El cdigo hasta aqu mostrado es ejecutado en la CPU y su memoria. Segn la documentacin de CUDA, un kernel es cdigo compilado para ser ejecutado simultneamente en los microprocesadores de la GPU, aplicar la misma instruccin sobre secciones de memoria diferentes. Veamos el kernel que calcula .
__global__ void evolve(float *n, float t, int step) { //Cdigo que se ejecuta en GPU } //...Cdigo evolve<<<blocks, threads>>>(data->dev_uNext,t,0); //...Cdigo

La firma de este mtodo no es muy diferente a uno escrito en lenguaje C, pero podemos notar una importante alteracin que es el calificador __global__. Este mecanismo alerta al compilador para que el mtodo sea compilado para ser ejecutado en la GPU. El paso de parmetros a estas funciones se asemeja a la manera del lenguaje C. Sin embargo en la invocacin de un kernel con la sintaxis <<<m , n>>>, indicamos que 14

ejecutaremos el programa dividiendo la seccin de memoria original en m bloques y que cada uno contendr n procesos paralelos trabajando cooperativamente, teniendo cuidado de no sobrepasar los lmites fsicos de nuestro dispositivo. Ver Fig. 4 Arreglo bidimensional. La memoria global, es el tipo de memoria de uso ms general con la que cuenta una GPU. Al igual que reservamos la memoria RAM de un CPU para los arreglos de un programa escrito en C, podemos reservar memoria global para la ejecucin de un kernel con la funcin cudaMalloc. Veamos un ejemplo de su uso.
HANDLE_ERROR( cudaMalloc( (void**)&data.dev_uOld,1024*1024*sizeof(float) ) );

En este ejemplo con la funcin cudaMalloc alojamos dentro de la memoria del dispositivo, el vector que guardar los valores de a lo largo del programa. Tambin haremos uso de la memoria de textura para mejorar el desempeo de nuestro dispositivo. Veamos un ejemplo del uso de esta memoria.
//Cdigo texture<float,2> //Cdigo HANDLE_ERROR( cudaBindTexture2D( NULL, texOld,data.dev_uOld,desc,DIM,DIM,DIM*sizeof(float)) ); //Cdigo oidx = tex2D(texOld,i,j); texOld; //Memoria de textura para u^n-1

En este ejemplo declaramos texOld, un bloque de memoria de textura 2D. Despus inicializamos este bloque y creamos la conexin con el bloque de memoria global dev_uOld, mediante la funcin cudaBindTexture2D. Finalmente leemos datos de ella con la funcin tex2D. He descrito y ejemplificado la sintaxis que usaremos en los clculos de esta modelacin, entonces podemos describir las funciones y utilidades que CUDA ofrece para realizar los grficos y la animacin de este trabajo, basado en las APIs del libro CUDA BY EXAMPLE [2]. Aunque existen otras plataformas para visualizar los resultados como Matlab, gnuplot, dislin, etc. CUDA hace este trabajo ms eficiente y dinmico utilizando los recursos de la GPU, evitando la transferencia de datos entre CPU y GPU.

15

Animacin Teniendo en cuenta las dimensiones de nuestra malla, primero definimos un cuadro que graficar los mapas de bits correspondientes a las imgenes calculadas por cada paso de tiempo durante la simulacin.
GPUAnimBitmap bitmap( DIM, DIM, &data );//creamos una imagen de tamao DIM*DIM

La funcin anim_gpu es llamada por el cuadro de animacin cada vez que se muestra una nueva imagen, anim_exit es llamada al final de la animacin para liberar los recursos utilizados y anim_and_exit llama a estas dos rutinas para realizar la animacin.
bitmap.anim_and_exit( (void (*)(uchar4*,void*,int))anim_gpu,(void (*)(void*))anim_exit );

Los argumentos de esta funcin son: un apuntador a una estructura DataBlock y un entero ticks que cuenta las imgenes transcurridas, debido a que DataBlock contiene los clculos de , , en sus respectivos arreglos, el parmetro ticks no es utilizado.
void anim_gpu( uchar4* outputBitmap, DataBlock *data, int ticks ) { //Cdigo de animacin }

Ya que usamos memoria de textura, no podemos pasar parmetros que requieran grandes cantidades de memoria, por ello alternamos , , tres veces de manera que al terminar cada una retome su lugar, indicamos esta alternancia con un numero 0,1,2 al mtodo evolve que lleva a cabo el cmputo de la propagacin. Incrementamos la variable t despus de cada ejecucin del kernel evolve.
if(paso==0){ evolve<<<blocks, threads>>>(data->dev_uNext,t,0,ticks); in=data->dev_uNext; incrementDT(); } if(paso==1){ evolve<<<blocks, threads>>>(data->dev_uOld,t,1,ticks); in=data->dev_uOld; incrementDT(); } if(paso==2){ evolve<<<blocks, threads>>>(data->dev_uCurr,t,2,ticks); in=data->dev_uCurr; incrementDT(); } paso++;

Al llegar a la frontera las ondas rebotan, para evitarlo lanzamos el kernel siguiente:
frontera<<<blocks, threads>>>(in,20,20,0.035);

16

La funcin up_Color permite tener colores llamativos sin afectar el cmputo de la propagacin, la funcin float_to_color mapea valores de punto flotante en pixeles de color susceptibles de graficar y la funcin sleepP retarda la simulacin.
upColor<<<blocks, threads>>>(data->dev_color,in); float_to_color<<<blocks,threads>>>(outputBitmap,data->dev_color); sleepP(10000);

Elemento de animacin
GPUAnimBitmap bitmap DataBlock data

anim_gpu

anim_exit

anim_and_exit

Descripcin Estructura CUDA que define el cuadro de animacin y sus funciones. Estructura definida por el usuario utilizada por el GPUAnimBitmap para guardar los buffers de lectura y escritura de datos para la animacin, adems de variables particulares de la animacin. Rutina de animacin definida por el usuario es llamada cada vez que se calcula una nueva imagen. Rutina de liberacin de recursos, una vez que se termina la animacin ser necesario liberar los buffers y las variables de animacin. Funcin para llamar a las dos rutinas anteriores, anim_gpu y anim_and_exit.

Esta fue la forma de graficar y animar la propagacin de ondas acsticas. En las siguientes pginas se muestran un diagrama de flujo y el cdigo fuente de este programa.

17

Diagrama de flujo de la operacin del programa presentado.

18

Cdigo fuente
#include #include #include #include "../common/book.h" "../common/gpu_anim.h" <stdio.h> <stdlib.h>

/*DEFINIMOS EL NUMERO DE THREADS Y EL NUMERO DE BLOQUES PARA NUESTROS KERNELS **RESPETANDO: n_blocks = DIM / n_threads */ #define DIM 1024 #define _nthreads 16 #define _nblocks (DIM/_nthreads)

/* ** ** ** ** */

N = DIM-1: h = 1.0/N: tf: Tiempo dt = h/2.0

Tamao de la malla Delta espacial final : Delta temporal

#define #define #define #define

N (DIM-1) h (1.0f/(float)N) tf 1.0f dt (h/2.0f) texOld; //Memoria de textura para u^n-1 texCurr;//Memoria de textura para u^n texNext;//Memoria de textura para u^n+1

texture<float,2> texture<float,2> texture<float,2>

float t=0; //Tiempo int paso=0; /* *Estructura DataBlock usada para *guardar datos para realizar la animacin */ struct DataBlock { float *dev_uOld; float *dev_uCurr; float *dev_uNext; float *host_uOld; float *host_uCurr; float *host_uNext; float *dev_color; cudaEvent_t start, stop; float totalTime; float frames; };

19

/*Funcin f(ih,ij,ndt) ** x = i*h ** y = j*h ** t = n*dt **/ __device__ float f(float *x, float *y, float *t) { return expf(-*t)*(*x*(*x-1.0f)**y*(*y-1.0f) - 2.0f*(*y*(*y-1.0f)+*x*(*x-1.0f))); } /*Funcin equivalente a f(ih,ij,ndt) pero ejecutada en el host ** x = i*h ** y = j*h ** t = n*dt **/ float g(float *x, float *y, float *t) { return expf(-*t)*(*x*(*x-1.0f)**y*(*y-1.0f) - 2.0f*(*y*(*y-1.0f)+*x*(*x-1.0f))); }

/*Mtodo para convertir un arreglo de tipo float en un arreglo de tipo uchar4 **con las escalas de grises equivalentes, susceptible de graficar. **uchar4 *in arreglo donde se guarda el mapeo float-escala de grises **float *ou arreglo original para realizar el mapeo float-escala de grises */ __global__ void float_to_grey(uchar4* in,float* ou){ // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; int idx = x + y * blockDim.x * gridDim.x; if(idx > DIM*DIM) return; in[idx].x=(1.0f-ou[idx])*255; in[idx].y=(1.0f-ou[idx])*255; in[idx].z=(1.0f-ou[idx])*255; in[idx].w=255; }

20

/*Mtodo para establecer las condiciones iniciales. **Estable la fuerza que inicia la propagacin de las ondas. **Es un aro blanco en el centro. **float u arreglo en el que se guardan las condiciones iniciales */ __global__ void init(float *u){ // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; int idx = x + y * blockDim.x * gridDim.x; if(idx > DIM*DIM) return; //movemos el origen de coordenadas al centro de la imagen float fx = x - DIM/2; float fy = y - DIM/2; float d = sqrt(fx * fx + fy * fy); float grey = cos(d/10.0f - 100.0f/7.0f) /(d/10.0f + 1.0f); //grey=fx*(fx-1)+fy*(fy-1); u[idx]=grey; if(u[idx]<0.20f)u[idx]=0.0f;//Eliminamos puntos basura. else u[idx]=1.0f;//Subimos el color de los puntos importantes al mximo. } /*Mtodo para subir el color de las ondas **float *color arreglo modificado **float *in arreglo original */ __global__ void upColor(float *color, float *in){ // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; int idx = x + y * blockDim.x * gridDim.x; if(idx > DIM*DIM) return; float px=2.0f*in[idx];//Subimos el color de los puntos. if(px>1.0f)px=1.0f; color[idx]=px; } /*Mtodo para incrementar el tiempo */ bool incrementDT() { float tmp = t+dt; if(tmp < tf) { t=tmp; return false; } return true; }

21

//Mtodo para contener las ondas, al llegar a las mallas //de contencin las ondas se debilitan __global__ void frontera(float *in, int nxa,int nya,float a){ // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int x = threadIdx.x + blockIdx.x * blockDim.x; int y = threadIdx.y + blockIdx.y * blockDim.y; int idx = x + y * blockDim.x * gridDim.x; if(idx > DIM*DIM) return; float c=1.0f; if(x<nxa) c=expf(-((a*(nxa-x))*((nxa-x)))); if(y<nya) c=expf(-((a*(nya-y))*((nya-y)))); if(x>DIM-nxa+1) c=expf(-((a*(x-DIM+nxa-1))*((x-DIM+nxa-1)))); if(y>DIM-nya+1) c=expf(-((a*(y-DIM+nya-1))*((y-DIM+nya-1)))); in[idx]=c*in[idx]; } /* *Mtodo para calcular la propagacin de onda acstica secuencialmente */ void evolve_s(float *old, float *curr, float *next, float t) { //Inicia uso de apuntadores float g(float *,float *, float*); float ih; float jh; float *pih; float *pjh; float *pt; float oidx,cidx,cleft,cright,cbottom,ctop; //Termina uso de apuntadores for(int i=0;i<(DIM*DIM);i++){ int x = i % DIM; int y = i / DIM; if(x==0||x==(DIM-1)||y==0||y==(DIM-1)){ next[i]=0; } else{ oidx = old[i]; cidx = curr[i]; cleft = curr[i-1]; cright = curr[i+1]; cbottom = curr[i+DIM]; ctop = curr[i-DIM]; //Diferencias finitas pih=&ih; pjh=&jh; pt=&t; ih=h*x; jh=h*y; next[i]= -oidx + 2*cidx + (dt*dt)*(N*N*(cleft + cright + cbottom + ctop- 4 * cidx)+g(pih, pjh, pt)); } } }

22

/* *Mtodo para calcular la propagacin de onda acstica haciendo uso *de memoria global. */ __global__ void evolve_gm(float *old, float *curr, float *next, float t) { // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int i = threadIdx.x + blockIdx.x*blockDim.x; int j = threadIdx.y + blockIdx.y*blockDim.y; int idx = i + j*blockDim.x*gridDim.x; if(idx > DIM*DIM) return; //Puntos en la frontera if(i==0 || i == DIM-1 || j==0 || j == DIM-1) { next[idx] = 0.0f; return; } //Inicia uso de punteros float f(float *,float *, float*); float ih=i*h; float jh=j*h; float *pih; float *pjh; float *pt; pih=&ih; pjh=&jh; pt=&t; //Termina uso de apuntadores

float oidx,cidx,cleft,cright,cbottom,ctop;

oidx = old[idx];

cidx = curr[idx]; cleft = curr[idx-1]; cright = curr[idx+1]; cbottom = curr[idx+DIM]; ctop = curr[idx-DIM]; //Diferencias finitas next[idx]= -oidx + 2*cidx + (dt*dt)*(N*N*(cleft + cright + cbottom + ctop- 4 * cidx)+f(pih, pjh, pt)); }

23

/*Mtodo principal, aqu se calcula u^n+1 con memoria compartida **float *n arreglo en el que guardaremos el clculo de u^n+1 **t tiempo actual transcurrido del inicio de propagacin n*dt **step u^n-1,u^n,u^n+1 se alternan de acuerdo a este parmetro */ __global__ void evolve_sh(float *n, float t,int step,int ticks) { // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int i = threadIdx.x + blockIdx.x*blockDim.x; int j = threadIdx.y + blockIdx.y*blockDim.y; int idx = i + j*blockDim.x*gridDim.x; if(idx > DIM*DIM) return; __shared__ float sh_old[_nthreads][_nthreads]; __shared__ float sh_curr[_nthreads][_nthreads]; __shared__ float sh_next[_nthreads][_nthreads]; if(threadIdx.x==_nthreads-1){ sh_old[threadIdx.x+2][threadIdx.y]=tex2D(texOld,i+1,j); sh_curr[threadIdx.x+2][threadIdx.y]=tex2D(texCurr,i+1,j); sh_next[threadIdx.x+2][threadIdx.y]=tex2D(texNext,i+1,j); } if(threadIdx.y==_nthreads-1){ sh_old[threadIdx.x][threadIdx.y+2]=tex2D(texOld,i,j+1); sh_curr[threadIdx.x][threadIdx.y+2]=tex2D(texCurr,i,j+1); sh_next[threadIdx.x][threadIdx.y+2]=tex2D(texNext,i,j+1); } if(threadIdx.x==0){ sh_old[threadIdx.x][threadIdx.y]=tex2D(texOld,i-1,j); sh_curr[threadIdx.x][threadIdx.y]=tex2D(texCurr,i-1,j); sh_next[threadIdx.x][threadIdx.y]=tex2D(texNext,i-1,j); } if(threadIdx.y==0){ sh_old[threadIdx.x][threadIdx.y]=tex2D(texOld,i,j-1); sh_curr[threadIdx.x][threadIdx.y]=tex2D(texCurr,i,j-1); sh_next[threadIdx.x][threadIdx.y]=tex2D(texNext,i,j-1); }

sh_old[threadIdx.x+1][threadIdx.y+1]=tex2D(texOld,i,j); sh_curr[threadIdx.x+1][threadIdx.y+1]=tex2D(texCurr,i,j); sh_next[threadIdx.x+1][threadIdx.y+1]=tex2D(texNext,i,j); __syncthreads(); //Puntos en la frontera if(i==0 || i == DIM-1 || j==0 || j == DIM-1) { n[idx] = 0.0f; return; }

24

//Obtenemos los datos de la memoria de textura float oidx,cidx,cleft,cright,cbottom,ctop; if(step==0){ oidx = sh_old[threadIdx.x+1][threadIdx.y+1]; cidx = sh_curr[threadIdx.x+1][threadIdx.y+1]; cleft = sh_curr[threadIdx.x][threadIdx.y+1]; cright = sh_curr[threadIdx.x+2][threadIdx.y+1]; cbottom = sh_curr[threadIdx.x+1][threadIdx.y+2]; ctop = sh_curr[threadIdx.x+1][threadIdx.y]; } if(step==1){ oidx = sh_curr[threadIdx.x+1][threadIdx.y+1]; cidx = sh_next[threadIdx.x+1][threadIdx.y+1]; cleft = sh_next[threadIdx.x][threadIdx.y+1]; cright = sh_next[threadIdx.x+2][threadIdx.y+1]; cbottom = sh_next[threadIdx.x+1][threadIdx.y+2]; ctop = sh_next[threadIdx.x+1][threadIdx.y]; } if(step==2){ oidx = sh_next[threadIdx.x+1][threadIdx.y+1]; cidx = sh_old[threadIdx.x+1][threadIdx.y+1]; cleft = sh_old[threadIdx.x][threadIdx.y+1]; cright = sh_old[threadIdx.x+2][threadIdx.y+1]; cbottom = sh_old[threadIdx.x+1][threadIdx.y+2]; ctop = sh_old[threadIdx.x+1][threadIdx.y]; } __syncthreads(); //Inicia uso de punteros float f(float *,float *, float*); float ih=i*h; float jh=j*h; float *pih; float *pjh; float *pt; pih=&ih; pjh=&jh; pt=&t; //Termina uso de punteros //Diferencias finitas n[idx]= -oidx + 2*cidx + (dt*dt)*(N*N*(cleft + cright + cbottom + ctop- 4 * cidx)+f(pih, pjh, pt)); }

25

/*Mtodo principal, aqu se calcula u^n+1 **float *n arreglo en el que guardaremos el clculo de u^n+1 **t tiempo actual transcurrido del inicio de propagacin n*dt **step u^n-1,u^n,u^n+1 se alternan de acuerdo a este parmetro */ __global__ void evolve(float *n, float t,int step,int ticks) { // mapeo de threadIdx/BlockIdx a coordenas x,y de los pixeles int i = threadIdx.x + blockIdx.x*blockDim.x; int j = threadIdx.y + blockIdx.y*blockDim.y; int idx = i + j*blockDim.x*gridDim.x; if(idx > DIM*DIM) return; //Puntos en la frontera if(i==0 || i == DIM-1 || j==0 || j == DIM-1) { n[idx] = 0.0f; return; } //Obtenemos los datos de la memoria de textura float oidx,cidx,cleft,cright,cbottom,ctop; if(step==0){ oidx = tex2D(texOld,i,j); cidx = tex2D(texCurr,i,j); cleft = tex2D(texCurr,i-1,j); cright = tex2D(texCurr,i+1,j); cbottom = tex2D(texCurr,i,j-1); ctop = tex2D(texCurr,i,j+1); } if(step==1){ oidx = tex2D(texCurr,i,j); cidx = tex2D(texNext,i,j); cleft = tex2D(texNext,i-1,j); cright = tex2D(texNext,i+1,j); cbottom = tex2D(texNext,i,j-1); ctop = tex2D(texNext,i,j+1); } if(step==2){ oidx = tex2D(texNext,i,j); cidx = tex2D(texOld,i,j); cleft = tex2D(texOld,i-1,j); cright = tex2D(texOld,i+1,j); cbottom = tex2D(texOld,i,j-1); ctop = tex2D(texOld,i,j+1); } //Inicia uso de punteros float f(float *,float *, float*); float ih=i*h; float jh=j*h; float *pih; float *pjh; float *pt; pih=&ih; pjh=&jh; pt=&t; //Termina uso de punteros //Diferencias finitas n[idx]= -oidx + 2*cidx + (dt*dt)*(N*N*(cleft + cright + cbottom + ctop- 4 * cidx)+f(pih, pjh, pt)); }

26

//Mtodo para retrasar la simulacin void sleepP(unsigned int mseconds) { clock_t goal = mseconds + clock(); while (goal > clock()); } //Rutina de para graficar y animar los cmputos void anim_gpu( uchar4* outputBitmap, DataBlock *data, int ticks ) { //if(t==0.0f)system("pause"); HANDLE_ERROR( cudaEventRecord( data->start, 0 ) ); dim3 blocks(_nblocks, _nblocks); dim3 threads(_nthreads, _nthreads); float *in; paso=paso%3; //lanzamos el kernel evolve para calcular u^n+1 if(paso==0){ evolve<<<blocks, threads>>>(data->dev_uNext,t,0,ticks); //evolve_gm<<<blocks, threads>>>(data->dev_uOld,data->dev_uCurr,data->dev_uNext,t); //evolve_s(data->host_uOld,data->host_uCurr,data->host_uNext,t); //HANDLE_ERROR( cudaMemcpy( data->dev_uNext, data>host_uNext,DIM*DIM*sizeof(float),cudaMemcpyHostToDevice ) ); in=data->dev_uNext; incrementDT(); } if(paso==1){ evolve<<<blocks, threads>>>(data->dev_uOld,t,1,ticks); //evolve_gm<<<blocks, threads>>>(data->dev_uCurr,data->dev_uNext,data->dev_uOld,t); //evolve_s(data->host_uCurr,data->host_uNext,data->host_uOld,t); //HANDLE_ERROR( cudaMemcpy( data->dev_uOld, data>host_uOld,DIM*DIM*sizeof(float),cudaMemcpyHostToDevice ) ); in=data->dev_uOld; incrementDT(); } if(paso==2){ evolve<<<blocks, threads>>>(data->dev_uCurr,t,2,ticks); //evolve_gm<<<blocks, threads>>>(data->dev_uNext,data->dev_uOld,data->dev_uCurr,t); //evolve_s(data->host_uNext,data->host_uOld,data->host_uCurr,t); //HANDLE_ERROR( cudaMemcpy( data->dev_uCurr, data>host_uCurr,DIM*DIM*sizeof(float),cudaMemcpyHostToDevice ) ); in=data->dev_uCurr; incrementDT(); } paso++; //Debilitamos las ondas que estan en la frontera frontera<<<blocks, threads>>>(in,10,10,0.015f); //Subimos el color de las ondas upColor<<<blocks, threads>>>(data->dev_color,in); //Convertimos valores float en pixeles de color float_to_color<<<blocks,threads>>>(outputBitmap,data->dev_color); HANDLE_ERROR(cudaEventRecord( data->stop, 0 ) ); HANDLE_ERROR( cudaEventSynchronize( data->stop ) ); float elapsedTime; HANDLE_ERROR( cudaEventElapsedTime( &elapsedTime,data->start, data->stop ) ); data->totalTime += elapsedTime; ++data->frames; printf( "Average Time per frame: %3.12f ms\n",data->totalTime/data->frames ); //Retrasamos la animacin sleepP(10000); }

27

//Rutina para liberar recursos void anim_exit( DataBlock *data ) { HANDLE_ERROR( cudaUnbindTexture( texOld ) ); HANDLE_ERROR( cudaUnbindTexture( texCurr ) ); HANDLE_ERROR( cudaUnbindTexture( texNext ) ); HANDLE_ERROR( cudaFree( data->dev_uOld) ); HANDLE_ERROR( cudaFree( data->dev_uCurr ) ); HANDLE_ERROR( cudaFree( data->dev_uNext ) ); HANDLE_ERROR( cudaEventDestroy( data->start ) ); HANDLE_ERROR( cudaEventDestroy( data->stop ) ); }

int main (int argc, char *argv[]) { DataBlock data; //Estructura usada por anim_gpu GPUAnimBitmap bitmap( DIM, DIM, &data );//creamos una imagen de tamao DIM*DIM data.totalTime = 0; data.frames = 0; HANDLE_ERROR( cudaEventCreate( &data.start ) ); HANDLE_ERROR( cudaEventCreate( &data.stop ) ); int imageSize = bitmap.image_size(); //Asignamos memoria global HANDLE_ERROR( cudaMalloc( (void**)&data.dev_uOld,DIM*DIM*sizeof(float) ) ); HANDLE_ERROR( cudaMalloc( (void**)&data.dev_uCurr,DIM*DIM*sizeof(float) ) ); HANDLE_ERROR( cudaMalloc( (void**)&data.dev_uNext,DIM*DIM*sizeof(float) ) ); HANDLE_ERROR( cudaMalloc( (void**)&data.dev_color,DIM*DIM*sizeof(float) ) );

//Ligamos la memoria de textura a la memoria glogal cudaChannelFormatDesc desc = cudaCreateChannelDesc<float>(); HANDLE_ERROR( cudaBindTexture2D( NULL, texOld,data.dev_uOld,desc,DIM,DIM,DIM*sizeof(float)) ); HANDLE_ERROR( cudaBindTexture2D( NULL, texCurr,data.dev_uCurr,desc,DIM,DIM,DIM*sizeof(float) ) ); HANDLE_ERROR( cudaBindTexture2D( NULL, texNext,data.dev_uNext,desc,DIM,DIM,DIM*sizeof(float) ) ); //Asignamos memoria RAM data.host_uOld = (float*)malloc( DIM*DIM*sizeof(float)); data.host_uCurr = (float*)malloc( DIM*DIM*sizeof(float)); data.host_uNext = (float*)malloc( DIM*DIM*sizeof(float)); //Inicializamos//

dim3 threads(_nthreads,_nthreads); dim3 blocks(_nblocks,_nblocks); //Establecemos condiciones iniciales init<<<blocks, threads>>>(data.dev_uOld); init<<<blocks, threads>>>(data.dev_uCurr); HANDLE_ERROR( cudaMemcpy( data.host_uCurr, data.dev_uCurr,DIM*DIM*sizeof(float),cudaMemcpyDeviceToHost ) ); HANDLE_ERROR( cudaMemcpy( data.host_uOld, data.dev_uOld,DIM*DIM*sizeof(float),cudaMemcpyDeviceToHost ) ); //Llamamos a la rutina de animacin bitmap.anim_and_exit( (void (*)(uchar4*,void*,int))anim_gpu,(void (*)(void*))anim_exit ); return 0; }

28

RESULTADOS El objetivo principal de este trabajo fue hacer uso de las propiedades de una GPU para acelerar el cmputo de la propagacin de ondas acsticas en un sistema 2D. El cmputo de esta simulacin fue realizado en una GPU GeForce GT240 (modificar las constantes n_threads y n_blocks, si se cuenta con un dispositivo de mayores capacidades). A continuacin se muestran los tiempos de cmputo obtenidos para los tres algoritmos: evolve hace uso de la GPU y memoria de textura, evolve_gm hace uso de la GPU y memoria global, evolve_s hace uso de una CPU (AMDFx-4100 Quad-Core Processor) y su memoria RAM. Tamao de imagen evolve GPU + Mem. Textura 0.03 0.07 0.18 0.58 2.17 8.52 Tiempo de clculo en milisegundos evolve_gm GPU + Mem. Global 0.03 0.08 0.19 0.65 2.42 9.62 evolve_sh GPU + Mem. Compartida 0.04 0.10 0.29 0.99 3.81 15.14 evolve_s CPU + RAM 1.04 5.37 21.62 84.5 335.75 1342.81

64 x 64 px 128 x 128 px 256 x 256 px 512 x 512 px 1024 x 1204 px 2048 x 2048 px

Fig. 14. Tiempos de cmputo de los algoritmos para diferentes tamaos de imagen. El tiempo es en milisegundos por imagen.

La siguiente grfica muestra la superioridad de cmputo de una GPU sobre una CPU para diferentes tamaos de imagen.

Comparacin de Tiempos de Clculo


10000 1000 100 10 1 0.1 0.01 64 128 256 512 1024 2048 GPU + Mem Textura GPU + Mem Global GPU + Mem Compartida CPU + RAM

Fig. 15. Grfica de comparacin de tiempos de cmputo para los algoritmos definidos.

29

La superioridad de cmputo en paralelo de una GPU sobre una CPU queda comprobada en los resultados anteriores, una GPU (GeForce GT240) requiere el 2.88% del tiempo requerido por una CPU (AMDFx-4100 Quad-Core Processor) para procesar imgenes de 64x64 px, mientras que para imgenes de 2048x2048 px el tiempo requerido por la GPU es el 0.63% del tiempo requerido por la CPU. A continuacin se muestran los resultados arrojados por la herramienta de grficos.

t = 0.00978

t = 0.005865

t = 0.011730

t =0.020039

t=0.038612

t = 0.074780

t = 0.112903

t = 0.173020

t = 0.320137

t = 0.478983

t = 0.521994

Fig. 15. Imgenes en diferentes momentos de la simulacin.

CONCLUSIONES La velocidad de cmputo en paralelo de una GPU tiene mayor potencial sobre implementaciones hechas en Matlab o C. Conforme los ambientes de programacin en CUDA vayan progresando, ser ms fcil programar cdigo ejecutable en tarjetas grficas que utilicen de manera eficiente los recursos que ofrecen. Permitindonos realizar cmputos extensos, en el mejor de los casos sin interactuar con los recursos del sistema que las alberga, o en un caso menos ideal disminuyendo el uso de los mismos, liberndolos para la realizacin de otras tareas, tal como se hizo en esta simulacin.

30

El uso de memoria de textura facilita el acceso a los datos a las unidades de procesamiento de las GPUs, mejorando su desempeo en la realizacin de los clculos, ya que se encuentra integrada en la circuitera del dispositivo, disminuye el trnsito de los datos a diferencia de la memoria global que es externa. Hacer uso de ella es una tarea sencilla con la funcin cudaBindTexture2D para ligarla a la memoria global y tex2D para leer datos de ella. En el caso de la presente simulacin la diferencia no es muy notoria sin embargo si hubo una mejora al desempeo de la GPU. El procesamiento en paralelo de las GPUs es la principal aceleracin de los cmputos y el motivo principal de trabajar con ellas, ya que dividimos el rea de trabajo en bloques y en cada uno de estos ejecutamos cierta cantidad de procesos que trabajan al mismo tiempo y cooperativamente. Utilizar esta tcnica para definir una malla bidimensional sobre secciones de memoria unidimensionales, conlleva a realizar un mapeo de ndices a coordenadas (x,y), afortunadamente CUDA cuenta con los mecanismos necesarios para facilitar esta tarea. El modelado de la propagacin de ondas acsticas por el mtodo de diferencias finitas presenta problemas de discretizacin y de recursos finitos, por ello fue importante hacer uso de la condicin de Courant e implementar barreras absorbentes en los bordes.

31

APENDICE A

INSTALACIN Y CONFIGURACIN DE CUDA Este manual fue probado en una PC con sistema operativo Ubuntu 10.10.
1. Verificar la lista de GPUs compatibles con CUDA. https://developer.nvidia.com/cuda-gpus 2. Descargar los drivers de nuestra tarjeta grfica desde: http://la.nvidia.com/Download/index.aspx

3. Limpiar todo lo referente a NVIDIA y apagar el X server, para no generar conflictos. aptitude remove nvidia* aptitude purge xserver-xorg-video-nouveau /etc/init.d/lightdm stop Nota: Si no se tiene instalado aptitude ejecutar. sudo apt-get install aptitude 4. Dar permisos de ejecucin y ejecutar el instalador de drivers. chmod +x NVIDIA-Linux-x86-304.64.run ./NVIIDIA-Linux-x86-304.64.run 5. Descargar CUDA Toolkit y SDK de: 32

https://developer.nvidia.com/cuda-toolkit-archive 6. Dar permisos de ejecucin y ejecutar el instalador de CUDA Toolkit. chmod +x cudatoolkit_4.2.9_linux32_ubuntu11.04.run ./cudatoolkit_4.2.9_linux32_ubuntu11.04.run 7. Terminada la instalacin, procedemos a configurar el Path. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${CUDA}/lib:${CUDA}/lib64 export PATH=PATH:{cuda}/bin 8. Dar permisos de ejecucin y ejecutar el instalador de SDK. chmod +x gpucomputingsdk_4.2.9_linux.run ./ gpucomputingsdk_4.2.9_linux.run Durante el proceso el instalador preguntar si se desea instalar los complementos, Aceptar la instalacin de ellos. libgl1-mesa-dev libglu1-mesa-dev libxmu-dev freeglut3-dev libxi-dev 9. Tan pronto est listo, moverse a la carpeta donde se instalaron los programas y ejecutamos los comandos: cd C Para entrar a la carpeta que contiene los cdigos de ejemplo. make Para compilar los ejemplos del SDK.

Nota: Este manual muestra la forma de instalacin que se realiz en el ao 2010 para la computadora donde se desarroll el presente trabajo, la cual cuenta con un Sistema Operativo Ubuntu 10.10. Para versiones ms recientes del instalador, as como los manuales de instalacin para otros sistemas operativos se recomienda la siguiente pgina del sitio oficial de NVIDIA. https://developer.nvidia.com/cuda-downloads

33

REFERENCIAS [1] Laurent Michel. Solving a wave equation with CUDA. Technical report. May 2011. http://sma.epfl.ch/~lmichel/cuda_report.pdf [2] Jason Sanders, Edward Kandrot. CUDA by Example, An introduction to generalpurpose GPU programming. Addison-Wesley. July 2010. [3]NVIDIA Corporation. CUDA C Programming Guide. http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html October 2012.

[4] Randall J. LeVeque. Finite Difference Method for Ordinary and Partial Differential Equation. SIAM. July 2007. [5] Alfredo Ghisays Ruiz, Carlos Alberto Vargas J, Luis Alfredo Montes Vides. Mtodo hbrido de fronteras no reflectivas en lmites de modelos ssmicos. 2006. [6] Cerjan, C., D. Kosloff, R. Kosloff, and M. Reshef. A non-reflecting boundary condition for direct acoustic and elastic wave equations. Geophysics, 50, 705 708. 1985. [7] http://www.open-mpi.org http://www.mpi-forum.org/docs [8] http://www.intel.com/cd/corporate/techtrends/emea/spa/209840.htm

34