/*
 *                 	Exemple "Dothost.c" PVM versio 3.3
 *		 Susana Maria Bajo Sanchez (ei05646@salleURL.edu)
 *		 Josep Maria Garrell i Guiu (josepmg@salleURL.edu)
 *				Software Paral.lel
 *		           Departament d'Informatica (DI)
 *	               Enginyeria i Arquitectura La Salle
 *		           Universitat Ramon Llull (URL)
 * 		                  Curs 1999/2000
*/

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

int info;

//----------------------------------------------------------------
int *create_slaves(char *node_exe, int NPROC)
{
int mytid = pvm_mytid();
int *taskid = (int *)malloc(NPROC*sizeof(*taskid));
int msglabel = 0;

	info = pvm_spawn(node_exe,NULL,PvmTaskDefault,"*",NPROC,&taskid[0]);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_spawn()\n");

	// Envia las tablas de taskid a los otros procesos
	info = pvm_initsend(PvmDataDefault);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_initsend()\n");

	info = pvm_pkint(&NPROC,1,1);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_pkint()\n");

	info = pvm_pkint(taskid,NPROC,1);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_pkint()\n");

	info = pvm_mcast(taskid,NPROC,msglabel);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_mcast()\n");

	return taskid;
}

//----------------------------------------------------------------
int main(int argc, char *argv[])
{
int i, j;
int *taskid;
int mytid = pvm_mytid();
int N = atoi(argv[1]);
int Nlocal, narch, NPROC ;
struct pvmhostinfo *hostp;
char *node_exe = "Dotnode";
double *a, *b, dotprod;
	
	info = pvm_config(&NPROC,&narch,&hostp);
	if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_config()\n");

	printf("DOTHOST: Ejecutando en %d procesadores\n",NPROC);
	
	if (NPROC>1)
		{	
		NPROC = NPROC-1;
		Nlocal = (N+NPROC-1)/NPROC;
		}
		else Nlocal= N;

	N = Nlocal*NPROC;
	
	a = (double*)malloc(N*sizeof(*a));
	b = (double*)malloc(N*sizeof(*b));

	for (i=0;i<N;i++)
		{
		a[i] = i+1;
		b[i] = 1.0/(i+1);
		}

	taskid = create_slaves(node_exe,NPROC);

	// Envía los datos a los esclavos
	for (j=0;j<NPROC;j++)
		{
		int msglabel = 1000;
	
		info = pvm_initsend(PvmDataDefault);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_initsend()\n");
	
		info = pvm_pkint(&Nlocal,1,1);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_pkint()\n");

		info = pvm_pkdouble(&a[j*Nlocal],Nlocal,1);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_pkdouble()\n");
	
		info = pvm_pkdouble(&b[j*Nlocal],Nlocal,1);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_pkdouble()\n");

 		info = pvm_send(taskid[j],msglabel);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_send()\n");
		}

	// Lee los resultados parciales y los suma
	dotprod = 0;
	for (j=0;j<NPROC;j++)
		{
		int msglabel = 2000;
		double partial_sum;
		
		info = pvm_recv(-1,msglabel); 	// Recv en cualquier orden
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_recv()\n");

		info = pvm_upkdouble(&partial_sum,1,1);
		if (info<0) pvm_perror("DOTHOST: <ERROR> Despues pvm_upkdouble()\n");

		dotprod += partial_sum;
		}

	printf("N = %d, dotprod = %f with NPROC=%d\n",N,dotprod,NPROC);

	printf("DOTHOST: Saliendo de PVM..\n");
	pvm_exit();	

	return 0;
}

