next up previous contents
Next: 4.2.4 Comparación de funciones: Up: 4.2.3 Implementación Previous: 4.2.3.1 MPI   Índice General


4.2.3.2 PVM

El programa de multiplicación de matrices paralelo utilizando PVM se muestra en el apéndice (A.1.4).

La inicialización de PVM es hasta cierto punto implícita; el llamar a cualquier función de PVM automáticamente enrola al proceso en la máquina virtual, si es que no se encontraba en ella anteriormente. Por convención la primera llamada debe ser a la función pvm_mytid (línea 43), con la que también se obtiene el TID (identificador de tarea o Task Identifier) del proceso. A continuación se obtiene el TID del proceso padre con una llamada a pvm_parent. La necesidad de conocer el TID del proceso padre será obvia más adelante.

Entre la línea 80 y 112, el proceso padre (identificado por el hecho de que su proceso padre tiene el valor PvmNoParent, que se verifica en la línea 80) debe iniciar o engendrar4.2 a los demás procesos que tomarán parte en el cálculo.

La función pvm_spawn inicia, con una sola llamada, todos los procesos necesarios (el número de procesos a iniciar se pasa como un parámetro a la función). La función permite especificar dónde se deben iniciar los procesos, o bien dejar que PVM decida dónde hacerlo; también permite pasar parámetros de línea de comando a los procesos (segundo parámetro) a fin de que su inicialización pueda ser controlada adecuadamente. La función devuelve un arreglo con los TID de los procesos que se iniciaron.

Una vez concluida la inicialización de procesos, todos los procesos deben unirse a un grupo, que arbitrariamente se nombró ``matrix_world'' (línea 116), obteniendo al mismo tiempo su posición en el grupo. El grupo cumple una función similar a la del comunicador en MPI, es decir, permite organizar procesos en grupos de trabajo para restringir el alcance de algunas funciones de comunicación. Una vez unido al grupo, el proceso determina el tamaño del grupo (línea 119). El tamaño del grupo y la posición del proceso se utilizan para determinar el rango de renglones a resolver.

Los grupos no son una función intrínseca de PVM. La funcionalidad de grupos está provista por una biblioteca adicional, así como un demonio que arbitra la comunicación en grupos. La biblioteca y el demonio se incluyen con la distribución de PVM así que no se requiere configuración adicional para usarlos, sin embargo téngase en mente que la funcionalidad es adicional a las funciones básicas de PVM.

A continuación se realiza la bifurcación de trabajo en el proceso, designando al proceso maestro. En PVM hay un concepto directo de proceso padre, y por convención el proceso padre será el maestro. Basándose en aquél proceso que no tiene padre, el proceso maestro realiza su trabajo de la línea 136 a la 267, y los procesos esclavo de la línea 268 a la 384.

El proceso padre genera las matrices aleatorias y las transmite a todos los procesos hijo por medio de un broadcast.

Las operaciones de comunicaciones en PVM involucran algunos pasos. El primero es inicializar el buffer de transmisión, con una llamada a pvm_initsend (línea 182). Posteriormente, se debe empacar el mensaje a enviar en dicho buffer. Esto representa un paso adicional, pero también permite empacar varios mensajes en el buffer y enviarlos todos simultáneamente. El empaque se realiza con una llamada a pvm_pkint4.3 indicando la dirección y tamaño del dato a enviar. Finalmente, el envío se realiza con una llamada a la función correspondiente, en este caso se trata de un broadcast y la función es pvm_bcast, a la que le especificamos el grupo al que se envía y una etiqueta identificadora de mensaje. La etiqueta es en realidad un valor entero, aunque se acostumbra definir nombres significativos para las constantes de etiqueta (líneas 16-17).

Antes de transmitir la segunda matriz se debe llamar a pvm_initsend nuevamente, a fin de limpiar el buffer, ya que éste es acumulativo.

Finalmente el proceso padre espera la recepción de los resultados enviados por los procesos hijo. Utilizando una recepción de mensaje bloqueante (pvm_recv), el proceso espera en la línea 221 hasta recibir un mensaje de cualquier proceso, y con cualquier etiqueta de identificación (indicado por los valores $-1$ que especifican recepción tipo wildcard). Al recibir el mensaje (un renglón resuelto) se desempaca (pvm_upkint, línea 228), y se integra al resultado final.

Al terminar de recibir los renglones el proceso padre muestra el tiempo empleado en el cálculo y termina su ejecución.

A partir de la línea 170, los procesos esclavos (para los cuales la variable pvmparent es distinto de la constante pvmNoParent, indicando que sí tienen un proceso padre) asignan memoria para las matrices a operar y reciben sus valores por medio de broadcast. En PVM la recepción se hace con una llamada a pvm_recv, independientemente de si el origen fue un broadcast o un envío punto a punto. Nótese que en las llamadas a pvm_recv en las líneas 293 y 304 se especifica la etiqueta de mensaje MATRIX_TAG, que corresponde a la etiqueta que se empleó al enviar el broadcast.

Los procesos deben desempacar las matrices recibidas por medio de la función pvm_upkint, después de lo cual determinan los renglones que deben calcular (líneas 317 a 325) y comienzan a realizar los cálculos.

Al completar cada renglón, lo envían al proceso padre, inicializando su buffer de mensajes (pvm_initsend, línea 371), empacando el resultado (pvm_pkint, línea 373) y finalmente enviándolo al proceso padre (pvm_send, línea 381). En la llamada a pvm_send, nótese el primer parámetro myparent, que indica enviar el mensaje al proceso padre.

Los nodos continúan con este proceso hasta terminar el cálculo de sus renglones asignados, en este momento terminan su ejecución.


next up previous contents
Next: 4.2.4 Comparación de funciones: Up: 4.2.3 Implementación Previous: 4.2.3.1 MPI   Índice General
2002-05-15