You are on page 1of 13

El objetivo de este artculo es servir como introduccin a PVM y MPI, dos sistemas de software ampliamente usados para la transmisin

de mensajes entre programas en procesamiento paralelo. Estos nos permiten tener diferentes sistemas UNIX/LINUX conectados por medio de una red, trabajando como si fuesen una nica mquina para resolver un problema complejo.

1. Introduccin al procesamiento paralelo.


El procesamiento paralelo es una forma de computo en la cual un nmero de actividades se realizan de manera concurrente de tal manera que el tiempo para resolver un problema se reduce. Anteriormente, el procesamiento paralelo se empleaba para resolver problemas que requeran una gran escala de simulacin (por ejemplo, simulacin molecular, simulacin de una explosin nuclear), un gran nmero de clculos y procesamiento de datos (por ejemplo, el computo de los datos de un censo) etc. Como quiera que sea, el costo del hardwarea se ha ido decrementando rpidamente, por lo que el procesamiento en paralelo se esta empleando ms y ms en tareas comunes. Los servidores con multiples procesadores han existido desde hace ya mucho tiempo. El procesamiento paralelo tambin se emplea en tu propia PC. Por ejemplo, un procesador grfico trabajo junto con el procesador principal para dibujar los grficos sobre tu monitor empleando procesamiento paralelo. A parte de las facilidades del hardware para llevar a cabo procesamiento paralelo, algo de soporte de software tambin es necesario para poder correr los programas en forma paralela y coordinar su ejecucin. La coordinacin es necesaria para resolver las dependencias de los programas paralelos puedan tener unos con otros. Esto quedar ms claro cuando trabajemos en un ejemplo. El mtodo ms empleado para implementar esta coordinacin es la transferencia de mensajes en la cual los programas coordinan su ejecucin enviando mensajes al resto de los programas. As, por ejemplo, un programa puede decirle a otro "Ok Este es el resultado intermedio que necesita ser procesado". Si todo esto suena demasiado abstracto, permitanme con un muy sencillo ejemplo.

2. Un problema muy simple.


En esta seccin, vamos a considerar un proble muy sencillo y consideremos que podemos emplear procesamiento paralelo para incrementar la velocidad de su ejecucin. El problema consiste en encontrar la suma de una lista de enteros almacenados en un arreglo. Supongamos que hay 100 enteros almacenados en un arreglo que se llama items. Ahora, Como paralelizamos este programa? . Esto es, primero debemos encontrar una forma que el problema pueda ser resuelto por un nmero de programas trabajando de manera concurrente. En muchas ocasiones. la dependencia de los datots, convierten a la paralelizacin en un problema difcil. Por ejemplo, si deseamos evaluar (a + b)*c, lo cual involcra dos operaciones, no lo podemos realizar de manera paralela, ya que la suma debe realizarse antes de la multiplicacin. Afortunadamente, para el problema seleccionado, la paralelizacin es sencilla Suponemos que 4 programas o procesadores trabajan simultaneamente para resolver la suma. La estrategia ms simple sera dividir el arreglo items. 1. 2. 3. Cuatro programas llamados P0, P1, P2 y P3 van a resolver el problema. P0 encontrar la suma de los elementos del arreglo items[0] a items[24]. De manera similar, P1 sumar de items[25] a items[49],, P2 de items[50] a items[74] y P3 items[75] a items[99] . Despus de que estos programas se ejecuten, debe haber otro programa que sume los resultados de los cuatro y de el resultado final. De la misma manera, los elementos del arreglo no son conocidos por los programas P0 a P3, as que algn otro programa deber indicarle a estos programas los valores de los elementos. Por lo tanto, adems de P0 a P3, necesitamos un programa ms que distribuya los datos, junte los resultados y coordine la ejecucin. Nosostros llamamos a este programa maestro y a los programas P0 a P3 esclavos y a esta organizacin el paradigma maestro-esclavo.

Con esta organizacin en la mente, escibiremos los algorimos para los programas maestro y esclavo.
/* Algoritmo para el programa maestro */ inicializacin del arreglo 'items'. /* enviamos los datos a los esclavos */ for i = 0 a 3 Enviar items[25*i] a items[25*(i+1)-1] a slave Pi end for /* juntamos los resultados de los esclavos */ for i = 0 a 3 Recibimos el resultado desde el esclavo Pi en result[i] end for /* clculo del resultado final */ sum = 0 for i = 0 to 3 sum = sum + result[i] end for print sum

El algoritmo para el esclavo puede escribirse de la siguiente manera.


/* Algoritmo para el programa esclavo */ Se reciben los 25 elementos desde el maestro en algn arreglo llamado 'items' /* se calcula el resultado intermedio */ sum = 0 for i = 0 to 24 sum = sum + items[i] end for se envia 'sum' como resultdao intermedio al maestro

3. Implementacin con PVM


Ahora que se tiene diseado al algoritmo bsico, debemos considerar como se implementa. En que hardware podemos correr este programa? De acuerdo, muy pocos de nosotros podemos acceder a mquinas especiales diseadas para correr programas paralelos. De cualquier forma, no se necesita ningn hardware especial para implementar este programa. Una simple computadora o un grupo de estas interconectadas servir, gracias a PVM, un sistema de software que nos permite interconectar a varias computadoras para la ejecucin de programas en paralelo. PVM acrnimo para Pallel Virtual Machine (Mquina Virtual Paralela) te permite crear un nmero de programas o procesos que corren de forma concurrente en la misma o en diferentes mquinas y provee funciones con las cuales es posible transmitir mensajes entre los procesos. En el caso de que tengas una nica mquina, PVM trabajar de todas formas, aunque de acuerdo no se tratar de "procesamiento paralelo real". De cualquier forma, para propositos de aprendizaje, ser ms que suficiente. Mas tarde describir como se lleva a cabo "procesamiento paralelo real"empleando PVM. Para poder usar el sistema PVM, necesitas instalar el software de PVM en tu sistema Linux. En el caso en que estes usando Red Hat Linux, el paquete RPM para PVM se incluye en el CD, as que lo puedes instalar como cualquier otro programa. Asumiendo que tu ya tienes instalado PVM en tu sistema, crea los siguientes directorios en tu directorio home: ~/pvm3/bin/LINUX/ . Por qu? Porque PVM requiere que algunos de los ejecutables que se van a crear se copien a este directorio. Una vez que has hecho esto, estas listo para iniciar. Para probar el funcionamiento de PVM teclea el comando pvm sobre el prompt. Esto debe de iniciar la consola PVM desde la cual se pueden dar comandos para el sistema PVM y consultar el estado de este. Si todo esta bien, veras el prompt pvm>. Ah teclea el comando conf. La salida debe ser algo similar a esto.
pvm> conf conf 1 host, 1 data format HOST joshicomp

DTID 40000

ARCH LINUX

SPEED DSIG 1000 0x00408841

Que quiere decir esto? El sistema PVM permite que consideres un grupo de interconectados sistemas LINUX como una "computadora virtual" la cual posees mucho mayores capacidades de computo que las mquinas individuales. De esta manera, PVM va a distribuir los procesos a travs de todas las computadoras. No obstante, por default, PVM considera que solamente el host en el que se esta trabajando se encuentra dentro de la mquina, es decir todos los procesos que se creen sern ejecutados en el mismo host. El comando conf muestra que hosts o nodos estan en el PVM. Actualmente, solo existe uno. Ms adelante, veremos como agregar ms. A continuacin, sal de la consola PVM dando el comando halt.

3.1 Un programa de Demostracin


Ahora que estamos seguros que el sistema PVM est correctamente instalado, veremos como escribir los programas. Los programas para el sistema PVM pueden estar tanto en FORTRAN como en C. Nosotros emplearemos el lenguaje C. Para usar el sistema PVM, se incluyen algunas llamanda a funciones PVM en tu programa en C y se liga la libreria PVM con tus programas. Para introducirnos a PVM, escribiremos un simple programa en el cual hay un maestro y un esclavo. El maestro enviar una cadena al esclavo, a la cual el esclavo convertir en maysculas y enviar de regreso al maestro. El maestro y el esclavo se muestran a continuacin. Para compilar los programas, se teclea el comando make -f makefile.demo [Click aqu para obtener el archivo tar que contiene los programas que se listan.]

1 /* -------------------------------------------------------------------2 * master_pvm.c 3 * 4 * Este es el programa maestro para una simple demostracin de PVM 5 * -------------------------------------------------------------------6 #include <stdio.h>

* * * * */

7 #include <stdlib.h> 8 #include <pvm3.h> 9 #include <string.h> 10 int main() 11 { 12 int mytid; /* nuesto ID de tarea */ 13 int slave_tid; /* el ID del esclavo */ 14 int result; 15 char message[] = "hello pvm"; 16 17 /* nos incluimos al sistema PVM y obtenemos nuestro ID */ 18 mytid = pvm_mytid(); 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 /* creamos al esclavo */ result = pvm_spawn("slave_pvm", (char**)0, PvmTaskDefault, "", 1, &slave_tid); /* comprobamos que el esclavo se creo adecuadamente if(result != 1) { fprintf(stderr, "Error: Cannot spawn slave.\n"); /* salimos del sistema PVM*/ pvm_exit(); exit(EXIT_FAILURE); } /* se inicializa el buffer de datos para transmitir los datos al esclavo*/ pvm_initsend(PvmDataDefault); /* se "empaqueta'' la cadena dentro del buffer*/ pvm_pkstr(message); /* se envia la cadena al esclavo con una etiqueta de mensaje igual a 0 */ pvm_send(slave_tid, 0); /* se espera y recibe el resultado del esclavo*/ pvm_recv(slave_tid, 0); /* se "desempaca'' el resultado del esclavo pvm_upkstr(message); */ */

/* se muestra el resultado del esclavo*/ printf("Data from the slave : %s\n", message);

43 /* salimos del sistema PVM*/ 44 pvm_exit(); 45 46 exit(EXIT_SUCCESS); 47 } /* fin del main() */ 48 /* fin del master_pvm.c */ 1 2 3 4 5 6 7 8 9 /* -------------------------------------------------------------------* slave_pvm.c * * Este es el program esclavo para una simple demostracin de PVM * -------------------------------------------------------------------#include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <pvm3.h> * * * * */

10 #define MSG_LEN 20 11 void convert_to_upper(char*); 12 int main() 13 { 14 int mytid; 15 int parent_tid; 16 char message[MSG_LEN]; 17 18 19 20 21 22 23 24 25 26 27 /* nos incluimos dentro del sistema PVM mytid = pvm_mytid(); /* se obtiene el ID del maestro*/ parent_tid = pvm_parent(); /* se recibe la cadena origina del maestro */ pvm_recv(parent_tid, 0); pvm_upkstr(message); /* se convierte la cadena a maysculas*/ convert_to_upper(message); /* se envia la cadena convertida al maestro pvm_initsend(PvmDataDefault); */ */

28 29

pvm_pkstr(message); pvm_send(parent_tid, 0);

30 /* se sale del sistema PVM*/ 31 pvm_exit(); 32 33 exit(EXIT_SUCCESS); 34 } /* fin del main() */ 35 36 37 38 39 40 41 42 43 /* funcion para convertir una cadena dada a maysculas */ void convert_to_upper(char* str) { while(*str != '\0') { *str = toupper(*str); str++; } } /* end convert_to_upper() */

44 /* fin del slave_pvm.c */ 1 # Make file para el programa de demostracin de PVM 2 3 4 5 6 7 8 9 10 .SILENT : # rutas para incluir archivos y librerias INCDIR=-I/usr/share/pvm3/include LIBDIR=-L/usr/share/pvm3/lib/LINUX # ligas a la libreria de PVM LIBS=-lpvm3 CFLAGS=-Wall CC=gcc TARGET=all

11 # este es el directorio donde se crearn los programas 12 PVM_HOME=$(HOME)/pvm3/bin/LINUX 13 all : $(PVM_HOME)/master_pvm $(PVM_HOME)/slave_pvm 14 $(PVM_HOME)/master_pvm : master_pvm.c 15 $(CC) -o $(PVM_HOME)/master_pvm master_pvm.c $(CFLAGS) $(LIBS) \ 16 $(INCDIR) $(LIBDIR) 17 $(PVM_HOME)/slave_pvm : slave_pvm.c 18 $(CC) -o $(PVM_HOME)/slave_pvm slave_pvm.c $(CFLAGS) $(LIBS) \ 19 $(INCDIR) $(LIBDIR)

Una vez que los programas han sido compilados, se deben copiar dentro del directorio ~/pvm3/bin/LINUX. (El makefile hace esto por default). Ahora correr los programas, para esto primero debes iniciar el sistema PVM. Para hacerlo da el comando pvm para entrar a la consola PVM. Ahora en el prompt pvm>, teclea quit. La salida deber ser como sigue:
pvm> quit quit Console: exit handler called pvmd still running.

Nota la ltima linea, indicando que el demonio PVM (pvmd) esta corriendo. Para correr los programas PVM, necesitas correr el demonio PVM el cual se encarga de manejar el intercambia de mensajes. Una vez que el demonio esta corriendo, tu puedes correr los programas de la siguiente manera:
[rahul@joshicomp rahul]$ cd ~/pvm3/bin/LINUX/ [rahul@joshicomp LINUX]$ ./master_pvm Data from the slave : HELLO PVM [rahul@joshicomp LINUX]$

Nota como la cadena esta en maysculas tal como esperabamos.

3.2 Explicacin del programa


En esta seccin, veremos exactamente como este programa trabaja. Primero de todo para usar las funciones PVM, necesitas incluir el archivo dee cabecera pvm3.h en tus programas. Esto se hace en la lnea 8 del master_pvm,c y en la lnea 9 del slave_pvm.c Tambin al compilar los programas , necesital ligarlos con la libreria PVM. Esto se hace especificando la opcin -lpvm3 al compilador, como se hace en la lnea 7 del makefile.demo. Adems. se necesita especificar al compilador las rutas de los archivos cabecera y las librerias, como se hace en las lneas 4 y 5 del makefile.

En el programa maestro, primero se obtiene el task ID del maestro haciendo una llamada a la funcin pvm_mytid(). El sistema PVM asigna a cada proceso un identificador nico un entero de 32 bits llamado task ID de la misma mandera como Linux asigna a cada proceso un identificador de proceso. De cualquier forma, el maestro no emplea este identificador (almacenado en mytid). Nuestra intencin era solo llamar a la funcin pvm_mytid(). Esta funcin enlista al proceso dentro del sistema PVM y genera un identificador nico. Si no se enlista explicitamente al proceso, PVM automaticamente agrega a nuestro proceso en la primera llamada de cualquier funcin PVM. A continuacin empleamos pvm_spawn() para crear al proceso esclavo. El primer parmetro de esta, "slave_pvm", es el nombre del ejecutable para el esclavo. El segunto son los argumentos que se desean pasar al esclavo (de manera similar al argv en C) Como no se quieren enviar argumentos, se establece este valor a 0. El tercer parmetro es una bandera con la cual podemos controlar como y donde PVM inicia el esclavo. Como solo tenemos una sola mquina, establecemos esta bandera a PvmTaskDefault, lo cual le indica a PVM que emplee el criterio por omisin para crear al esclavo. El cuarto parmetro es el nombre del host o arquitectura sobre el cual deseamso se corra el programa y en este caso se deja vaco. Solo se emplea cuando se usa una bandera diferente a PvmTaskDefault. El quinto parmetro establece el nmero de esclavos que se crearn y el sexto es un puntero a un arreglo en el cual se regresan los IDs de los esclavos. Esta funcin regresa el nmero de esclavos actualmente creados. Un mensaje en PVM consiste basicamente de dos partes, el dato y una etiqueta que identifica el tipo de mensaje. La etique nos ayuda a distinguir entre diferentes mensajes. Por ejemplo, en el ejemplo de la suma, la cual estamos tratando de implementar, suponemos que esperas que cada esclavo regrese al maestro un entero el cual es la suma de los elementos. Tambin es posible que algun esclavo encuentre un error y envie al maestro un entero el cual indica el tipo de error. Como hace el maestro par distinguir cuando un entero recibido se trata de un resultado intermedio o de un cdigo de error? En esto es donde las etiquetas entran en accin. Puedes asiganr al mensaje para el valor intermedio una etiqueta que diga MSG_RESULT la cual se puede #define en cualquier archivo de cabecera y una etiqueta que diga MSG_ERROT para los mensajes que indiquen error. El maestro observar las etiquetas de los mensajes y determinar a que tipo pertenecen. Para enviar un mensaje, primero se necesita "inicializar" el buffer. Esto se hace llamando a pvm_initsend(). El parmetro para esta funcin indica el esquema de "codificacin" a emplear. Cuando intercambiamos datos entre mquinas de diferentes arquitecturas (entre una mquina Pentium y una estacin de trabajo SPARC) se necesita codificar el dato a enviar y decodificar el dato que se recibe de esta manera el dato es confiable. El parmetro para pvm_initsend() indica el esquema de condificacin a emplear. El valor PvmDataDefault indica un esquema de codificacin en el cual posibilta que el dato pueda ser intercambiado entre arquitecturas heterogeneas. Una vez que el buffer ha sido inicializado, necesitamos colocar el dato dentro del buffer y codificarlo. En nuestro caso, el dato es una cadena, as que empleamos la funcin pvm_pkstr() para "empacarlo" es decir codificarlo y colocarlo dentro del buffer. Si se requiere enviar un entero, existe la funcin pvm_pkint(). De forma similar, hay funcines para otros tipos de datos. Una vez que el dato es empacado, llamamos a pvm_send() para enviar el mensaje. El primer argumento es el ID del proceso al cual esta destinado el mensaje y el segundo es la etiqueta del mensaje. Como solo tenemos un tipo de mensaje, ponemos esta valor a 0. Una vez que el dato se envia al esclavo, el esclavo va a procesarlo y envia el resultado al maestro. As que ahora llamamos pvm_recv() para recibir el datos del esclavo. De nuevo, el parmetro es le ID del proceso que estamos esperando el mensaje y la etiqueta del mensaje. Si el mensaje deseado an no es enviado, esta funcin lo espera y no regresa. Por lo tanto, el maestro espera para que el esclavo procese el dato. Una vez que el mensaje llega, el dato se almacena en el buffer de recepcin. Es necesario "desempacar" es decir decodificar para obtener el mensaje original. Esta decodificacin se realiza mediante pvm_upkstr(). Por ltimo desplegamos la cadena. Antes que el programa termine, se debe indicar al sistema PVM que se deja este de esta manera los recursos ocupados por el proceso son liberados. Esto se realiza llamando a la funcin pvm_exit(). Despus, el programa termina. El programa esclavo es sencillo de comprender. Primero encontramos el ID del master (el cual es tambin su padre ya que el maestro creo al esclavo) llamando a la funcin pvm_parent(). Despus recibe la cadena del maestro, la convierte a mayscula y envia el resultado al maestro.

3.3 El programa de la suma


Ahora que conocemos las cuestiones bsicas de PVM, implementaremos el algoritom de la suma que desarrollamos empleando PVM, Hay un maestro y 4 esclavos. El maestro crea primero a los 4 esclavos y envia a cada uno de ellos su parte de los datos. El esclavo suma los datos y envia el resultado al maestro. Por lo que, se tienen dos tipos de mensajes, uno cuando el maestro envia un dato a los esclavos, para el cual emplearemos la etiqueta MSG_DATA y otro cuando el esclavo envia el resultado al maestro, para el cual usaremos la etiqueta MSG_RESULT. El resto es simple. Los programas maestro y esclavo se listan a continuacin.
1 /* -------------------------------------------------------------------2 * common.h 3 * 4 * Esta cabecera define algunas constantes comunes. 5 * -------------------------------------------------------------------* * * * */

6 #ifndef COMMON_H 7 #define COMMON_H 8 #define NUM_SLAVES 9 #define SIZE 10 #define DATA_SIZE 11 #endif 12 /* end common.h */ 1 /* -------------------------------------------------------------------2 * tags.h 3 * 4 * Esta cabecera define las etiquetas empleadas por los mensajes. 5 * -------------------------------------------------------------------6 #ifndef TAGS_H 7 #define TAGS_H 8 #define MSG_DATA 9 #define MSG_RESULT 10 #endif 11 /* end tags.h */ 1 /* -------------------------------------------------------------------2 * master_add.c 3 * 4 * Programa maestro para implementar la suma de los elementos de un * arreglo usando PVM 5 * -------------------------------------------------------------------6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <pvm3.h> /* PVM constantes y declaraciones */ 9 #include "tags.h" /* etiquetas para los mensajes 10 #include "common.h" /* constantes comunes */ 11 int get_slave_no(int*, int); 12 int main() 13 { 14 int mytid; 15 int slaves[NUM_SLAVES]; /* arreglo para almacenar los task IDs de los esclavos */ 16 int items[SIZE]; /* datos a ser procesados */ 17 int result, i, sum; 18 int results[NUM_SLAVES]; /* resultados de los esclavos */ 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 /* nos enlistamos en el sistema PVM mytid = pvm_mytid(); */ * * * * * */ 101 102 * * * * */ 4 100 (SIZE/NUM_SLAVES) /* nmero de esclavos */ /* tamao total del dato */ /* tamao para cada esclavo */

/* datos del maestro al esclavo*/ /* resultado del esclavo al maestro*/

*/

/* inizilizacion del arreglo 'items' */ for(i = 0; i < SIZE; i++) items[i] = i; /* se crean los esclavos */ result = pvm_spawn("slave_add", (char**)0, PvmTaskDefault, "", NUM_SLAVES, slaves); /* se comprueba que los esclavos creados sean suficientes if(result != NUM_SLAVES) { fprintf(stderr, "Error: Cannot spawn slaves.\n"); pvm_exit(); exit(EXIT_FAILURE); } /* se distribuyen los datos a los esclavos */ for(i = 0; i < NUM_SLAVES; i++) { pvm_initsend(PvmDataDefault); pvm_pkint(items + i*DATA_SIZE, DATA_SIZE, 1); pvm_send(slaves[i], MSG_DATA); } /* se recibe el dato de los esclavos for(i = 0; i < NUM_SLAVES; i++) { int bufid, bytes, type, source; int slave_no; */ */

/* se recibe el mensaje de cualquiera de los esclavos bufid = pvm_recv(-1, MSG_RESULT); /* se obtiene informacin del buffer*/ pvm_bufinfo(bufid, &bytes, &type, &source); /* se obtiene el nmero del esclavo que envio el mensaje*/ slave_no = get_slave_no(slaves, source); /* se desempaca la informacin del esclavo*/

*/

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

pvm_upkint(results + slave_no, 1, 1); } /* se obtiene el resultado final */ sum = 0; for(i = 0; i < NUM_SLAVES; i++) sum += results[i]; printf("The sum is %d\n", sum); /* se sale del sistema pvm_exit(); exit(EXIT_SUCCESS); } /* end main() */ /* funcin que regresa el numero del esclavo dado su task ID */ int get_slave_no(int* slaves, int task_id) { int i; for(i = 0; i < NUM_SLAVES; i++) if(slaves[i] == task_id) return i; PVM */

74 return -1; 75 } /* end get_slave_no() */ 76 /* end master_add.c */

1 /* -------------------------------------------------------------------2 * slave_add.c 3 * 4 * Programa esclavo para realizar la suma de los elementos de un * arreglo usando PVM 5 * -------------------------------------------------------------------6 #include <stdlib.h> 7 #include <pvm3.h> 8 #include "tags.h" 9 #include "common.h" 10 int main() 11 { 12 int mytid, parent_tid; 13 int items[DATA_SIZE]; /* datos para enviar al maestro*/ 14 int sum, i; 15 16 /* nos enlistamos dentro del sistema PVM */ 17 mytid = pvm_mytid(); 18 19 20 21 22 23 24 25 26 27 28 29 30 /* se obtiene el identificador del maestro */ parent_tid = pvm_parent(); /* se reciben los datos del maestro */ pvm_recv(parent_tid, MSG_DATA); pvm_upkint(items, DATA_SIZE, 1); /* se encuetra la suma de los elementos*/ sum = 0; for(i = 0; i < DATA_SIZE; i++) sum = sum + items[i]; /* se envia el resultado al maestro */ pvm_initsend(PvmDataDefault); pvm_pkint(&sum, 1, 1); pvm_send(parent_tid, MSG_RESULT);

* * * * * */

31 /* se sale del PVM*/ 32 pvm_exit(); 33 34 exit(EXIT_SUCCESS); 35 } /* end main() */

1 # Make file para el programa suma del PVM - makefile.add 2 3 4 5 6 7 8 9 10 .SILENT : # rutas para los archivos include y librerias del PVM INCDIR=-I/usr/share/pvm3/include LIBDIR=-L/usr/share/pvm3/lib/LINUX # liga a la libreria PVM LIBS=-lpvm3 CFLAGS=-Wall CC=gcc TARGET=all

11 # el directorio donde se colocaran los ejecutables

12 PVM_HOME=$(HOME)/pvm3/bin/LINUX 13 all : $(PVM_HOME)/master_add $(PVM_HOME)/slave_add 14 $(PVM_HOME)/master_add : master_add.c common.h tags.h 15 $(CC) -o $(PVM_HOME)/master_add master_add.c $(CFLAGS) $(LIBS) \ 16 $(INCDIR) $(LIBDIR) 17 18 $(PVM_HOME)/slave_add : slave_add.c common.h tags.h 19 $(CC) -o $(PVM_HOME)/slave_add slave_add.c $(CFLAGS) $(LIBS) \ 20 $(INCDIR) $(LIBDIR)

En primer termino analizarermos al programa esclavo, por ser el ms sencillo. El esclavo recive los 25 elementos del arreglo del maestro en el arreglo items, obtiene su suma y envia el resultado al maestro con la etiqueta del mensaje MSG_RESULT. Ahora analizemos al maestro. Definimos un arreglo slaves de tamao igual a NUM_SLAVES el cual contiene los task ID's de los esclavos creados. Existe otro arreglo results en el cual se almacenan los resultados de los esclavos. El maestro primero inicializa el arreglo items y despus crea a los esclavos. Despus distribuye los datos a los esclavos. En la llamada a la funcin pvm_pkint() en la lnea 38, el primer parmetro es un puntero al arreglo en el cual los datos se almacenan, el segundo es el nmero de enteros a empacar y el tercero es el "stride". Stride significa cuantos elementos se saltan cuando se empaca. Cuando es 1, los elementos consecutivos son empacados. Cuando es 2, PVM va saltarse a los elementos 2 dando un paquete con los elementos pares (0,2,,4...). De ah que empleemos el 1. Una vez que los datos han sido distribuidos a los esclavos. el maestro espera que los esclavos regresen el valor del resultado intermedio. Una posibilidad para obtener los resultados es que el maestro obtenga primero el resultado del esclavo 0 (es decir del esclavo cuyo ID esta almacenado en slave[0]), despus del esclavo 1 y as sucesivamente. De cualquier forma esta no es una manera ptima. Por ejemplo, puede darse el caso que el esclavo 0 trabaje mas lentamende que la mquina con el esclavo 1, 2 y 3. En este caso, donde el maestro espera el resultado del esclavo 0, los resultados de los esclavos 1, 2 y 3 termina de juntar los datos y realiza las operaciones, esta solucin podra ser valida, pero si se considera la situacin donde un esclavo, cuando termina una tarea se le asigna otra, deseariamos que se le diera la tarea inmediatamente despus que ha terminado la anterior. Por lo que el maestro debe ser capaz de responder a un mensaje de cualquiera de los esclavos. Esto es lo que se hizo. En la llamada a pvm_recv() en la lnea 48, sabemos que el primer parmetro es el task ID de la fuente del mensaje. Si este valor es -1, significa una terjeta salvaje es decir los mensajes de cualquier proceso con la etiqueta de mensaje igual a MSG_RESULT van a ser recibidos por el maestro. El mensaje recibido junto con informacin de control se almacena en un buffer llamado active receive buffer. La llamada regresa un ID nico para este bufffer. Ahora, necesitamos conocer quien envi el mensaje para poder almacenar el resultado en el apropiado elemento del arreglor results. La funcin pvm_bufinfo() regresa informacin acerca del mensaje en el buffer, como la etiqueta del mensaje, el nmero de bits y el task ID de quien lo envi. Una vez que se tiene el ID del remitente, se almacena el resultado enviado en su correcto elemento dentro del arreglo results. El resto del programa debe ser fcil de comprender.

Introduccin
En PVM todas las tareas estn identificadas por un nmero entrero proveido por el pvmd local. En las descripciones futuras ste identificador de tareas ser llamado TID. Es similar al identificador de procesos (PID) usado en el sistemaoperativo UNIX y asume ser opaco para el usuario, es decir, el valor del TID no tiene significadopara l. De hecho, PVM codifica informacin en el TID para su uso interno unicamente. Todas las rutimas de PVM estan escritas en C. Aplicaciones de Fortran pueden llamara stas rutinas a travs de una interface de fortran 77 proveida por PVM.Esta interface traduce argumentos en la cual son pasados por referencia en fortran a sus valores sies necesario por las rutinas de C. El modelo de comunicacin de PVM asume que cualquier tarea puede enviar un mensaje a cualquier otra tarea en PVM y que no hay limite a su tamao o nmero de tales mensajes. Mientras que todos los anfitriones (hosts) tienen limitaciones de memoriafsica que limita espacio potencial de buffer, el modelo de comunicacin no se restringe a las limitaciones de una mquina en particular y asume que hay suficiente memoria disponible. El modelo de comunicacin PVM provee funciones de envio asncrono de bloques, recibo asncrono de bloques, recibo de particionado en bloques. Ennuestra terminologa, envio de bloque regresa en cuanto el buffer de envio se encuentra libre para ser reusado, envio asncronico no depende de un llamado del recibo a una pareja recibo antes de poder el envio regresar. Un recibo no particionado inmediatamente regresa ya sea con datos o una bandera indicando que los datos aun no han llegado, mientras que un recibo particionado regresa nicamente cuando los datos se encuentran en el buffer de recibo. El modelo de PVM garantiza que el orden de los mensajes es preservado. Si la tarea 1 enva un mensaje A a la tarea 2, despus la tarea 1 enva el mensaje B a la tarea 2, el mensaje A llegar a la tarea 2 antes que el mensaje B. Los buffer de mensajes son asignados dinmicamente. El tamao mximo del mensaje que se puede enviar o recibir es limitado nicamente por la cantidad de memoria disponible de un anfitrin dado.

1 Control de Proceso
int tid = pvm_mytid( void ) La rutina pvm_mytid() regresa el TID de este proceso y puede ser llamado varias veces. Prepara ste proceso en PVM si sta es la primer llamada de PVM. int info = pvm_exit( void ) La rutina pvm_exit() le dice al pvmd local que ste proceso se retira de PVM. Esta rutina no mata el proceso, la cual puede seguir en ejecutando tareas al igual que cualquier proceso en UNIX. int numt = pvm_spawn( char *task, char **argv, int flag, char *where, int ntask, int *tids ) La rutina pvm_spawn() empieza ntask copias de un archivo de tareas ejecutables en la mquina virtual. argv es un apuntador a un arreglo de argumentos a procesar con el final del arreglo especificado con NULL. Si task no tiene argumentos, entonces argv es NULL. El argumento flag es usado para especificar opciones: Valor Opcin
0 1 2 4 8 16 32 PvmTaskDefault PvmTaskHost PvmTaskArch PvmTaskDebug PvmTaskTrace PvmMppFront PvmHostCompl

Descripcin
PVM elige en donde reproducir procesos. el argumento where es un anfitrin en particular a reproducir la tarea el argumento where es un PVM_ARCH a reproducirse inicializa tareas bajo un depurador seguimiento de datos es generado inicializa tareas en MPP front-end complemento de anfitrin definido en where

De regreso, numt es un conjunto de tareas que lograron reproducirse o un cdigo de error si nunguna tarea se pudo ejecutar. Si tareas fueron comenzadas, entonces pvm_spawn() regresa un vector de los tid's de las tareas reproducidas; y si algunas tareas no pudieron ser ejecutadas, los cdigos de error correspondiente son puestos en los ultimos ntask - numt posiciones del vector. int info = pvm_kill( int tid ) La rutina pvm_kill() mata alguna otra tarea PVM identificada por el TID. Esta rutina no est diseada para matar a la tarea llamada, en la cual deber ser acompaada llamando a pvm_exit() seguido de exit(). int info = pvm_catchout( FILE *ff ) Por omisin PVM escribe el stderr y stdout de las tareas reproducidas al archivo /tmp/pvml.. La rutina pvm_catchout causa a la tarea llamada pescar la salida de tareas posteriormente reproducidas. Caracteres impresos en stdout o en stderr en tareas hijas son colectadas por los pvmds y enviados en mensajes de control a la tarea padre, en la cual va a marcar cada lnea y agregarla al archivo especificado (en C) o a la salida estndar (en Fortran).

2 Informacin
int info = pvm_parent( void ) La rutina pvm_parent() regresa el TID del proceso que reprodujo esta tarea o el valor de PvmNoParent si no fue creado por pvm_spawn(). int info = pvm_tidtohost( int tid ) La rutina pvm_tidtohost() regresa el TID dtid del demonio corriendo en el mismo anfitrin que TID. Esta rutina es til para determinar en que anfitrin est ejecutandose cierta tarea. int info = pvm_config( int *nhosts, int *narch, struct pvmhostinfo **hostp ) La rutina pvm_config() regresa informacin acerca de la mquina virtual incluyendo el nmero de anfitriones, nhost, el nmero de los distintos formatos de datos, narch. hostp es un apuntador a un arreglo declarado por el usuario de estructuras pvmhostinfo. El arreglo debe ser por lo menos de tamao nhost. De regreso, cada estructura pvmhostinfo contiene el TID pvmd, nombre del anfitrin, nombre de la arquitectura, velocidad relatica de CPU para ese anfitrin en la configuracin.

int info = pvm_tasks( int which, int *ntask, struct pvmtaskinfo **taskp ) La rutina pvm_tasks() regresa informacin acerca de las tareas PVM corriendo en la mquina virtual. El entero which especifica acerca de cual de las tareas regresar informacin. El nmero de tareas es regresado en ntask. taskp es un apuntador a un arreglo de estructuras pvmtaskinfo. El arreglo es de tamao ntask. Cada estructura pvmtaskinfo contiene el TID, pvmd TID, TID padre, bandera de status, y el nombre del archivo reproducido.

3 Configuracin Dinmica
int info = pvm_addhosts( char **hosts, int nhost, int *infos ) int info = pvm_delhosts( char **hosts, int nhost, int *infos ) Las rutinas de C agregan o borran un conjunto de anfitriones de la mquina virtual. En fortran agregan o borran un solo anfitrin en la mquina virtual. En la versin de C info es devuelto como el valor de anfitriones agregados exitosamente. El argumento <>infos es un arreglo de longitud nhost que contiene el cdico de estado para cada anfitrin idividual siendo agregado o borrado. Esto permite al usuario revisar ya sea si nicamente un anfitrim dentro de un conjunto caus un problema en vez de intentar de nuevo agregar o borrar el conjunto entero de anfitriones. Estas rutinas son usadas algunas veces para configurar la mquina virtual, pero es ms comn que sean usadas para incrementar la flexibilidad y la tolerancia de fallas de una aplicacin grande. Estas rutinas permiten a la aplicacin incrementar la potencia de cmputo (agregando anfitriones) si determina que el problema se est poniendo ms complejo para resolverse.

4 Sealamiento
int info = pvm_sendsig( int tid, int signum ) int info = pvm_notify( int what, int msgtag, int cnt, int tids ) La rutina pvm_sendsig() enva una seal signum a otra tarea de PVM identificada por el TID. La rutina pvm_notify() solicita a PVM a notificar a quien hace la llamada la deteccin de ciertos eventos. Las opciones presentes son las siguientes:

PvmTaskExit: notifica si una tarea se retira. PvmHostDelete: notifica si un anfitrin es borrado (o no responde). PvmHostAdd: notifica si un anfitrin es agregado.

En respuesta a una solicitud de notificacin, cierto nmero de mensajes son enviados de vuelta por PVM a la tarea que hace la llamda.

Definiendo y obteniendo opciones


int oldval = pmv_setopt( int what, int val ) int val = pvm_getopt( what, val ) La rutina pmv_setopt() es una funcin de proposito general que permite al usuario definir u obtener opciones en el sistema PVM. pmv_setopt() puede ser usada para definir varias opciones, incluyendo impresin automtica de mensajes de error, nivel de depuracin, y el mtodo de enrutamiento de comunicacin para todas las llamadas posteriores de PVM. pmv_setopt() regresa el valor previo del conjunto en oldval. whatpuede tener los siguientes valores: Opcin
PvmRoute PVMDebugMask PvmAutoErr PvmOutputTid PvmOutputCode PvmTraceTid PvmTraceCode PvmFragSize PvmResvTids PvmSelfOutputTid PvmSelfOutputCode PvmSelfTraceTid PvmSelfTraceCode

Valor Descripcin
1 2 3 4 5 6 7 8 9 10 11 12 13 pliza de enrutamiento enmascaramiento del depurador reporte de error automtico destino stdout para los hijos salida de msgtag seguimiento de destino para los hijos seguimiento de msgtag tamao del fragmento del mensaje permitir que los mensajes reserven etiquetas y tids destino stdout para si mismo salida de msgtag seguimiento de destino para si mismo seguimiento de msgtag

El uso ms popular de pmv_setopt es de activar una ruta de comunicacin directa entre tareas de PVM. Como una regla general, el ancho de banda de comunicacin de PVM sobre una red se dobla haciendo la llamada pmv_setopt( PvmRoute, PvmRouteDirect ); la desventaja es que ste mtodo rpido de comunicacin no es escalable bajo UNIX; por consiguiente, puede que no funcione si la aplicacin involucra ms de 60 tareas que se comunican aleatoriamente entre si. Si no funciona, PVM automticamente hace el cambio de vuelta al mtodo de comunicacin por omisin. Puede ser llamado multiples veces durante la aplicacin para definir selectivamente las ligas de comunicacin directa entre tareas, pero comunmente se llama una sola vez despus de la llamada inicial a pmv_mytid().

5 Envio de mensajes
Enviando mensajes en PVM esta compuesto por tres pasos. Primero, un buffer de envo debe ser inicializado con una llamada a pvm_initsend() o pvm_mkbuf(). Segundo, el mensaje debe de ser encapsulado a ste buffer cualquier nmero de veces y en combinaciones de las rutinas pvm_pk*(). Tercero, el mensaje completo es enviado a otro proceso llamando a la rutina pvm_send() o reparticin multiple con la rutinapvm_mcast(). Un mensaje es recibido ya sea llamando a una rutina de recibo de bloques partiocionados o no particionados y despus expander cada unos de los paquetes del buffer de recibo. Las rutinas de recibo pueden estar puestas para recibir cualquier tipo de mensajes, o cualquier mensaje de una fuente especfica, o cualquier mensaje con una marca de mensaje especificada, o nicamente mensajes con una cierta marca de mensaje dado de una fuente dada.

Buffers de mensajes
inf bufid = pvminitsend( int encoding ) Si el usuario est usndo nicamente un solo buffer (este es el caso tpico) entonces pvm_initsend() es la nico rutina para el buffer que se requiere. Es llamada antes de encapsular un mensaje nuevo en un buffer. La rutina pvm_initsend limpia el buffer de envo y crea uno nuevo para encapsular el mensaje nuevo. El esquema de codificacin usado para la encapsulacin es definido por encoding. El identificador del buffer nuevo es devuelto en bufid. Las opciones de codificacin son las siguientes:

PvmDataDefault: codificacin XDR es empleada por omisin porque PVM no puede determinar si el usuario va a agregar una mquina hetereogena antes de que el mensaje sea enviado. Si el usuario sabe que el siguiente mensaje va a ser enviado solo a una mquina que conoce el formato nativo, entonces se puede usar la codificacim PvmDataRaw y ahorrarse costos de codificacin. PvmDataRaw: no se hace codificacin alguna. Mensajes son enviados en su formato original. Si el proceso de recibo no puede leer este formato, regresar un error durante la expancin. PvmDataInPlace: El buffer contiene solo tamao y apuntadores de los mensajes que se van a enviar. Cuando pvm_send() es llamado, los mensajes son leidos directamente de la memoria del usuario.

Las rutinas de mensajes de buffer siguientes son requeridas solo si el usuario desea manejar multiples buffers de mensaje dentro de la aplicacin. Por lo general, multiples buffers de mensajes no son necesarios para el envo de mensajes entre procesos. Solo hay un buffer de envo activo y uno buffer de recibo activo por proceso en cualquier tiempo dado. El desorrallador puede crear varios buffer de mensajes y cambiarse de uno a otro para la encapsulacin y envio de datos. Las rutinas encapsulacin, envio, recibo, y expancin solo afectan a los buffers activos. int bufid = pvm_mkbuf( int encoding ) La rutina pvm_mkbuf crea un nuevo buffer de envio vaco y especifica el m&eaute;todo de codificacin usado para la capsulacin de mensajes. Regresa un identificador de buffer bufid. int info = pvm_freebuf( int bufid ) La rutina pvm_freebuf() desecha el buffer con el identificador bufid. Este debe de hacerse despus de que un mensaje ha sido enviado y que ya no se ocupar. Llama a pvm_mkbuf() para crear un buffer para un mensaje nuevo si lo requiere. Ninguna de estas llamadas son necesarias cuando se hace la llamada a pvm_initsend(), la cual ejecuta estas llamadas para el usuario. int bufid = pvm_getsbuf( void ) int bufid = pvm_getrbuf( void ) pvm_getsbuf() regresa el identificador del buffer de envio activo. pvm_getrbuf() regresa el identificador del buffer de recibo activo. int oldbuf = pvm_setsbuf( int bufid ) inf oldbuf = pvm_setrbuf( int bufid ) Estas rutinas definen el buffer de envio(o recibo) activo en bufid, guardar el estado del buffer anterior, y regresar el identificador del buffer activo previo oldbuf. Si bufid es puesto a 0 en pvm_setsbuf() o pvm_setrbuf(), entonces el presente buffer es guardado y sin buffer activo. Esta caracterstica puede ser utilizada para guardar el presente estado de los mensajes de la aplicacin para que las libreras de matemticas o grficos que tambin envian mensajes no interfieran con el estado de los buffers de la aplicacin. Es posible el envio de mensajes sin tener que volver a encapsularlos usando las rutinas de buffer de mensajes. Esto se ilustra en el siguiente fragmento. bufid = pvm_recv( src, tag ); oldid = pvm_setsbuf( bufid );

Encapsulamiento de datos
Cada una de las siguientes rutinas en C encapsulan un arreglo del tipo de datos dado en un buffer de envio activo. Pueden ser llamadas varias veces para encapsular datos en un solo mensaje. No hay limite en la complejidad de los mensajes encapsulados, pero una aplicacin debe de expander los mensajes exactamente como fueron encapsulados. Los argumentos para cada una de las rutinas es un apuntador al primer dato a ser encapsulado, nitem es el nmero total de datos a encapsular dentro del arreglo, y STRIDE es el STRIDE a usar en la encapsulacin. Un STRIDE de 1 significa que un vector contiguo es

encapsulado, un STRIDE de 2 significa todos los dems datos son encapsulados, y as sucesivamente. Una escepcin es pvm_pkstr() que por definicin encapsula una cadena con una caracter terminador NULL y no requiere del parmetro nitem o stride. int info = pvm_pkbyte( char *cp, int nitem, int stride ) int info = pvm_pkcplx( float *xp, int nitem, int stride ) int info = pvm_pkdcplx( double *zp, int nitem, int stride ) int info = pvm_pkdouble( double *dp, int nitem, int stride ) int info = pvm_pkfloat( float *fp, int nitem, int stride ) int info = pvm_pkint( int *np, int nitem, int stride ) int info = pvm_pkilong( long *np, int nitem, int stride ) int info = pvm_pkshort( short *np, int nitem, int stride ) int info = pvm_pk( char *cp ) Todas las variables son pasadas como direcciones is count y stride son especificadas; del caso contrario, a las variables se asume que son valores.

Envio y recibo de datos


int info = pvm_send( int tid, int msgtag ) int info = pvm_mcast( int *tids, int ntask, int msgtag ) La rutina pvm_send() etiqueta el mensaje con un identificador entero msgtag y lo enva al proceso identificado por TID. La rutina pvm_mcast() etiqueta el mensaje con un identificador entero msgtag y transmite el mensaje a todas las tareas especificadas en el arreglo de tids (excepto asi mismo). El arreglo de los tids es de tamaontask. int info = pvm_psend( int tid, int msgtag, void *vp, int cnt, int type) La rutina pvm_psend() encapsula y enva un arreglo de tipo de datos especificado a la tarea identificada por TID. Los tipos de datos definidos pueden ser cualquiera de los siguientes:
PVM_STR PVM_BYTE PVM_SHORT PVM_INT PVM_LONG PVM_USHORT PVM_FORMAT PVM_CPLX PVM_DOUBLE PVM_DCPLX PVM_UINT PVM_ULONG

int bufid = pvm_recv( int tid, int msgtag ) Esta rutina de recibo de bloques va a esperar hasta que un mensaje con la etiqueta msgtag ha llegado de TID. Un valor de -1 en msgtag o el TID se empareja con cualquier cosa. Entonces pone el mesaje en un nuevo buffer de recibo que es creado. El buffer de recibo previo es vaciado al menos que haya sido guardado con una llamada a pvm_setrbuf(). int bufid = pvm_nrecv( int tid, int msgtag ) Si el mensaje solicitado an no ha llegado, entonces el recibo sin particiones pvm_nrecv() regresa bufid = 0. Esta rutina puede ser llamada varias veces para el mismo mensaje para verificar si ha llegado o no, mientras ejecuta trabajo til entre llamadas. Si un mensaje con la etiqueta msgtag ha llegado de TID, pvm_nrecv() coloca el mensaje en un nuevo buffer de recibo activo(el cual crea) y regresa el identificador del buffer. El buffer de recibo activo previo es vaciado al menos de que haya sido guardado con la llamada a pvm_setrbuf(). int bufid = pvm_probe( int tid, int msgtag ) Si el mensaje solicitado an no ha llegado, entonces pvm_probe() regresa bufid = 0. Del caso contrario, regresa un bufid para ese mensaje, pero no lo recibe. Esta rutina puede ser llamada varias veces para el mismo mensaje para verificar si ha llegado o no, mientras ejecuta trabajo til entre llamadas. En adicin, pvm_bufinfo() puede ser llamada con el bufid devuelto para determinar informacin acerca del mensaje antes de recibirlo. int bufid = pvm_trecv( int tid, int msgtag, struct timeval *tmout ) Ademas PVM suministra una versin de recibo con expiracin de tiempo. Considere el caso donde un mensaje nunca llegar a su destino(debido a un error o falla); la rutina pvm_recv se bloquearia para siempre. Para evitar tales situaciones, el usuario puede retirarse despus de un lapso de tiempo fijo. La rutina pvm_trecv() permite al usuario especificar el tiempo de espera. Si el tiempo de espera es puesto bien largo, entonces pvm_trecv actua como pvm_recv. Si el tiempo es puesto a 0, entonces pvm_trecv actua como pvm_nrecv. int info = pvm_bufinfo( int budid, int *bytes, int *msgtag, int *tid ) La rutina pvm_bufinfo() regresa msgtag, TID fuente, y la longitud en bytes del mensaje indentificado por bufid. Puede ser usada para determinar la etiqueta y fuente de un mensaje que fue recibido con comodines(wildcards) especificados. int info = pvm_precv( int tid, int msgtag, void *vp, int cnt, int type, int *rtid, int *rtag, int *rcnt ) La rutina pvm_precv() combina las funciones de un recibo de bloques y expande el buffer de recibo. No regresa un bufid. En su lugar, regresa los valores actuales de TID, msgtag, y cnt. int (*old)() = pvm_recvf( int ( *new )( int buf, int tid, int tag ) ) La rutina pvm_recvf() modifica el contexto de recibo causado por las funciones de recibo y puede ser empleado para extender PVM.
Regresar

Expancin de datos

Las siguientes rutinas en C expanden tipos de datos del buffer de recibo activo. En una aplicacin deben de corresponder a las rutinas equivalentes de encapsulacin en tipo, nmero de bloques, y progreso. nitem es un nmero de elementos del tipo dado a expander, y stride es el progreso. int info = pvm_upkbyte( char *cp, int nitem, int stride ) int info = pvm_upkcplx( float *xp, int nitem, int stride ) int info = pvm_upkdcplx( double *zp, int nitem, int stride ) int info = pvm_upkdouble( double *dp, int nitem, int stride ) int info = pvm_upkfloat( float *fp, int nitem, int stride ) int info = pvm_upkint( int *np, int nitem, int stride ) int info = pvm_upklong( long *np, int nitem, int stride ) int info = pvm_upkshort( short *np, int nitem, int stride ) int info = pvm_upkstr( char *cp ) int info = pvm_unpackf( const char *fmt, ... ) La rutina pvm_unpackf() usa un tipo de formato similar de expresin printf para especificar que datos expander y como expander los datos del buffer de recibo.

6 Grupos de procesos dinmicos


Las funciones del grupo de procesos dinmicos estn construidas en el ncleo de las rutinas de PVM. Una librera separada libgpvm3.a debe de ser encadenada a los programas de los usuarios para hacer uso de cualquiera de las funciones del grupo. El pvmd no ejecuta las funciones del grupo. Esta tarea es manejada por el grupo servidor que es automticamente empezada cuando el primer grupo de funciones es invocada. Siguiendo la filosofa de PVM, las funciones de grupo fueron diseadas para ser muy generales y transparentes al usuario. Cualquier tarea de PVM puede unirse o retirarse de cualquier grupo en cualquier instante sin tener que informarle a las dems tareas en los grupos afectados. Las tareas pueden transmitir mensajes a grupos en la cual no pertenecen. En general, cualquier tarea de PVM puede hacer un llamado a cualquiera de las funciones del grupo en cualquier instante dado. Las escepciones son pvm_lvgroup(), pvm_barrier(), y pvm_reduce(), que por su naturaleza requieren que la tarea que llama sea miembro de un grupo especificado. int inum = pvm_joingroup( char *group ) int info = pvm_lvgroup( char *group ) Estas rutinas permiten que una tarea se una o deje un grupo de usuarios. La primer llamada a pvm_joingroup() crea un grupo con el nombre del grupo y coloca a la tarea que llama en este grupo. pvm_joingroup()regresa la instancia del nmero(inum) del proceso de este grupo. Instancias de nmero tienen un rango de 0 hasta el nmero de miembros en el grupo menos 1. Una tarea puede unirse a multiples grupos. Si un proceso se retira de un grupo y despus regresa, el proceso puede recibir una instancia de nmero diferente. Las instancia de nmeros son ciclados para que una tarea que se une al grupo reciba la instancia de nmero ms bajo disponible. int tid = pvm_gettid( char *group, int inum ) int inum = pvm_getinst( char *group, int tid ) int size = pvm_gsize( char *group ) La rutina pvm_gettid() regresa el TID de un proceso dado nombre de un grupo y la instancia de nmero. pvm_gettid() permite que dos tareas sin conocimiento de la otra obtenga el TID de la otra con el simple hecho de unirse al grupo. La rutina pvm_getinst() regresa la instancia de nmero dado el nombre del grupo y el TID. La rutina pvm_gsize() regresa el nmero de miembros en el grupo especificado. int info = pvm_barrier( char *group, int count ) En la llamada a pvm_barrier() el proceso se bloquea hasta count miembros del grupo hayan llamado pvm_barrier(). En general count deber de ser el total de miembros en el grupo. Una cuenta es necesaria ya que en grupos de procesos dinmicos PVM no puede determinar cuantos miembros pertenecen al grupo en un instante dado. int info = pvm_bcast( char *group, int msgtag ) pvm_bcast() etiqueta el mensaje con un identificador entero msgtag y transmite el mensaje a todas las tareas en el grupo especifico excepto a si misma (si es que es del mismo grupo). Para pvm_bcast() "all tasks" es definido ser todas aquellas tareas que el grupo servidor cree que estn dentro del grupo cuando la rutina es llamada. Si una tarea se une al grupo mientras una transmisin, puede que no reciba el mensaje. Si una tarea se retira del grupo mientras una transmisin se lleva a cabo, una copia del mensaje va a ser enviada a la tarea. int info = pvm_reduce( void (*func)(), void *data, int nitem, int datatype, int msgtag, char *group, int root ) pvm_reduce() realiza operaciones globales aritmticas en el grupo, por ejemplo, global sum o global max. El resultado de la operacin de reduccin aparece en root. PVM provee cuatro funciones predefinidas que el usuario pueda colocar en func. Estas son:

PvmMax PvmMin PvmProduct

You might also like