domingo, 24 de enero de 2010

Programando en paralelo con OpenMP

Durante estas vacaciones de navidad mi antiguo portátil decidió dejar de funcionar (lo cual me acarreó una serie de problemas que se merecen una entrada aparte...) y tuve que conseguir uno nuevo (generoso regalo de mi madre, ¡gracias mamá!). El nuevo ordenador viene equipado con un procesador Intel de doble núcleo Core 2 Duo.

De vuelta en Cork, y después de unas primeras semanas un poco ajetreadas por el trabajo, me decidí a probar cómo funciona el Core 2 Duo bajo una implementación en paralelo, es decir, ejecutando dos procesos distintos al mismo tiempo, un proceso por núcleo del procesador.

La estructura básica de un procesador de doble núcleo es la siguiente:


Cada núcleo dispone de su propia memoria caché de primer nivel (L1) y comparten la caché de segundo nivel (L2) además de la RAM, claro está.

Lo más eficiente (y fácil) para programar en paralelo intra-nodo es usar el estándar OpenMP. Intra-nodo quiere decir que se comunican procesos que tienen lugar dentro de núcleos que comparten la misma memoria física. Creo recordar que el nodo con mayor número de núcleos disponible comercialmente es uno con 16. El mío, como ya he comentado, tiene dos núcleos.

Para acceder a un mayor número de procesadores es necesario conectarlos en una red local, para lo cual se puede utilizar, por ejemplo, el estándar MPI.

A la hora de paralelizar una operación hay que plantearse si es de hecho más eficiente hacerlo en paralelo o es mejor en serie (usando sólo uno de los núcleos). La implementación en paralelo es siempre más eficiente dadas dos condiciones:

1. Que el problema a resolver puede separarse en varios procesos totalmente independientes entre sí.

2. Que la complejidad del problema compensa el tiempo que se pierde al tener varios núcleos accediendo a la misma memoria a la vez.

De hecho, aunque se dé la primera circunstancia, si el problema es muy simple puede ocurrir que, debido al uso de memoria de la implementación en paralelo, un sólo núcleo haga el trabajo completo más rápido que dos núcleos haciendo la mitad del trabajo cada uno.

Así que programé una rutina en FORTRAN que resolvía las siguientes integrales de funciones cada vez más difíciles de computar:

La más fácil:
\int_0^{\pi} sin(x) \text{d}x
Un poco más difícil:
\int_0^{\pi} sin(x) cos(x) \text{d}x
La más difícil:
\int_0^{\pi} sin {\left[ sin(x) cos(x) \right]} \text{d}x
Los resultados son los siguientes:


Se observa que, a medida que aumenta la complejidad del problema, el proceso en paralelo (que consistió en que cada núcleo resolviera la mitad de la integral) es más y más eficiente que el proceso en serie.

El código que programé se puede descargar aquí. Quien lo quiera ejecutar en Linux puede hacer lo siguiente:
sudo apt-get install f95 (si no tienes el compilador instalado)

cd /directorio_donde_hayas_puesto_el_código/

f95 -fopenmp -o test.ex test.f (compila el código y crea un ejecutable)

./test.ex (ejecuta el programa)

sábado, 9 de enero de 2010

My solar system

Hace un par de días Alberto me mandó este enlace al email:

My solar system

Se trata de un applet, aparentemente en Flash, que han realizado en la Universidad de Colorado y que te permite hacer simulaciones de sistemas solares de hasta cuatro cuerpos moviéndose en un plano. Dependiendo de la configuración inicial elegida se pueden ver cosas muy interesantes, como colisiones o cuerpos que escapan hacia el infinito. Después de mucho probar configuraciones distintas, conseguí incluso que un cuerpo que inicialmente giraba en torno a otro de forma estable durante un buen número de órbitas fuera atrapado por un cuerpo más masivo al avicinarse y empezara a girar alrededor de este último.

Como nota curiosa, es interesante comprobar cómo el resultado de la simulación depende de la precisión (barra de velocidad) que se elige. Con la misma configuración inicial, uno puede acabar con una colisión o con un cuerpo que escapa al infinito sólo variando el nivel de precisión. La explicación que le encuentro es que, al resolver las ecuaciones de forma numérica, la barra de precisión afecta básicamente al paso de tiempo utilizado (mayor cuanto menor es la precisión) y por lo tanto las soluciones son diferentes.

Merece un vistazo.