lunes, 24 de marzo de 2008

enREDando

Una vez mirado un poco de Cg y viendo por donde van los tiros, decidi ir probando cosas de la red.

La idea es que un ordenador pueda mandar trabajos en red a varios, para realizar un trabajo en paralelo que procesara la grafica.

Lo primero es poder comunicar dos ordenadores, para eso usaremos SDL_Net y el protocolo TCP. Mas adelante se puede mirar si con UDP la mejora de velocidad compensa el trabajo extra (comprobar perdidas, desorden, etc...).

Tras iniciar SDL, las funciones que usaremos para esto son las siguientes:

- SDLNet_ResolveHost(&ip,host,port) := dado un host (ip o nombre de maquina) y un puerto, nos rellena la variable ip de tipo IPaddress. Usaremos ip para abrir los sockets. Si host es igual a NULL, se entiende que es un socket de servidor y es la maquina local.

- SDLNet_TCP_GetPeerAddress(socket) := dado un socket, devuelve una variable de tipo IPaddress con la informacion del socket.

- SDLNet_TCP_Open(&ip) := nos devuelve un socket "enganchado" a esa ip.

- SDLNet_TCP_Accept(socket) := pone el socket de servidor en modo escucha y devuelve el socket que se intenta conectar a el.

- SDLNet_TCP_Send(socket,message,len) := envia por sock, una cantidad igual de caracteres a len, del buffer message.

- SDLNet_TCP_Recv(socket,message,len) := lee de socket tantos caracteres como len (si los hay) y los guarda en el buffer message.

- SDLNet_TCP_Close(sock) := cierra un socket abierto.


Las dos primeras funciones se usan para crear un socket dada una ip y puerto, o para recibir esta informacion de un socket creado. Una vez tengamos un socket valido, la forma de usarlo es similar a la de un archivo.

Con esto ya podemos mandar un archivo de una maquina a otra. Ahora necesitamos decirle a la maquina remota que lo ejecute.

Buscando por MSDN tenemos la fortuna de encontrar la funcion CreateProcess, que crea un proceso hijo que va a ejecutar lo que le digamos, mientras nosotros con WaitForSingleObjet esperamos a que termine. Lo bueno de esta funcion esque nos ahorramos tener que crear un hijo, mandarle ejecutar y todo lo demas.

El aspecto de la funcion es el siguiente:

- CreateProcess(NULL, // No module name (use command line)
cmd,
// Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure


De todos los argumentos solo nos interesan los dos primeros y los dos ultimos, en realidad el unico que manejaremos "conscientemente" es el segundo. Aqui un ejemplo.

El primer argumento es el nombre del comando, si ponemos NULL lo cogera del segundo argumento, que es una cadena de palabras separadas por espacio, la primera es el comando y las siguentes sus argumentos (hay un limite de, creo, 32kb pero no nos afecta demasiado).

Los dos ultimo argumentos son punteros a estructuras de datos que utiliza windows para los procesos, las usaremos para esperar la ejecucion, y terminar.

El segundo argumento que es una lista de cadenas, puede ser algo tan sencillo como:

- "echo hola" : ejecutara el comando echo con el argumento hola, lo que hara que imprima por pantalla "hola".

- "miprograma.exe arg1 arg2 arg3" : ejecutara miprograma.exe (el .exe puede omitirse) que tiene que estar en el directorio de trabajo o en el path (lo del path no lo he comprobado), y recibe 3 argumentos.

o un poco mas complicados (por lo largo) como el que necesitamos para compilar un cpp con codigo cg:

- "cl /c /I \"C:\\Archivos de programa\\Microsoft Visual Studio .NET 2003\\Vc7\\PlatformSDK\\include\" /I \"C:\\Archivos de programa\\Microsoft Visual Studio .NET 2003\\Vc7\\include\" /I \"C:\\Archivos de programa\\NVIDIA Corporation\\Cg\\include\" main.cpp"

Las \\, \" son comandos de escape de c para que imprima \ y " respectivamente. Este comando ejecuta cl que es el compilador que viene con los visual studio, recibe varios argumentos, basicamente, ruta a includes. El ultimo argumento main.cpp es el nombre del archivo que queremos compilar, previsiblemente el que le acabamos de pasar por red. Esto nos creara un programa objeto .obj con el mismo nombre.

Despues de compilar, tendremos que linkar, esto lo hace una linea similar a la anterior:

- "link /OUT:\"main.exe\" /LIBPATH:\"C:\\Archivos de programa\\Microsoft Visual Studio .NET 2003\\Vc7\\PlatformSDK\\Lib\" /LIBPATH:\"C:\\Archivos de programa\\Microsoft Visual Studio .NET 2003\\Vc7\\Lib\" /LIBPATH:\"C:\\Archivos de programa\\NVIDIA Corporation\\Cg\\lib\" cg.lib cgGL.lib glew32.lib glu32.lib main.obj"

Y por ultimo, ejecutar nuestro programa, cuya linea sera similar al ejemplo de "miprograma.exe", el nombre que tendra el exe se lo decimos al linkador con la orden /OUT:.


Degryll....

martes, 18 de diciembre de 2007

GPGPU@HOME

Propicios dias.

Por fin he creado el blog para hablar sobre mi pfc (...Trompetas celestiales...). En algun momento, creo que recibió el nombre de GPGPU@HOME, veamos que significa esto:

- Lo de GPGPU se refiere a General Purpose GPU, esto es, utilizar la grafica como un procesador de proposito general.

Haciendo una pequeña busqueda por internet sobre los GFlops (operaciones de coma flotante por segundo, que es una manera de medir el rendimiento de un procesador) de cpu y gpu, encuentro que en procesadores se obtienen unos resultados (medidos) en torno a los 20-30 GFlops, y la info que he encontrado sobre la gpu 8800gtx de nvidia dice que esta en torno a los 500 GFlops (teoricos). Aun cuando estos datos esten equivocados, parece razonable intentar aprovechar el rendimiento que nos puede ofrecer la gpu.

La gpu es un procesador de streaming o SIMD (Single Instruction, Multiple Data), esta especializada en aplicar instrucciones "sencillas", a muchos datos a la vez. Asi que tendremos que adaptar este tipo de computacion a una de proposito general (cuando se pueda o sea rentable). Esto se traduce en problemas que sean altamente paralelizables (hacer los mismo muchas veces, sin que unos resultados alteren "demasiado" a otros).

Para ver unos ejemplos del rendimiento que ofrece la gpu vs cpu en este tipo de problemas, hechar un vistazo al blog de Santi.


- @HOME se refiere a la red. La idea es, que la gpu presenta un rendimiento excelente, ¿se obtendra algo parecido utilizando las graficas de ordenadores en red?. No solo esto, hay problemas que son intratables con una sola gpu (una matriz de 1 millon x 1 millon), pero permiten que se divida el problema, ¿una red de gpu sera igualmente rentable?, ¿a partir de que tamaño de problema es rentable usar una red?, ¿Solo es aplicable a un cluster o una red local, o dependiendo del problema incluso algo mas distribuido?.


Para llevar a cabo esta tarea, de que armas disponemos:

Desde hace varias generaciones de gpu, los fabricantes permitieron la programacion de ciertas etapas del pipeline de renderizado. En concreto, son programables la etapa de procesamiento geometrico, y la de operaciones sobre fragmentos (la parte que juega con vertices, rotaciones, luces, y la parte que sale de la rasterizacion y juega con los fragmentos para generar la imagen final).

En un principio (que creo, agradezno no haber conocido...) la programacion de estas etapas se hacia sobre ensamblador, por suerte ahora disponemos de lenguajes de mas alto nivel.

- Cg: Acronimo de C for graphics. Desrarrollado por Nvidia y Microsoft, es un lenguaje para la programacion de gpu's, enfocado a la obtencion de imagenes realistas, aunque puede ser utilizado para proposito general. Requiere del uso de una Api como Direct3D u OpenGl. Sus principales caracteristicas son que se puede usar con un gran abanico de graficas, tanto de Nvidia como de otros fabricantes, dependiendo las operaciones que se pueden realizar con estas segun lo "modernas" que sean. Su mayor desventaja para lo que nos proponemos aqui, es que no tiene realimentacion con la cpu, esto se tendra que hacer con la Api 3D que utilicemos. Nos limitaremos a programar la etapa de operaciones sobre fragmentos.


- CUDA: Lenguaje mas reciente desarrollado por Nvidia enfocado a la programacion de proposito general sobre la grafica. Ofrece mayor abstraccion que Cg, se habla de bloques y threads como unidades de procesamiento, no de la etapa en la que participan y se programa directamente sobre CUDA sin Api intermedia. Su mayor desventaja es que solo es aplicable a gpu de Nvidia G80 o superiores.


Aunque CUDA parece la opcion mas razonable ya que esta diseñado especificamente para la computacion de altas prestaciones, no quisiera desaprovechar lo que Cg puede ofrecer, el uso de graficas inferiores a G80, que tienen un rendimiento por explotar. Ademas quisiera ver si en una red heterogenea, podemos usar a la par, Cg y CUDA, y en que afecta esto al rendimiento.


Otras librerias de las que tendremos que hacer uso, especialmente para trabajar con Cg:

- OpenGl: Aunque el proyecto lo programare en windows, utilizare OpenGL por varios motivos, primero que no quiero cerrar la puerta a la posibilidad de portar el proyecto a otro sistema, segundo, OpenGl sera una herramienta que usare en alguna asignatura del segundo cuatrimestre, y tercero, asi me obligo a aprenderlo.

- GLu/GLAux: Casi en todos los tutoriales y manuales que he visto, utilizan este tandem para añadirle funcionalidad a OpenGl. Yo lo conservare mientras aprendo, por no complicarme las cosas, pero mi intencion es sustituirlo por SDL. Glaux esta obsoleto, se suele usar junto con GLu unicamente para cargar imagenes. Glu por otra parte esta actualizado, se usa para crear ventanas y entornos de renderizado, y un par de funciones que simplifican tareas comunes con OpenGl:

GluPerspective: que se usa para calcular la forma de ver la escena. Ojeando por ahi, encontre esta aproximacion:

void myPerspective(GLfloat fov,GLfloat aspect,GLfloat near,GLfloat far) {
GLfloat range = near*tan(deg2rad(fov/2));
glFrustum(-range*aspect,range*aspect,-range,range,near,far);
}


GluLookAt: para calcular la matriz de vista, teniendo en cuenta el observador y hacia donde mira. Todavia no he encontrado una aproximacion, por eso sigo usando glu.


- SDL: Simple DirectMedia Layer. Libreria para el manejo de ventanas y eventos, puede usarse para 2D o 3D, utilizando OpenGl para el 3D. Incluye toda la funcionalidad de Glu y GLaux a excepcion de las dos funciones mencionadas anteriormente. El principal motivo de que use esta libreria esque me es algo familiar, y que para las funciones de red usare SDL_Net que es una extension para dicho proposito.

- SDL_Net: extension de SDL para funciones de red, tanto TCP como UDP de forma bastante sencilla.


En cuanto a Entorno de desarrollo, Visual C++ (version 7 o superior, por CUDA) que es como vienen la mayoria de tutoriales y no es momento de complicarse.


Degryll....