Professional Documents
Culture Documents
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.
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
DTID 40000
ARCH LINUX
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.
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
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]$
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.
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 */
*/
/* 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 */
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);
* * * * * */
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
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.
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.
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.