apuntes pvm

36
aic2tema5 Parallel Virtual Machine Índice 5.1. Características de PVM 5.2 Arquitectura de PVM 5.2.1 Modelo de computación 5.2.2 Modelo de implementación 5.2.3 Arranque y configuración de PVM 5.2.4 Construcción de la máquina virtual (interioridades). 5.3 Modelo de comunicación. 5.3.1 Mensajes. 5.3.2 Tarea – demonio. 5.3.3 Demonio – demonio. 5.3.4 Etapas de un mensaje. 5.4 Programación de aplicaciones en PVM 5.4.1 Interfaz de usuario de PVM 5.4.2 Funciones para el control de procesos 5.4.3 Funciones de información 5.4.4 Funciones de configuración dinámica de la máquina virtual 5.4.5 Funciones de señalización 5.4.6 Funciones de control de buffers 5.4.7 Funciones de empaquetado/desempaquetado de datos. 5.4.8Funciones para envío y recepción de mensajes. 5.4.9 Funciones para operaciones colectivas 5.5 Ejemplos 5.5.1 Padre-Hijo 5.5.2 Envío de mensajes 5.5.3 Uso de grupos 5.5.4 Información de la PVM 5.5.5 Producto escalar de dos vectores 5.5.6 Producto de dos matrices cuadradas 1

Upload: david-agui-lera

Post on 01-Nov-2014

109 views

Category:

Documents


1 download

DESCRIPTION

Apuntes PVM

TRANSCRIPT

Page 1: Apuntes PVM

aic2tema5

Parallel Virtual Machine

Índice

5.1. Características de PVM5.2 Arquitectura de PVM

5.2.1 Modelo de computación5.2.2 Modelo de implementación5.2.3 Arranque y configuración de PVM5.2.4 Construcción de la máquina virtual (interioridades).

5.3 Modelo de comunicación.5.3.1 Mensajes.5.3.2 Tarea – demonio.5.3.3 Demonio – demonio.5.3.4 Etapas de un mensaje.

5.4 Programación de aplicaciones en PVM5.4.1 Interfaz de usuario de PVM5.4.2 Funciones para el control de procesos5.4.3 Funciones de información5.4.4 Funciones de configuración dinámica de la máquina virtual

5.4.5 Funciones de señalización5.4.6 Funciones de control de buffers5.4.7 Funciones de empaquetado/desempaquetado de datos.

5.4.8Funciones para envío y recepción de mensajes.

5.4.9 Funciones para operaciones colectivas5.5 Ejemplos

5.5.1 Padre-Hijo

5.5.2 Envío de mensajes

5.5.3 Uso de grupos

5.5.4 Información de la PVM

5.5.5 Producto escalar de dos vectores

5.5.6 Producto de dos matrices cuadradas

1

Page 2: Apuntes PVM

5.1 Características de PVM ● SW de dominio público desarrollado por el Oak Ridge National Laboratory.● Computación basada en procesos.● Modelo basado en paso de mensajes.● Heterogeneidad a nivel de computadores, redes y aplicaciones.

● Existe la posibilidad de asignar explícitamente tareas a computadores concretos.● Los computadores de la máquina virtual pueden ser multiprocesadores de memoria distribuida o compartida.● Escalabilidad.

○ Inclusión/ eliminación de forma dinámica.○ Se puede configurar en una aplicación una submáquina virtual dentro de la máquina virtual.

● Tolerancia a fallos.○ No proporciona tolerancia a fallos de forma implícita en una aplicación.○ El programador es el responsable de diseñarla en el programa.

● Dominio público.○ Versión actual: 3.4.4

● Bajo coste.○ SW gratuito.○ HW: cualquier computador con versiones Linux/PVM.

● Portabilidad. Entornos donde se ha instalado PVM

MODELO DE COMPUTADOR SISTEMA OPERATIVO

ORDENADORES PERSONALES ---------------------------------------------------------------------------------

Pentium II, Pentium PRO, Pentium Duals y Quads, AMD, Apple Macintosh

WinNT, Linux, Solaris, SCO, NetSBD, BSDI, FreeBSD, NetBSD

ESTACIONES DE TRABAJO Y SISTEMAS DE MEMORIA COMPARTIDA

---------------------------------------------------------------------------------

DEC Alpha, Pmax, Microvax, HP 9000, IBM RS6000, J30, SGI, SUN3, SUN4, SPARC, Ultra SPARC

OSF, NT-Alpha, HP-UX, AIX 3.x, AIX 4.x, IRIS 5.x, IRIS 6.x, SunOS, Solaris 2.x

COMPUTADORES PARALELOS ---------------------------------------------------------------------------------

2

Page 3: Apuntes PVM

Cray YMP T3D T3E, Cray2, Convex Exemplar, IBM SP2, 3090, NEC SX-3, Fujitsu, Amdahl, TMC CM5, Intel Paragon, Sequent, Symmetry, Balance

5.2 Arquitectura de PVM● Cada tarea puede enviar un mensaje a cualquier otra tarea PVM

○ No existen límites en el número y tamaño de los mensajes.○ Factor condicionador ==> memoria disponible en cada computador.

● Envío asíncrono sin bloqueo○ Devuelve el control a la tarea tan pronto como el buffer de envío esté libre para ser utilizado de nuevo con

independencia de que el destinatario haya realizado una llamada a la función de recepción.● Recepción asíncrona con/sin bloqueo.

○ Una recepción no-bloqueante devuelve el control a la tarea con independencia de la llegada de los datos.○ Existe un flag que permite determinar qué ha ocurrido en la recepción.○ La recepción bloqueante no devuelve el control a la tarea en tanto no se produzca la llegada de los datos al buffer

de recepción.● Se garantiza el orden de los mensajes.

○ Modificación del orden mediante las funciones de filtrado.● Difusión de mensajes en modo broadcast.

○ Mismo mensaje a un grupo de tareas.● Grupos dinámicos de tareas.

○ Identificador de grupo.○ Formar parte de diferente grupos.○ Entrada y salida dinámica.○ Sincronización de barrera y envío de mensajes en modo broadcast.

● Envío de señales y eventos asíncronos.○ Ej.: despertar a una tarea para recibir un mensaje, notificar situaciones anómalas.○ La recepción de eventos sólo se puede dar en: conclusión de una tarea, y eliminación/inclusión de un computador

en la máquina virtual.

5.2.1 Modelo de computación

a. Paralelización de una aplicación según la similaridad de sus tareas:a. MPMD o paralelismo a nivel funcional:

i. Cada tarea realiza una función diferente (entrada de datos, resolución del problema, presentación de resultados...)

ii. ¿Cómo se obtiene el paralelismo?1. Ejecutando diferentes tareas de forma concurrente.2. Estableciendo entre alguna de ellas una segmentación o pipeline a nivel de datos.

b. SPMD:i. Cada tarea ejecuta el mismo código pero sobre un subconjunto diferente de datos.

b. Paradigmas algorítmicos de paralelización desde el punto de vista de la estructuración de las tareas:a. Fases paralelas:

i. Sucesión de un número indeterminado de fases para alcanzar la solución.ii. Cada fase tiene dos etapas: cálculo e interacción.

3

Page 4: Apuntes PVM

b. Segmentación (pipeline)i. Las tareas de la aplicación se comportan como etapas de una segmentación virtual a través de la cual los

datos circulan de forman continua.

EJEMPLO - Suma de números (Segmentación)

Código básico para el procesador PI recv(&accumulation, Pi-1);accumulation=accumulation+number;send(&accumulation, Pi+1); Excepto para el primer proceso P0: send(&number, P1); Y el último proceso Pn-1, que es: recv(&number, Pn-2);accumulation=accumulation+number;

4

Page 5: Apuntes PVM

c. Arborescente

i. Adecuado para problemas en los que la carga de trabajo se desconoce a priori (algoritmos recursivos o de clasificación...)

ii. Difícil balancear adecuadamente la carga

d. Maestro-esclavo (host-node)

i. Tarea maestra1. Parte secuencial del algoritmo2. Lanza e inicializa las tareas esclavas, recoge los resultados y realiza (si hay) funciones de

sincronizaciónii. Variantes

1. Un hijo cuando concluye puede recibir más carga del padre y continuar trabajando.2. El padre puede tener que procesar la parte que le corresponda de la carga de trabajo.

e. Híbridoi. Generación totalmente arbitraria de la estructura de las tareas en función de la carga de trabajo a

procesar

5.2.2 Modelo de implementación

● Demonio (pvmd3):○ Instalado en todos los computadores de la máquina virtual.○ Acepta como parámetro opcional un fichero con la configuración.○ Gestiona y ejecuta las aplicaciones PVM en la máquina virtual, administra los mecanismo de sincronización,

comunicación, conversión de datos y oculta la estructura de red al programador.● Biblioteca de desarrollo (API):

○ Contiene funciones para operar con las tareas, transmitir mensajes entre ellas y alterar las propiedades o configuración de la máquina virtual.

○ Toda aplicación se debe enlazar con los ficheros de la biblioteca.○ Estos ficheros son tres: libpvm3.a, libgpvm3.a, libfpvm3.a.

● Consola de PVM.

5

Page 6: Apuntes PVM

○ Proporciona una interfaz simple entre el usuario y el demonio.○ Permite modificar de forma interactiva la máquina virtual que previamente ha sido definida por el demonio

mediante el fichero de configuración.○ Versión gráfica de la consola: xpvm.

5.2.3 Arranque y configuración de PVMHay cuatro formas de arrancar PVM en Linux:

- Desde la consola (pvm)- Desde la consola gráfica (xpvm)- Ejecutando de forma directa el demonio (pvmd3)

pvm [-n host_name] [host_file]xpvm [-n host_name] [host_file]pvmd3 [-n host_name] [host_file]&

o –n host_name permite especificar un nombre alternativo para la máquina en la que se arranca el demonio en caso de que estén instaladas varias tarjetas o interfaces de red.o host_file fichero de configuración.

- Desde un programa (función pvm_start_pvmd Antes de visualizar la consola se produce la lectura del fichero $HOME/.pvmrc

SINTAXIS SIGNIFICADO EJEMPLO

add host_1...host_n Incorpora los computadores host_1 a host_n a la máquina virtual. add tarzan

alias atajo comando Define un atajo o alias para escribir un comando. Sin parámetros, lista los existentes.

alias h help

conf Muestra la configuración de la máquina virtual

delete host_1...host_n Elimina los computadores host_1 a host_n de la máquina virtual. Losprocesos que se encuentren funcionando en esos computadores son eliminados. No se puede eliminar la máquina desde la que se está utilizando la consola.

delete tarzan

echo argumento Muestra en pantalla argumento. echo hola mundo

halt Mata (elimina) a todos los procesos y demonios PVM incluyendo la consola y detiene la máquina virtual.Es la forma recomendada para detener el sistema ya que asegura una salida ordenada.

help comando Muestra todas las opciones disponibles para comando. Sin argumento lista todos los comandos que se pueden utilizar en la consola.

help halt

id Imprime el identificador (TID) de la tarea consola.

jobs Visualiza un listado de los trabajos en ejecución.

kill tid Se utiliza para matar una tarea PVM mediante su identificador. kill 40003

mstat host Muestra el estado del computador host. mstat tarzan

6

Page 7: Apuntes PVM

ps opciones Lista todos los procesos que se ejecutan en la máquina virtual. Muestra su localización, su identificador y el de latarea padre. Las opciones que posee son: -a: Información de todos los procesos.-hhost_tid: Información de los procesos del nodo que tenga como TID host_tid.-nhost_name: Información de los procesos que del nodo con el nombre host_name-x: Información de todos los procesos, incluida la consola.

ps -aps -h40003 ps -nlinda.uned.esps -x

pstat tid Imprime por pantalla el estado de la tarea cuyo identificador es tid.

pstat 40003

quit Cierra la consola dejando la máquina virtual funcionando.

reset Mata todas las tareas PVM salvo las consolas que se encuentren en ejecución, limpia los buffers de envío y recepción de mensajes, inicializa las tablas internas de PVM y deja a los demonios en estado de espera.

setenv Visualiza las variables de entorno del sistema.

sig n_señal tid Envía la señal n_señal a la tarea cuyo identificador es tid. sig 15 40003

alias ? helpalias ayuda helpalias stop haltalias exit quitalias depurar traceecho Configuración actual máquina virtualconfecho Versión de PVMversionecho TID de la consolaidadd blancanievesadd sabio

Ejemplo de fichero .pvmrc Hay dos formas de configurar PVM:● Fichero de configuración

○ Contiene la lista de los computadores que forman la máquina virtual.○ Contiene los computadores que en el futuro pueden añadirse desde consola.○ Cada usuario puede tener su propio fichero de configuración.○ Sintaxis:

■ nombre_computador opcion_i=valor_i

● Manualmente desde Consola (add)○ No permite incluir opciones○ Salvo que se hayan especificado antes en el fichero de configuración (&)

OPCIONES SIGNIFICADO

lo=nombre_usuario Permite indicar un nombre de usuario (login) alternativo para realizar la conexión remota al computador. Por defecto, se utiliza el login empleado en la máquina en que se inició la ejecución de PVM.

7

Page 8: Apuntes PVM

so=pw Provoca que el demonio de la máquina en la que se inició la ejecución de PVM solicite una contraseña para poder acceder a la máquina remota. Cuando se recurre a esta opción no se puede arrancar la PVM desde la consola o como tarea de fondo ya que el demonio solicita la entrada de datos a través del teclado. Al procesar el demonio esta opción se obtendrá por pantalla el mensaje: Password(tarzan.dia.uned.es:msanchez): teniendo que introducir la contraseña del usuario msanchez en el computador tarzan.dia.uned.es. Tras esto, el arranque de la máquina continuará normalmente. Por defecto, PVM utiliza el comando rsh para iniciar los demonios pvmd3 remotos. Esto sólo funcionará si en la máquina remota aparece el nombre del computador local en el fichero .rhosts del usuario o en el fichero /etc/host.equiv del sistema y, además, las RPC (Remote Procedure Calls) están activadas. Sin embargo, cuando se especifica esta opción el demonio maestro recurre a la función rexec() para la creación de la tarea remota.

dx=ubicacion_del_demonio Permite establecer al demonio en la máquina remota en una ubicación diferente a la que se utiliza por defecto. Se puede indicar una ruta absoluta o relativa con respecto al directorio home del usuario en la máquina remota seguido del nombre del demonio (por defecto, pvmd3). Es la opción adecuada para poder utilizar la instalación personal de un usuario.

ep=ubicaciones_de_ejecutables Conjunto de rutas separadas por el carácter : en las que se encuentran los ficheros que se van a utilizar. Si no se especifica esta opción, la máquina virtual buscará las aplicaciones en la ruta $HOME/pvm3/bin/PVM_ARCH siendo PVM_ARCH el nombre de la arquitectura de la máquina considerada.

sp=valor_numerico Permite especificar la potencia del computador en relación con las demás máquinas que constituyen la máquina virtual. El valor numérico debe ser entero y estar en el rango [1 – 1000000]. El valor por defecto es 1000.

wd=directorio_de_trabajo Permite indicar el directorio de trabajo en el que se van a ejecutar todas las tareas que sean lanzadas. Por defecto se ejecutan en el directorio $HOME.

ip=nombre_de_ordenador Cuando existen varios interfaces o tarjetas de red, esta opción permite seleccionar un nombre de entre los que maneja la máquina. Hay que utilizar un nombre y no una dirección IP ya que el valor se pasa al comando rsh y a la función rexec().

so=ms Implica que en esta máquina el demonio debe ser arrancado de forma manual. Esta opción es la adecuada si no se pueden utilizar rsh y rexec() pero existe comunicación IP entre el maestro y el esclavo. El empleo de esta opción provoca el establecimiento de un diálogo a través de la consola con el maestro, el cual irá proporcionando por consola las instrucciones necesarias para arrancar de forma manual el demonio. El uso de esta opción no es muy habitual.

# Ejemplo de fichero de configuraciónblancanievessabio so=pwmudito dx=/url/local/bin/pvmd3 lo=lengualloron ep=/home/ejecutables:~/bincascarrabias lo=tozudo# Computadores que pueden añadirse#posteriormente con el comando add

8

Page 9: Apuntes PVM

&ulises.dia.uned.es lo=laertes&telemaco.ucm.es so=pw&penelope.mat.uned.es wd=/home/pruebas/

Ejemplo de fichero de configuración

# Ejemplo de fichero de configuración con#opciones por defecto* lo=aqueo dx=/url/local/bin/pvmd3patrocloaquiles# Redefinición de una de las opciones por#defecto* lo=troyanohectorparis

Ejemplo de fichero de configuración con opciones por defecto

5.2.4 Construcción de la máquina virtual

● Arranque del demonio maestro:○ Es el que arranca en primer lugar (4 formas descritas).○ Arranca a los demonios esclavos según el host_file.

■ Este proceso de arranque se realiza por el proceso shadow pvmd o pvmd’ (proceso hijo del maestro realizada mediante la llamada al sistema fork()).

○ Cada demonio arranca en el directorio /tmp dos ficheros:■ pvm1.uid (registro de errores).■ pvmd.uid (nº ip y puerto de escucha).

● uid: identificador numérico del usuario que ejecuta el demonio.● Creación de los demonios esclavos:

○ Manualmente (opción so=ms del host_file).■ No se puede usar para la inclusión dinámica.■ Suele usarse si los servicios RPC están deshabilitados pero existe conectividad entre las máquinas

mediante TCP/IP.● Mediante el comando rsh():

○ Tienen que estar activos los servicios RPC (demonio rshd).○ Sin necesidad de contraseñas:

■ /etc/hosts.equiv: contiene todos los nombres de los computadores que componen la máquina virtual.■ $HOME/.rhosts: contiene todos los nombres de los computadores que componen la máquina virtual.

● Mediante la función rexec():○ Se encuentra compilada como parte del código de pvmd3.○ Reclama al usuario el empleo de una contraseña en tiempo de ejecución.

● La tabla del host.○ Contiene información de los computadores que forman la PVM.○ Entrada host descriptor:

■ hay una por cada uno de los computadores que foman la máquina virtual.■ Permite acceder a la información de configuración del computador y de los buffers de mensajes.

○ Cada demonio tiene una copia de la host table.○ ¿Por qué se puede producir la actualización?

■ Al añadir un nuevo esclavo a la máquina virtual. El maestro se encarga de actualizar la host table y enviar la taba actualizada mediante broadcasting a todos los esclavos.

■ Eliminación de un esclavo desde el maestro. El maestro envía un mensaje a todos los esclavos indicando la máquina que ha causado la baja.

■ Un demonio sea dado de baja de forma local, sea cancelado por el envío de una señal UNIX, sea abortado... El esclavo mata a todas las tareas que dependan de él mediante el envío de la señal SIGTERM y remite un mensaje a los restantes demonios para que lo eliminen de sus copias de la host table.

■ Eliminación autónoma por parte de un esclavo de una entrada cuando observe que una máquina es inalcanzable (tiempo de confirmación).

9

Page 10: Apuntes PVM

● Identificador de una tarea (TID)○ Cada tarea, grupo de tareas y demonios poseen un TID único.○ Campos: S (Server bit), G (Group bit), H (Host field), L (Local field).○ H: almacena el host descriptor. Es posible disponer de hasta (212 −1)= 4095 computadores en una máquina

virtual.○ L: identifica a una tarea dentro de cada uno de los computadores de la máq. virtual. Pueden coexistir hasta (218

−1)= 262143 en cada computador.

S G H L

31 30 29 18 17 0

S G H L SIGNIFICADO

0 0 1...4095 1...262143 Identificador de una tarea.

0 1 1...4095 1...262143 Dirección multicast.

1 0 0 0 Identificador del demonio local a la tarea.

1 0 1...4095 0 Identificador de un demonio.

1 0 0 0 Identificador del shadow daemon en la máquina maestra.

1 1 Número negativo Número negativo Condición de error.

10

Page 11: Apuntes PVM

5.3 Modelo de comunicación● Tipos de comunicación que coexisten en la PVM:

○ Indirecta entre dos tareas (opción por defecto):■ Entre un demonio y una tarea (TCP)■ Entre demonios (UDP)

○ Directa entre dos tareas (TCP) Hay que compilar PVM con la opción.

5.3.1 Mensajes

● Partes del mensaje:○ Cuerpo: información útil (datos del problema) que se intercambian las tareas.○ Cabecera: información de control.

■ Código: nº entero que define el tipo de mensaje (filtrado).■ Codificación: indica la clase de empaquetamiento.■ Wait context ID (waitc): lo genera el demonio cuando recibe una petición de servicio por parte de una

tarea local. Este número se envía al demonio destino y se devuelve con la respuesta. El waitc sirve para que el demonio local cuando reciba la conformidad del demonio destino pueda recuperar el contexto en que se encontraba y saber qué tarea fue la originaria.

■ Checksum: para control de errores. No se

usa.5.3.2 Tarea-demonio:● Se realiza a través de sockets TCP. Se puede selecionar en la compilación que los sockets sean Unix en lugar de TCP (más

rápido).○ Servicio seguro (mensajes de confirmación).○ Comunicación a nivel local ==> coste de creación y cierre relativamente bajo.

● Formato de las cabeceras de los paquetes:○ SOM (Start Of Message). SOM=1: primer mensaje.○ EOM (End Of Message). EOM=1: último mensaje.○ SOM=EOM=0 ==> fragmento intermedio.

11

Page 12: Apuntes PVM

5.3.3 Demonio-demonio:● Protocolo UDP.

○ Bajo número de conexiones.○ Coste de creación de sockets UDP más bajo que los de TCP.○ Empleo de timers del nivel UDP para detectar problemas en las comunicaciones o los demonios.

● Cabecera del paquete:○ SOM y EOM: determinan los paquetes que delimitan el comienzo y final de un mensaje.○ DAT: indica que el paquete contiene datos válidos y debe ser entregado a la tarea.○ ACK: indica que el número del paquete del que se confirma su recepción es válido. PVM envía un paquete de ACK

(ACK=1, DAT=0) por cada fragmento de datos recibido (ACK=0, DAT=1). Ambos bits activos: piggybacking.○ FIN: provoca el cierre ordenado del proceso de comunicación entre los demonios.

5.3.4 Etapas de un mensaje● M: mensaje● Mn: partes en que se descompone M.● CT: cabecera tarea.● CTD: cabecera tarea – demonio.● CDD: cabecera demonio-demonio.● ACK: cabeceras con ACK=1, DAT=0

.

12

Page 13: Apuntes PVM

5.4 Programación de aplicaciones en PVM

● Aplicación paralela basada en PVM:○ Lenguaje de programación: C, C++ y FORTRAN.○ API de PVM.

● Composición de la aplicación paralela:○ Un único programa:

■ Lanzado desde la consola.■ Se generan varias copias con el comando spawn.

○ Programa maestro y esclavo:■ El programa maestro crea tareas que ejecutan el código de los esclavos.

○ Un único programa:■ Se desdobla en varias tareas.■ Cada tarea ejecuta un código según la lógica del programa.

● Restricción al lanzamiento de una tarea desde la consola: la tarea no debe contener una entrada interactiva.● Salida estándar:

○ Aplicación invocada desde la línea de comandos: los resultados se escriben en pantalla.○ Aplicación lanzada desde la consola: la salida irá al fichero /tmp/pmd1.uid del demonio maestro.

5.4.1 Interfaz de usuario de PVM● http://www.netlib.org/pvm2/book/pvm-book.html● Control de procesos: creación y destrucción de tareas.● Información: permiten obtener información sobre el estado de la máquina virtual.● Configuración dinámica de la máquina virtual: permiten la adaptación del sistema ante determinadas situaciones, como

por ejemplo, un fallo de computadores o un aumento de la carga computacional.● Señalización: permiten dotar a la máquina virtual de la funcionalidad necesaria para poder construir aplicaciones paralelas

tolerantes a fallos.● Control de buffers: limpiar buffer de envío, crear un buffer, establecer un buffer activo... ● Empaquetamiento /desempaquetamiento de datos.● Envío y recepción de mensajes.● Operaciones colectivas.

13

Page 14: Apuntes PVM

5.4.2 Funciones para el control de procesos

OPCIONES SIGNIFICADO

int info=pvm_start_pvmd(int arg, char **argv, int block) Arranca el demonio PVMD.

int info=pvm_addhosts(char **hosts, int nhost, int

*infos)

Añade hosts a la máquina virtual PVM.

int info=pvm_delhosts(char **hosts, int nhost, int

*infos)

Elimina hosts de la máquina virtual PVM.

int numt=pvm_spawn(char *task, char **argv, int flag,

char

*where, int ntask, int *tids)

● task: nombre del programa PVM que va a ejecutarse. La ruta por defecto en que se buscan los programas es $HOME/pvm3/bin/$PVM_ARCH.

● argv: puntero a un vector de argumentos que se pasa a la tarea que va a ser creada, siendo el elemento 0 el nombre y ubicación del proceso y el último null.

● flag: valor entero que se emplea para especificar las opciones de creación del proceso.

● where: cuando procede, es una cadena de caracteres que indica dónde crear el proceso.

● ntask: nº de copias del proceso que hay que crear.● tids: array con los TIDs de las tareas creadas con éxito. Si hay errores, los

códigos de error se sitúan en las últimas (ntask-numt) posiciones.

Arranca nuevos procesos bajo PVM.

int info=pvm_kill(int tid) Termina tarea PVM

● Ejemplos de uso de la función pvm_spawn.

○ numt=pvm_spawn(argv[0], (char**)0, PvmTaskDefault, (char*)0, n, tids);

○ numt=pvm_spawn(argv[0], (char**)0, PvmTaskDefault,``´´, n , tids);

○ char argumentos[] = {“12”, “60”, (char*)0}numt=pvm_spawn(“esclavo”, argumentos, 0, 0, 16, tids)

○ numt=pvm_spawn(“esclavo”,0,PvmTaskHost,”ulises.dia.uned.es”, 1, &tids[0]);

○ numt=pvm_spawn(“esclavo”, 0, PvmTaskArch,“SUN4”, 1, tids);

○ numt=pvm_spawn(“esclavo, 0, PvmTaskHost, “linda”, 256, tids);

● int info=pvm_kill (int tid).○ Solicita la terminación del proceso que la recibe.○ No debe usarse para la terminación de la tarea que la invoca (pvm_exit() y exit()).○ info<0==> error

● int info=pvm_start_pvmd (int argc, char **argv, int block).

14

Page 15: Apuntes PVM

○ argc: nº de argumentos en argv.○ argv: array de parámetros que se pasan al demonio. Nombre de un host_file.○ block:

■ block<>0: la rutina ha de esperar hasta que todos los comutadores indicados en el host_file se incorporen.

■ block=0: permite continuar la ejecución del programa.■ info: devuelve 0 si la rutina se ejecuta con éxito.

5.4.3 Funciones de información● int tid = pvm_mytid();

● int tid = pvm_parent();

○ Devuelve el TID del padre o el valor PvmNoParent si el proceso no fue creado con la función pvm_spawn().

● int info = pvm_config( int *nhost, int *narch, struct pvmhostinfo **hostp);

○ nhost: nº de computadores que forman la máquina virtual.

○ narch: nº de diferentes formatos de datos que se están utilizando.

○ hostp: puntero a un array de estructuras del tipo pvm hostinfo que proporciona la siguiente información sobre cada computador:

■ int hi_tid: DTID del demonio.

■ char *hi_name: array de caracteres con el nombre del computador.

■ char *hi_arch: array de caracteres con el nombre de la arquitectura.

■ int hi_speed: velocidad relativa del computador.

struct pvmhostinfo *computadores;int i, nhost, narch; info = pvm_config( &nhost, &narch, &computadores );printf ("Número de nodos que componen la PVM: %d\n", nhost);printf ("Tipos de arquitecturas que componen la PVM: %d\n", narch); for (i = 0; i < nhost; i++) { printf("Nombre: %s\n", computadores[i].hi_name); printf("DTID: %x\n", computadores[i].hi_tid); printf("Arquitectura: %s\n", computadores[i].hi_arch);}

Ejemplo

● int info = pvm_tasks (int which, int *ntask, struct pvmtaskinfo **taskp);○ Proporciona información sobre las tareas PVM que se están ejecutando en la máquina virtual.○ which

■ 0: solicita información de todas las tareas.■ DTID: solicita información de las tareas asociadas a ese demonio.■ TID genérico para una tarea concreta.

○ ntask: nº de tareas de las que se devuelve información.○ taskp: puntero a un array de tamaño ntask de estructuras del tipo pvmtaskinfo.

■ int ti_tid: TID de la tarea.■ int ti_ptid: TID de la tarea padre.■ int ti_host: TID del demonio bajo el que se ejecuta la tarea.■ int ti_flag: indicador del estado de la tarea.■ char *ti_a_out: cadena de caracteres con el nombre de la tarea.

struct pvmtaskinfo *taskp;int i, ntask; info = pvm_tasks( 0, &ntask, &taskp );

15

Page 16: Apuntes PVM

printf("Total tareas en PVM: %d\n", ntask); for (i = 0; i < ntask; i++) { printf("TID tarea: %x\n", taskp[i].ti_tid); printf("TID tarea padre: %x\n", taskp[i].ti_ptid); printf("TID demonio: %x\n", taskp[i].ti_host); printf("Nombre de la tarea: %s\n", taskp[i].ti_a_out);}

Ejemplo● int info = pvm_perror (char *msg);

○ Imprime información sobre el error producido en la última llamada a una función de PVM.○ msg: mensaje adicional que se concatena a la información generada por la rutina.

● int status = pvm_pstat (in tid)

○ Proporciona información sobre el estado de la tarea de identificador tid.

● int mstat = pvm_mstat (char *host)○ Proporciona infromación sobre el estado del computador host.

● int oldval = pvm_setopt (int what, int val)

○ Rutina de propósito general para el cambio de ciertas opciones que determinan el funcionamiento de la máquina virtual.

○ Algunas opciones: impresión automática de errores, nivel de depuración, enrutamiento de los mensajes...

● int val = pvm_getopt (int what)○ Rutina de propósito general que permite obtener información sobre la configuración de la máquina virtual.

5.4.4 Funciones de configuración dinámica de la máquina virtual● int info = pvm_addhosts (char **hosts, int nhost, int *infos)

○ Rutina para la inclusión de nhost nuevos computadores en la máquina virtual.○ hosts: array de cadenas de caracteres con el nombre de los computadores a incluir en la máquina virtual.○ nhost: nº de computadores a añadir.○ infos: array con los códigos de estado de cada uno de los computadores indicados en el array hosts.○ info:

■ info=nhost: todos los computadores se han añadido.■ 1<=info<nhost: se ha producido algún fallo. ==> análisis de infos.■ info<1: no se ha añadido ningún computador.

16

Page 17: Apuntes PVM

● int info = pvm_delhosts (char **hosts, int nhost, int *infos)○ Rutina para la eliminación de nhost computadores de la máquina virtual.

5.4.5 Funciones de señalización● int info = pvm_sendsig (int tid, int signum);

○ Rutina para el envío de una señal signum a la tarea PVM asociada al tid. Si se envía con éxito la seál info=0.

● inf info = pvm_notify (int what, int msgtag, int cnt, int *tids);○ Función que envía un mensaje a la tarea que lo invoca cuando suceden determinados eventos en un conjunto

específico de tareas.■ what: establece el evento al que hay que prestar atención.

■ msgtag: etiqueta del mensaje que se envía a la tarea que ha invocado la rutina.■ cnt: especifica la long. del array cuando se usan las opciones PvmTaskExit y PvmHostDelete. Cuando se

usa la opción PvmHostAdd, se indica las veces que hay que avisar.■ tids: lista de los TIDs de las tareas y demonios que hay que observar. El array está vacío si se usa la opción

PvmHostAdd

info = pvm_notify( PvmTaskExit, 100, contador, array_tids ); % Establecimiento de la notificación.pvm_notify( PvmTaskExit, 9999, contador, arraytids );. . . . . .. . . . . . % Cancelación de la notificación.pvm_notify( PvmTaskExit | PvmNotifyCancel, 9999, contador, arraytids );

Ejemplo5.4.6 Funciones de control de buffer● Pasos para el envío de un mensaje de una tarea PVM:

○ Inicialización de un buffer de envío○ Empaquetamiento del mensaje en el buffer○ Envío del mensaje

● Pasos para la recepción de un mensaje por una tarea:○ Recepción mensaje (modo bloqueante o no bloqueante).○ Desempaquetamiento de los datos.

● Inicialmente para cada tarea PVM se crea un buffer activo de envío y otro de recepción.● El programador puede crear más buffer pero sólo puede haber uno activo en cada instante.

● int bufid = pvm_initsend (int encoding);

○ Limpia el buffer de envío activo.○ bufid: identificador del buffer activo.

17

Page 18: Apuntes PVM

○ encoding: indica el método de codificación.■ PvmDataDefault: formato XDR (adecuado para entornos heterogéneos).■ PvmDataRaw: sin codificación (sólo posible si los computadores tienen formatos de datos compatibles si

no dará error en el desempaquetado).■ PvmDataInPlace: en el buffer se almacenan únicamente punteros a los datos y sus tamaños,

manteniendo los datos almacenados en el espacio de datos del usuario. Los datos han de estar en posiciones contiguas de memoria y no deben ser modificados entre el empaquetado y envío.

● int bufid = pvm_mkbuf (int encoding)

○ Crea un buffer de envío vacío.

● int info = pvm_freebuf (int bufid)○ Se emplea para liberar la memoria asignada al buffer bufid cuando no vaya a ser utilizado más.

● int bufid = pvm_getsbuf ()

○ Devuelve en bufid el identificador del buffer activo de envío.

● int bufid = pvm_getrbuf ()○ Devuelve en bufid el identificador del buffer activo de recepción.

● int oldbuf = pvm_setsbuf (int bufid)

○ Establece como buffer activo de envío el identificado por bufid.○ oldbuf: valor del buffer de envío activo antes de invocar la rutina.

● int oldbuf = pvm_strbuf (int bufid).

○ Establece como buffer activo de recepción el identificado por bufid.○ oldbuf: valor del buffer de recepción activo antes de invocar la rutina.

5.4.7 Funciones de empaquetado y desempaquetado de datos● Argumentos de las rutinas de empaquetado:

○ Puntero al primer elemento del arreglo a empaquetar.○ nitem: total de elementos a empaquetar. ○ stride: establece la distancia entre dos elementos consecutivos a empaquetar.

■ stride = 2 de cada dos elementos se empaqueta 1.● Formato genérico de las funciones más importantes:

○ int info = pvm_pkXXX (YYY *datos, int nitem, int stride)○ int info = pvm_upkXXX (YYY *datos, int nitem, int stride)

■ XXX: tipo de datos de PVM que se va a enviar.■ YYY: tipo de datos C del array a empaquetar.

○ int info = pvm_pkstr (char *cadena)○ int info = pvm_upkstr (char *cadena)

18

Page 19: Apuntes PVM

5.4.8 Funciones para el envío y recepción de mensajes● a) Datos a enviar son de distinto tipo:

○ Necesariamente tienen que ser empaquetados antes de ser colocados en un buffer de envío de PVM.○ pvm_send (): envío no bloqueante.○ pvm_recv (): recepción bloqueante.

■ Crea un nuevo buffer de recepción activo para el mensaje que llega.○ pvm_nrecv (): recepción no bloqueante.

● b) Datos a enviar son del mismo tipo:○ Se emplea pvm_psend() y pvm_precv(). Estas rutinas conllevan el empaquetamiento/envío o

desempaquetamiento/recepción.

19

Page 20: Apuntes PVM

● c) Modos de empaquetamiento de datos de PVM:

● d) Descripción de las rutinas:

● int info = pvm_send (int tid, int msgtag)○ info = pvm_initsend (PvmDataDefault);○ info = pvm_pkint( array, 10, 1);○ info = pvm_send( tid, -1)

● int info = pvm_psend (int tid, int msgtag, void *buf, int len, int type);

○ Valores del argumento type:

20

Page 21: Apuntes PVM

● int info = pmv_mcast (int *tids, int ntask, int mstag)○ Rutina no-bloqueante que envía el mensaje previamente empaquetado en el buffer activo a un grupo de ntask

tareas identificado por el array tids).○ msgtag ha de ser mayor o igual que 0.

info = pvm_initsend( PvmDataRaw);info = pvm_pkint( array, 10, 1); etiqueta = 5;info = pvm_mcast( tids, ntask, etiqueta);

?● int bufid = pvm_recv (int tid, int msgtag);

○ bufid: identificador del buffer de recepción activo que ha sido creado y que contiene el mensaje recibido. Si se ha producido un error en la recepción devuelve un valor inferior a 0.

tid = pvm_parent();bufid = pvm_recv( tid, -1);info = pvm_upkint( tids, 10, 1);info = pvm_upkint( tamanio_problema, 1, 1);info = upkfloat( array_entrada, 100, 1);

● int bufid = pvm_nrecv( int tid, int msgtag); tid = pvm_parent ();bufid = pvm_nrecv( tid, -1);if (bufid){ info = pvm_upkint (tids, 10, 1); info = pvm_upkint (tam_prob, 1, 1); info = pvm_upkfloat (array, 100, 1);} else /*Realizar otras operaciones */?

● int bufid = pvm_trecv (int tid, int msgtag, struct timeval *timeout)○ Permite fijar un tiempo máximo de espera para la recepción del mensaje.

● int bufid = pvm_probe (int tid, int msgtag);

○ Rutina no-bloqueante que sólo devuelve un identificador del buffer en el bufid como notificación de que el mensaje ha llegado.

○ Si el mensaje no ha llegado a la tarea receptora la rutina devuelve 0. tid = pvm_parent ();etiqueta = 4;recibido = pvm_probe( tid, etiqueta);if (recibido)bufid = pvm_recv(tid, etiqueta);else

21

Page 22: Apuntes PVM

/*Realizar otras operacione*/?

● int info = pvm_bufinfo (int bufid, int *bytes, int *mstag, int *tid)○ Permite obtener información del mensaje almacenado en el buffer bufid.○ bytes: long. del cuerpo del mensaje en bytes.○ msgtag: etiqueta del mensaje.○ tid: identificador de la tarea origen del mensaje.

bufid= pvm_recv (-1, -1);info = pvm_bufinfo( bufid, &long, &tipo, &tid)

● int info = pvm_precv (int tid, int msgtag, void *buf, int len, int type, int *rtid, int *rtag, int *rlen)○ tid: identificador tarea origen (comodín –1)○ msgtag: etiqueta○ buf: puntero al array en que almacenamos el mensaje recibido.○ len: tamaño del array (múltiplo del tamaño del tipo de datos).○ type: tipo de los datos del array.

o rtid: identificador de la tarea que ha enviado el mensaje.o rtag: etiqueta del mensaje recibido.o rlen: long. del mensaje recibido.o info: éxito info=0, fracaso info<0

5.4.9 Funciones para operaciones colectivas● PVM Group Server (pvmgs): se activa al invocarse la primera función colectiva. ● Biblioteca de grupos: libgpvm3.a● Agrupamiento dinámico: permite que existan varios grupos de tareas simultáneamente y que una tarea forme parte de

varios grupos a la vez. ● Las llamadas a funciones colectivas pueden producir resultados imprevistos dependiendo de si una tarea abandona o entra

en el grupo.● int inum = pvm_joingroup (char *group)

○ inum: instancia (nº de orden de la tarea en el grupo. Si n es el nº de tareas dentro del grupo, 0<=inum<=n-1.○ Las tareas que se desunen del grupo y se vuelven a unir pueden que no obtengan el nº de instancia que tenían.

PVM intenta rellenar huecos con los nº de instancia de los miembros del grupo que lo han abandonado.○ Códigos de error que pueden ser devueltos en inum:

22

Page 23: Apuntes PVM

● int info = pvm_lvgroup (char *group)○ Códigos de error que pueden ser devueltos por info:

● int tid = pvm_gettid (char *group, int inum)○ Obtiene el tid de la tarea que tiene asignado el nº inum en el grupo group.

● int inst = pvm_getinst(char *group, int inum)● int size = pvm_getsize (char *group)● int info = pvm_barrier (char *group, int count)

○ La tarea se bloquea hasta que count miembros de group han invocado esta función.○ Se produce un error si las tareas que llaman a la función usan un valor de count distinto.○ Normalmente se usa count=(nº miembros del grupo).

■ count=-1 PVM usa el valor obtenido con pvm_ ■ info = 0 éxito. info<0 errores.

● int info = pvm_bcast (char *group, int msgtag)○ No-bloqueante.○ Envía el mensaje almacenado en el buffer activo a todos los procesos que forman parte de group excepto a la

tarea que invoca la función.○ Se puede invocar la función sin pertenecer al grupo.

info = pvm_initsend( PvmDataRaw);info = pvm_pkint( array, 10, 1);etiqueta = 5;info = pvm_bcast (“grupo”, etiqueta);

● int info = pvm_reduce(void (*func) (), void *data, int count, int datatype, int msgtag, char *group, int rootginst)

○ No-bloqueante.○ Debe ser invocada por todas las tareas que forman el grupo.○ Puede ser necesario llamar a pvm_barrier para sincronizar las tareas implicadas.○ func: función que define la operación a realizar sobre los datos. PvmMax, PvmMin, PvmSum y PvmProduct. Se

pueden usar funciones definidas por el usuario.

● void func (int *datatype, void *data, void *y, int *count, int * info)○ y: valores recibidos de las otras tareas implicadas en la función pvm_reduce.○ data: puntero a la dirección del array que contiene los valores locales. Al terminar el proceso root tendrá el

resultado final de la operación.○ count: nº de elemntos del array.○ rootginst: instancia de la tarea root.

Número de órden de la tarea Contenido del vector de datos

23

Page 24: Apuntes PVM

0 1,2,3,4,5

1 10,20,30,40,50

2 100,200,300,400,500

tarea_root = 1; info = pvm_reduce( PvmSum, &datos, 5, PVM_INT, msgtag, “calculador, tarea_root); Resultado después de la op.:

Número de órden de la tarea Contenido del vector de datos

0 No definido

1 111,222,333,444,555

2 No definido

tarea_root = 1; info = pvm_reduce( multiplicar, &datos, 5, PVM_INT, msgtad, “calculador”, tarea_root); void multiplicar( int *datataype, double *x, double y, int *num, int *info){ int i; for (i = 0; i< num; i++) x[i]*=y[i];} Resultado después de la op.:

Número de órden de la tarea Contenido del vector de datos

0 No definido

1 1000,8000,27000,64000,75000

2 No definido

Ejemplo

● int info = pvm_scatter (void *result, void *data, int count, int datatype, int msgtag, char *group, int rootginst)○ La tarea root envía a cada una de las tareas del grupo, incluida la que inicia el envío, una sección del array.

info = pvm_scatter(&getmyrow, &matriz, 10, PVM_INT, etiqueta, “grupo”, raiz)

● int pvm_gather( void *result, void *data, int count, int datatype, int msgtag, char *group, int rootginst)

○ Rutina para que la tarea root reciba un mensaje de cada uno de los integrantes del grupo, incluido ella, y recopile toda la información enviada en un único array.

○ pvm_gather es no bloqueante. Si una tarea llama a pvm_gather y abandona posteriormente el grupo antes de que la raíz haya llamado a pvm_gather puede ocurrir un error.

24

Page 25: Apuntes PVM

5.5 Ejemplos PVM

5.5.1 Padre-Hijo

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() {

int tid;int Hijos[2]; tid=pvm_mytid(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); return -1;}

printf("Soy el proceso padre con ID: %d. Ahora voy a lanzar 2 hijos\n", tid); if (pvm_spawn("plantilla-hijo", NULL, PvmTaskDefault, 0, 2, Hijos) != 2) {

printf("ERROR lanzando la ejecucion de los procesos hijo\n"); pvm_exit(); return -1;} printf("Soy el proceso padre, Todo fue bien. Terminamos\n");pvm_exit(); return 0;

}

Fichero PADRE

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() { int tid, parent_tid; tid=pvm_mytid(); parent_tid=pvm_parent(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); pvm_exit(); return -1; } printf("Soy un proceso hijo, de identificador %d\n", tid); printf("El identidicador del padre es %d\n", parent_tid); pvm_exit(); return 0;}

Fichero HIJO

25

Page 26: Apuntes PVM

5.5.2 Envío de mensajes

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() { int tid; int Hijos[2]; int temporal; tid=pvm_mytid(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); return -1; } if (pvm_spawn("comunica-hijo", NULL, PvmTaskDefault, 0, 2, Hijos) != 2) { printf("ERROR lanzando la ejecucion de los procesos hijo\n"); pvm_exit(); return -1; } printf("Soy el proceso padre. Voy a enviar un entero a cada hijo\n"); /* Inicializando el buffer */ if (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"); pvm_exit(); return -1; } /* Colocando la informacion en el buffer */ temporal=1; if (pvm_pkint(&temporal, 1, 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"); pvm_exit(); return -1; } /* Envio la informacion a un hijo */ if (pvm_send(Hijos[0], 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 1\n"); pvm_exit(); return -1; } /* Inicializando el buffer. Necesario porque no se borra */ /* Prueba a comentar esta seccion y vera como el hijo 2 */ /* Recibe un 1 en vez de un 2. Si la comenta prueba a que */ /* el hijo 2 realice dos operaciones pvm_recv y vera como */ /* el primer dato es 1 y el segundo 2 */ if (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"); pvm_exit(); return -1; } /* Colocando la informacion en el buffer */ temporal=2; if (pvm_pkint(&temporal, 1, 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"); pvm_exit(); return -1; } /* Envio la informacion a un hijo */ if (pvm_send(Hijos[1], 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 2\n"); pvm_exit(); return -1;

26

Page 27: Apuntes PVM

} printf("Soy el proceso padre. Todo fue bien. Terminamos\n"); pvm_exit(); return 0;}

Envío de mensajes MAESTRO

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() { int tid, parent_tid; int temporal; tid=pvm_mytid(); parent_tid=pvm_parent(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); pvm_exit(); return -1; } if(pvm_recv(parent_tid, 2) < 0) { printf("Error al recibir datos, fin"); pvm_exit(); return -1; } if(pvm_upkint(&temporal, 1, 1) < 0) { printf("Error al leer el primer dato de buffer y fin\n"); pvm_exit(); return -1; } printf("Soy el hijo %d y he recibido de %d lo siguiente: %d\n", tid, parent_tid, temporal); pvm_exit(); return 0;}

Envío de mensajes HIJO

27

Page 28: Apuntes PVM

5.5.3 Uso de grupos

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() { int tid, tid_grupo; int Hijos[2]; int temporal; /* Conectando con PVM */ tid=pvm_mytid(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); return -1; } /* Soy el padre. Creo el Grupo de nombre CyP */ if (pvm_joingroup("CyP") < 0) { printf("ERROR al crear el padre el grupo de nombre CyP\n"); pvm_exit(); return -1; } /* guardo mi tid en el grupo. Soy el padre luego se que es 0 */ tid_grupo= pvm_getinst("CyP", tid); if (pvm_spawn("grupos-hijo", NULL, PvmTaskDefault, 0, 2, Hijos) != 2) { printf("ERROR lanzando la ejecucion de los procesos hijo\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } printf("Soy el proceso padre. Voy a enviar un entero a cada hijo\n"); /* Sincronismo de entrada con el grupo. Andes de cualquier operacion con el grupo conviene estar seguros de que todos los procesos del grupo han conseguido unirse correctamente. En nuestro caso somos */ /* 3: el padre y dos hijos */ if ( pvm_barrier("CyP", 3) < 0) { printf("Problemas en el Padre en sincronismo de entrada al grupo\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } /* Inicializando el buffer */ if (pvm_initsend(PvmDataDefault) < 0) { printf("Problemas en el Padre al inicializar el buffer\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } /* Colocando la informacion en el buffer */ temporal=1; if (pvm_pkint(&temporal, 1, 1) < 0) { printf("Problemas en el Padre al manipular el buffer\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } /* Envio la informacion a un hijo */ if (pvm_send(pvm_gettid("CyP", 1), 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 1\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1;

28

Page 29: Apuntes PVM

} if (pvm_send(pvm_gettid("CyP", 2), 2) < 0) { printf("Problemas en el Padre al enviar el buffer al hijo 2\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } printf("Soy el proceso padre. Todo fue bien. Terminamos\n"); /* Sincronismo de salida con el grupo. Andes de abandonar el grupo conviene estar seguros de que todos las operaciones entre procesos del grupo han concluido correctamente. */ if (pvm_barrier("CyP", 3) < 0) { printf("Problemas en el Padre en sincronismo de salida de grupo\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } /* Notifico a PVM que abandono el grupo */ pvm_lvgroup("CyP"); /* Notifico a PVM que abandono la maquina virtual */ pvm_exit(); return 0;}

Uso de grupos MAESTRO

#include <stdio.h>#include <stdlib.h>#include <pvm3.h>

int main() { int tid, parent_tid, tid_grupo; int temporal; tid=pvm_mytid(); parent_tid=pvm_parent(); if (tid < 0) { printf("No puedo conectarme con PVM\n"); pvm_exit(); return -1; } /* Soy un hijo. Me uno al grupo de nombre CyP */ if (pvm_joingroup("CyP") < 0) { printf("ERROR al unise al grupo CyP un hijo\n"); pvm_exit(); return -1; } /* guardo mi tid en el grupo */ tid_grupo= pvm_getinst("CyP", tid); printf("Soy un hijo. Mi ID en PVM es %d y mi ID en el grupo %d\n", tid, tid_grupo); /* Sincronismo de entrada con el grupo. Andes de cualquier operacion */ /* con el grupo conviene estar seguros de que todos los procesos del */ /* grupo han conseguido unirse correctamente. En nuestro caso somos */ /* 3: el padre y dos hijos */ if (pvm_barrier("CyP", 3) < 0) { printf("Problemas en un hijo en sincronismo de entrada al grupo\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } if(pvm_recv(pvm_gettid("CyP", 0), 2) < 0) { printf("Error al recibir datos, fin"); pvm_exit(); return -1;

29

Page 30: Apuntes PVM

} if(pvm_upkint(&temporal, 1, 1) < 0) { printf("Error al leer el primer dato de buffer y fin\n"); pvm_exit(); return -1; } printf("Soy el hijo %d y he recibido de %d lo siguiente: %d\n", tid, parent_tid, temporal); /* Sincronismo de salida con el grupo. Andes de abandonar el grupo conviene estar seguros de que todos las operaciones entre procesos del grupo han concluido correctamente. */ if (pvm_barrier("CyP", 3) < 0) { printf("Problemas en un hijo en sincronismo de salida de grupo\n"); pvm_lvgroup("CyP"); pvm_exit(); return -1; } /* Notifico a PVM que abandono el grupo */ pvm_lvgroup("CyP"); pvm_exit(); return 0;}

Envío de mensajes ESCLAVO

30

Page 31: Apuntes PVM

5.5.4 Información de la PVM

#include <stdio.h>#include "pvm3.h" #define USO "infor n"#define MAX_TAREAS 10#define MUERTO 10 int main (int argc, char* argv[]) { int mytid, myparent; struct pvmhostinfo *PVM; struct pvmtaskinfo *taskp; int info, i, nhost, narch, j, ntask, tareas_lanzadas, datos, buffer; int array_tids[MAX_TAREAS]; int tareas = 3; mytid = pvm_mytid(); myparent = pvm_parent(); if (myparent == PvmNoParent) { /* Soy el padre */ if (argc == 2) tareas = atoi (argv[1]); if ((tareas < 1) || (tareas > MAX_TAREAS)) { pvm_exit (); printf ("\nError: Número de tareas debe ser mayor de 1 y menor de %d\n", MAX_TAREAS); exit (0); } info = pvm_config( &nhost, &narch, &PVM); printf ("\nNúmero de nodos que componen la PVM: %d\n", nhost); printf ("Tipos de arquitecturas que componen la PVM: %d\n", narch); tareas_lanzadas = pvm_spawn (argv[0], (char**)0, PvmTaskDefault, 0, tareas, array_tids); printf ("Tareas PVM lanzadas con éxito: %d\n", tareas_lanzadas); if (tareas_lanzadas == 0) { pvm_exit (); exit (-1); } for (i = 0; i < tareas_lanzadas; i++) printf ("\tTID %d: %x.\n", (i+1), array_tids[i]); for (i = 0; i < nhost; i++) { printf("\nNodo %d: DTID:%x", i+1,PVM[i].hi_tid); printf ("\n\tNombre: %s", PVM[i].hi_name); printf ("\n\tARQ: %s\n", PVM[i].hi_arch); info = pvm_tasks(PVM[i].hi_tid, &ntask,&taskp); printf("\tTareas PVM: %d\n\n", ntask); for (j = 0; j < ntask; j++) { printf("\t\tTID tarea: %x\n",taskp[j].ti_tid); printf("\t\tTID tarea padre: %x\n",taskp[j].ti_ptid); printf("\t\tTID demonio: %x\n",taskp[j].ti_host); printf("\t\tNombre tarea: %s\n",taskp[j].ti_a_out); } } printf ("\nIniciando el asesinato de las tareas:\n"); pvm_initsend(PvmDataDefault); info = pvm_mcast (array_tids, tareas, 0); if (info < 0) { printf ("\nError al hacer pvm_mcast a las %d tareas.\n", tareas); pvm_exit(); exit(-1); } for (i = 0; i < tareas_lanzadas; i++) { buffer = pvm_recv (-1, MUERTO);

31

Page 32: Apuntes PVM

pvm_upkint (&datos, 1, 1); printf ("\tTarea %x muerta.\n", datos); } pvm_exit(); exit (0); } /* Soy el hijo */ buffer = pvm_recv (myparent, -1); pvm_initsend (PvmDataDefault); pvm_pkint (&mytid, 1, 1); pvm_send (myparent, MUERTO); pvm_exit (); exit (0); }

Información de la PVM

32

Page 33: Apuntes PVM

5.5.5 Producto escalar de dos vectores

#include <stdio.h>#include <stdlib.h>#include "pvm3.h" #define USO "padre_pe longitud_de_los_vectores"#define ESCLAVO "hijo_pe" int main(int argc, char *argv[]) { int i, info, Nlocal, narch, N_NODOS; int mytid = pvm_mytid(); int N = atoi(argv[1]); int *array_tids; struct pvmhostinfo *hostp; double *vector_a, *vector_b, producto_escalar; pvm_config(&N_NODOS, &narch, &hostp); printf("La máquina PVM está compuesta por %d computadores\n", N_NODOS); array_tids = (int *)malloc(N_NODOS * sizeof(*array_tids)); Nlocal = (float)(N + N_NODOS - 1) / N_NODOS; N = Nlocal * N_NODOS; vector_a= (double *)malloc (N * sizeof (*vector_a)); vector_b= (double *)malloc (N * sizeof (*vector_b)); for (i = 0; i < N; i++) { vector_a[i] = rand() / (float)RAND_MAX; vector_b[i] = rand() / (float)RAND_MAX; } info = pvm_spawn (ESCLAVO, (char **)0, PvmTaskDefault, 0, N_NODOS, array_tids); /* Envío de la información a los esclavos */ for (i = 0; i < N_NODOS; i++) { pvm_initsend (PvmDataDefault); pvm_pkint (&Nlocal, 1, 1); pvm_pkdouble (&vector_a[i * Nlocal], Nlocal, 1); pvm_pkdouble (&vector_b[i * Nlocal], Nlocal, 1); pvm_send (array_tids[i], 1000); } /* Recepción de resultados parciales y suma total */ producto_escalar = 0; for (i = 0; i < N_NODOS; i++) { double suma_parcial = 0; pvm_recv (-1, 2000); pvm_upkdouble (&suma_parcial, 1, 1); producto_escalar += suma_parcial; } printf("Longitud vectores= %d\n",N); printf ("Vector A: "); for (i=0; i < N; i++) printf (" %f", vector_a[i]); printf ("\nVector B: "); for (i=0; i < N; i++) printf (" %f", vector_b[i]); printf("\nProducto escalar= %f con N_NODOS= %d\n", producto_escalar, N_NODOS); free (vector_a); free (vector_b); free (array_tids); pvm_exit(); exit (0);}

Producto escalar de dos vectores PADRE

#include "pvm3.h"

33

Page 34: Apuntes PVM

int main(void) { int I, Nlocal, padre; double *vector_a, *vector_b, suma_parcial; /* Recepción de los datos del padre */ padre = pvm_parent (); pvm_recv (padre, 1000); pvm_upkint (&Nlocal, 1, 1); vector_a = (double *)malloc( Nlocal * sizeof(*vector_a)); vector_b = (double *)malloc( Nlocal * sizeof(*vector_b)); pvm_upkdouble (vector_a, Nlocal, 1); pvm_upkdouble (vector_b, Nlocal, 1); /* Cálculo de la suma parcial */ suma_parcial = 0; for ( i = 0; i < Nlocal; i++) suma_parcial += vector_a[i] * vector_b[i]; /* Envío de resultado al maestro */ pvm_initsend (PvmDataDefault); pvm_pkdouble (&suma_parcial, 1, 1); pvm_send (padre, 2000); free(vector_a); free(vector_b); pvm_exit(); return 0}

Producto escalar de dos vectores HIJO

34

Page 35: Apuntes PVM

5.5.6 Producto de dos matrices cuadradas

#include <stdio.h>#include <stdlib.h>#include "pvm3.h" #define USO "mul_mat M"#define GRUPO "MUL"#define ETI_DATOS 1000#define ETI_REPARTO 2000#define ETI_RECOGIDA 3000 int main(int argc, char *argv[]) { int i, j, k, m, info, N_TAREAS, N_MEZCLA, instancia, N = 3; int *matriz_a, *matriz_b, *matriz_c, *mezcla, *mezcla_resultados, *array_tids, *fila_columna; int elemento[3]; if (pvm_parent () == PvmNoParent) { instancia = pvm_joingroup (GRUPO); if (argc > 1) N = atoi(argv[1]); N_TAREAS = N*N-1; N_MEZCLA = 2 * (N*N*N + N*N); matriz_a = (int *)malloc(N * N * sizeof(int)); matriz_b = (int *)malloc(N * N * sizeof(int)); matriz_c = (int *)malloc(N * N * sizeof(int)); mezcla = (int *)malloc(N_MEZCLA * sizeof(int)); mezcla_resultados = (int *)malloc(3 * N * N * sizeof(int)); array_tids = (int *)malloc(N_TAREAS * sizeof(int)); for (i=0; i<N*N; i++) { matriz_a[i] = (rand()/(float) RAND_MAX) * 10; matriz_b[i] = (rand()/(float) RAND_MAX) * 10; } k = 0; for (i=0; i<N; i++) { for (j=0; j<N; j++) { mezcla[k] = i+1; k++; for (m=0; m<N; m++) { mezcla[k] = matriz_a[i*N+m]; k++; } mezcla[k] = j+1; k++; for (m=0; m<N; m++) { mezcla[k] = matriz_b[m*N+j]; k++; } } } printf ("Matriz A:\n"); for (i=0; i<N; i++) { for (j=0; j<N; j++) printf ("\t%d", matriz_a[i*N+j]); printf ("\n"); } printf ("Matriz B:\n"); for (i=0; i<N;i++) { for (j=0; j<N; j++) printf ("\t%d",matriz_b[i*N+j]); printf ("\n"); } info = pvm_spawn (argv[0], (char **)0, PvmTaskDefault, 0, N_TAREAS, array_tids); printf ("\nEjecutándose %d tareas más el padre. Total: %d.\n", info, info+1);

35

Page 36: Apuntes PVM

if (info != N_TAREAS) { pvm_perror ("No se han creado todas las tareas.\n"); pvm_lvgroup (GRUPO); pvm_halt (); return -1; } pvm_initsend (PvmDataDefault); pvm_pkint (&N, 1, 1); pvm_mcast (array_tids, N_TAREAS, ETI_DATOS); pvm_barrier (GRUPO, N_TAREAS+1); info = pvm_scatter(fila_columna, mezcla, 2*(1+N), PVM_INT, ETI_REPARTO, GRUPO, instancia); elemento[0] = fila_columna[0]; elemento[1] = fila_columna[N+1]; elemento[2] = 0; for (i=0 ; i<N; i++) elemento[2] += fila_columna[i+1] * fila_columna [i+2+N]; info = pvm_gather (mezcla_resultados, elemento, 3, PVM_INT, ETI_RECOGIDA, GRUPO, instancia); for (i=0; i<3*N*N; i=i+3) { j = N * (mezcla_resultados[i]-1) + (mezcla_resultados[i+1]-1); matriz_c[j] = mezcla_resultados [i+2]; } printf ("Matriz C:\n"); for (i=0; i<N; i++) { for (j=0; j<N; j++) printf ("\t%d", matriz_c[i*N+j]); printf ("\n"); } pvm_barrier (GRUPO, N_TAREAS+1); } else { /* Soy el hijo */ pvm_joingroup (GRUPO); pvm_recv (pvm_parent(), ETI_DATOS); pvm_upkint (&N, 1, 1); N_TAREAS = N * N; N_MEZCLA = 2 * (N * N * N + N * N); fila_columna = (int *)malloc ( 2*(1+N) * sizeof(int)); pvm_barrier (GRUPO, N_TAREAS); info = pvm_scatter(fila_columna, 0, 2*(N+1), PVM_INT, ETI_REPARTO, GRUPO, pvm_getinst(GRUPO, pvm_parent())); elemento[0] = fila_columna[0]; elemento[1] = fila_columna[N+1]; elemento[2] = 0; for (i=0 ; i<N; i++) elemento[2] += fila_columna[i+1] * fila_columna [i+2+N]; info = pvm_gather (0, elemento, 3, PVM_INT, ETI_RECOGIDA, GRUPO, pvm_getinst(GRUPO, pvm_parent())); pvm_barrier (GRUPO, N_TAREAS); } pvm_lvgroup (GRUPO); pvm_exit(); exit(0);}

Producto de dos matrices cuadradas

36