1 - Técnicas Básicas de la Programación Paralela
Creando aplicaciones para PVM continúa con lo tradicional de la programación de memoria distribuida de multiprocesadores, como es el nCUBE de Intel. La computación en paralelo puede ser visto desde tres aspectos básicos, todas basadas en la organización de las tareas que requieran el uso de nuestro cluster. El modelo más común para programar con PVM es el crowd o multitud; es un conjunto de procesos similares (tienen el mismo código) pero que ejecutan distintas fracciones de un todo, o la tarea total.
El segundo es el término llamado tree o árbol, aquí los procesos son copiados de forma tripartita, creando una relación padre e hijo. Esta técnica, aunque no es muy usada, permite encajar aplicaciones de las que no sabemos nada apriori.
La tercera es el hybrid o híbrido, y es una combinación de las dos anteriores; en cualquier punto de la ejecución de una aplicación la relación entre los procesos de carga puede cambiar. Estas tres clasificaciones nos pueden ayudar con la topología de nuestro cluster, en mi caso, gracias a esto puedo añadir un tercer nodo fácilmente, sin afectar la configuración de unix.oz y billy.oz. A continuación están las dos primeras de forma más detallada.
2 - Cómputos CROWD
Estas generalmente usan tres fases. El primero es la inicialización del grupo; el segundo es el cómputo mismo; y el tercero es el conjunto del output (lo que devuelve el programa al usuario), durante esta fase el grupo de nodos pueden terminar una sesión. A continuación se puede ver a través de un programa de multiplicación de matrices el uso de esto por medio del algoritomo de Pipe Multiply Roll:
{Matrix Multiplication Using Pipe-Multiply-Roll Algorithm}
{Processor 0 starts up other processes}
if (<my processor number> = 0) then
for i := 1 to MeshDimension*MeshDimension
pvm_spawn(<component name>, . .)
endfor
endif
forall processors Pij, 0 <= i,j < MeshDimension
for k := 0 to MeshDimension-1
if myrow = (mycolumn+k) mod MeshDimension
{Send A to all Pxy, x = myrow, y <> mycolumn}
pvm_mcast((Pxy, x = myrow, y <> mycolumn),999)
else
pvm_recv(999) {Receive A}
endif
{Multiply. Running totals maintained in C.}
Multiply(A,B,C)
{Send B to Pxy, x = myrow-1, y = mycolumn}
pvm_send((Pxy, x = myrow-1, y = mycolumn),888)
pvm_recv(888) {Receive B}
endfor
endfor
3 - Cómputos TREE
Para mostrar mejor como esto crea un proceso parecido a la estructura de un árbol podemos usar un algoritmo de Parallel Sorting del MIT donde un proceso procesa, para luego compilar un segundo proceso. Ahora hay dos procesos, y ambos se copian nuevamente para generar dos más y así sucesivamente, creando una estructura de un árbol. Cada proceso es independiente del otro. Este es el código desarrollado por la MIT:
{ Spawn and partition list based on a broadcast tree pattern. }
for i := 1 to N, such that 2^N = NumProcs
forall processors P such that P < 2^i
pvm_spawn(...) {process id P XOR 2^i}
if P < 2^(i-1) then
midpt: = PartitionList(list);
{Send list[0..midpt] to P XOR 2^i}
pvm_send((P XOR 2^i),999)
list := list[midpt+1..M