v15i081: mpsim: MultiProcessor Simulator package

a.e.mossberg aem at mthvax.cs.miami.edu
Mon Oct 15 11:47:54 AEST 1990


Posting-number: Volume 15, Issue 81
Submitted-by: "a.e.mossberg" <aem at mthvax.cs.miami.edu>
Archive-name: mpsim/part01

This is Felix Quevedo's Multiprocessor simultator package which he wrote 
here at the University of Miami. I've provided a nroff'ed version of his
documentation, for those without the ms macros, or perhaps without *roff
itself. 

The package was developed on a Sun 3 running SunOS 3.5 and has been
tested on Sun 4 running SunOS 4.0.3, a vax running Ultrix 3.0, and
a mac running A/UX 1.1  The Makefile needs to be changed for non-SunOS
systems.

Felix can be reached at fqs at mthvax.cs.miami.edu, but he can not provide
any support. 

aem

-------------------------------cut here ------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	mpsim
# This archive created: Sat Oct  6 17:05:05 1990
export PATH; PATH=/bin:$PATH
if test ! -d 'mpsim'
then
	echo shar: creating directory "'mpsim'"
	mkdir 'mpsim'
fi
echo shar: entering directory "'mpsim'"
cd 'mpsim'
echo shar: extracting "'doc.ms'" '(5126 characters)'
if test -f 'doc.ms'
then
	echo shar: will not over-write existing file "'doc.ms'"
else
cat << \SHAR_EOF > 'doc.ms'
.nr PO 1.5i
.sp 2i
.ft B
.ce 2
The MultiProcessor Simulator\(co / Experimental Version 1.0
.sp 2
.ft R
by F\*'elix E. Quevedo Stuva
.sp 4
.ad b
.fi
.ls 2
.NH 1
Introduction
.NH 2
Why a Simulator
.PP
There are several reasons that justifies a Multiprocessor
Simulator, instead of purshising the actual hardware. The first reason 
would be cost, since we assume that a Multiprocessor Computer is expensive.
Well, it is, but not much more than a commercial "Supercomputer".  Another
reason would be the availability of CPU time, but we forget that the
hardware must be running some kind of multiprogramming operating system, that
allows time sharing. So then, what is the need of a simulator if the reasons
for not having a parallel computer are trivial? Well, we must not forget the
great diversity of proposed arquitectures and the fact that we do not have
at this moment a standard hardware and implementation software.
.PP
The spirit for the simulator design, was to have a tool for designing
algorithms without having a parallel computer, regardless of the model or
arquitecture used. This meant a design flexible enough to support the most
important features of most of the parallel computer models: shared memory
and interprocessor networks. From an academic point of view, these two 
features must be handy to test algorithms that requires them.
.NH 2
Outline of the Simulator
.PP
The simulator allows the user to define an environment where to
test parallel algorithms. The user has access to the multiprocessor facilities through user
functions and an interactive environment where to execute the programs.
The user can define a number of pseudoprocessors, each one with one message
queue, and access to a single shared memory segment.
.PP
The message queue defined for a processor can contain any type of data,
including structures.
The creation of shared memory segments is a special feacture reserved for
a host programs. The access is public and with concurrent read and concurrent
write. It is the user the encharged to control the access to the SMS.
By using a layered approach, the user can design the its own parallel
computer model. As observed the simulator tries not to constrait the application
of the user.
.PP
The simulator runs in an UNIX environment with IPC facilities. This is any
UNIX release with System V support.
The number of processors that a user can define depends on the value of the
UNIX system parameter MAXUPRC, on the system program /sys/param.c.
.PP
The simulator has been implemented with all the self controls
considered at that moment. This does not guarantee that a bug could eventually pop.
The only way to avoid such inconvinience is the use of the system.
.NH 2
Unix IPC Facilities
.PP
The Interprocess Communication Facilities of UNIX System V, is the
Simulator's lower layer. The two described feature of a processor, are
actually IPC facilities with a nice user friendly presentation.
.PP
The message queue facility operates with more options than available with
the simulator. It is important to mention a constrain in the number of bytes
that the message queue together can support is defined on the value ot the
UNIX system parameters MSGPOOL, MSGSIZ, MSGNMI, etc; on /sys/h/msg.h.
.NH 2
Suggested Further Implementations
.PP
There are many upgrades that can be made in this first experimental version:
.IP a)
improve the setup and execution (mpload, mprun) functions,
.IP b)
extend the user library with a set of prefixed intercommunication networks;
.IP c)
extend the user library with a interprocess synchronization function;
.IP d)
improve the interactive module, even with windows and graphic support;
.IP e)
research in a programming language interface layer; etc.
.NH 1
Installation
.PP
The Makefile has all the setups necessary to install the simulator, just
type:
.sp
		make
.PP
The final product are two file:
.IP mpsim
: Interactive Multiprocessor Simulator Manager;
.IP libmp.a 
: user loading library.
.PP
To compile a user library just do:
.sp
	cc myfile.c libmp.a [-o myfile] [-lm] ...
.NH 1
Implementation
.PP
The simulator has been implemented on UNIX C. It is transportability
has been proved between a SUN 3/60 and a VaxStation II. In both cases
the main modules were working, but with no guarantee of full feature
capacity.
.PP
The implementation consist of the following files:
.IP a)
mpsim.c: the interactive module. Contains the
.I main()
and the
.I _stop_handler()
functions.
.IP b)
mplib.c: the common function library. Contains the
.I
mpopen(), mptime(), mpprint(), mperro(), mehost(), _mplnode()
.R
functions.
.IP c)
mpsys.c: the system function library. Contains the
.I
_handler_req(), _handler_chl(), _handler_sys(), _mpinit(), _mpkill(),
_mplhost(), _mprun(), _mpstart(), _mpstatus(), _mpterm(),
.R and
_mpwait()
.R
functions.
.IP d)
mpusr.c: the user function library. Contains the
.I
_pause_handler()*, _getpt(), _trchd(), _imhost(), mprnd(), mpdim(),
mynode(), load(), _mvstr(), _rcvm(), recv(), trcv()*, send(), 
probe(), crtshm(), attshm(), detshm()
.R and
slpmsq()*
.R
functions. The ones marked with a * are still on experimental phase.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(635 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
LDIR = scrs
SPRG = $(LDIR)/mpsim
CLIB = $(LDIR)/mplib.o
ULIB = $(LDIR)/mpusr.o
SLIB = $(CLIB) $(LDIR)/mpsys.o 
SDEF = $(LDIR)/mpdef.h
UDEF = $(SDEF) $(LDIR)/mpuser.h
DFLG = -DMULTIPROCLIB

all:
	make sim
	make use
	make clean

sim:
	make $(SPRG)
	mv $(SPRG) .

use:
	make $(ULIB)
	rm -f libmp.a
	ar cr libmp.a $(ULIB) $(CLIB)
	ranlib libmp.a

$(SPRG): $(SDEF) $(SLIB)
	$(COMP) -o $@ $@.c $(SLIB)

$(SLIB): $(SDEF)
	$(COMP) -c $(@:.o=.c) -o $(@)

$(ULIB): $(UDEF) $(CLIB)
	$(COMP) -c $(@:.o=.c) -o $(@)

new:
	rm mpsim libmp.a

prt:
	ptroff -ms -h README

clean:
	rm $(SLIB) $(ULIB)
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'doc.txt'" '(6912 characters)'
if test -f 'doc.txt'
then
	echo shar: will not over-write existing file "'doc.txt'"
else
cat << \SHAR_EOF > 'doc.txt'


                 The MultiProcessor Simulator  / Experimental Version 1.0


                                by Fe'lix E. Quevedo Stuva


               1.  Introduction

               1.1.  Why a Simulator

                    There are several reasons that justifies a Multiproces-
               sor  Simulator,  instead  of purshising the actual hardware.
               The first reason would be cost, since we assume that a  Mul-
               tiprocessor  Computer  is  expensive.   Well, it is, but not
               much more than a commercial "Supercomputer".  Another reason
               would  be  the  availability of CPU time, but we forget that
               the hardware must be running some kind  of  multiprogramming
               operating system, that allows time sharing. So then, what is
               the need of a simulator if the  reasons  for  not  having  a
               parallel  computer are trivial? Well, we must not forget the
               great diversity of proposed arquitectures and the fact  that
               we do not have at this moment a standard hardware and imple-
               mentation software.

                    The spirit for the simulator design, was to have a tool
               for designing algorithms without having a parallel computer,
               regardless of the model or arquitecture used. This  meant  a
               design   flexible  enough  to  support  the  most  important
               features of most of the  parallel  computer  models:  shared
               memory  and  interprocessor networks. From an academic point
               of view, these two features must be handy to test algorithms
               that requires them.

               1.2.  Outline of the Simulator

                    The simulator allows the user to define an  environment
               where  to  test  parallel algorithms. The user has access to
               the multiprocessor facilities through user functions and  an
               interactive  environment where to execute the programs.  The
               user can define a number of pseudoprocessors, each one  with
               one message queue, and access to a single shared memory seg-
               ment.

                    The message queue defined for a processor  can  contain
               any  type  of  data,  including structures.  The creation of
               shared memory segments is a special feacture reserved for  a
               host programs. The access is public and with concurrent read
               and concurrent write. It is the user the encharged  to  con-
               trol  the  access  to the SMS.  By using a layered approach,
               the user can design the its own parallel computer model.  As
               observed  the  simulator tries not to constrait the applica-
               tion of the user.

                    The simulator runs in  an  UNIX  environment  with  IPC
               facilities.  This is any UNIX release with System V support.
               The number of processors that a user can define  depends  on
               the  value of the UNIX system parameter MAXUPRC, on the sys-
               tem program /sys/param.c.

                    The simulator has been implemented with  all  the  self
               controls  considered at that moment. This does not guarantee
               that a bug could eventually pop.  The only way to avoid such
               inconvinience is the use of the system.

               1.3.  Unix IPC Facilities

                    The Interprocess Communication Facilities of UNIX  Sys-
               tem  V,  is  the  Simulator's lower layer. The two described
               feature of a processor, are actually IPC facilities  with  a
               nice user friendly presentation.

                    The message queue facility operates with  more  options
               than  available  with the simulator. It is important to men-
               tion a constrain in the number of  bytes  that  the  message
               queue  together  can  support is defined on the value ot the
               UNIX system parameters  MSGPOOL,  MSGSIZ,  MSGNMI,  etc;  on
               /sys/h/msg.h.

               1.4.  Suggested Further Implementations

                    There are many upgrades that can be made in this  first
               experimental version:

               a)   improve the setup and execution (mpload,  mprun)  func-
                    tions,

               b)   extend the user library with a set of  prefixed  inter-
                    communication networks;

               c)   extend the user library with a interprocess  synchroni-
                    zation function;

               d)   improve the interactive module, even with  windows  and
                    graphic support;

               e)   research in a  programming  language  interface  layer;
                    etc.

               2.  Installation

                    The Makefile has all the setups  necessary  to  install
               the simulator, just type:

                               make

                    The final product are two file:

               mpsim: 	Interactive Multiprocessor Simulator Manager;

               libmp.a:	 user loading library.

                    To compile a user library just do:

                       cc myfile.c libmp.a [-o myfile] [-lm] ...

               3.  Implementation

                    The simulator has been implemented on  UNIX  C.  It  is
               transportability  has  been  proved between a SUN 3/60 and a
               VaxStation II. In both cases the main modules were  working,
               but with no guarantee of full feature capacity.

                    The implementation consist of the following files:

               a)   mpsim.c: the interactive module.  Contains  the  main()
                    and the  stop handler() functions.

               b)   mplib.c: the common function library. Contains the mpo-
                    pen(),   mptime(),   mpprint(),   mperro(),   mehost(),
                     mplnode() functions.

               c)   mpsys.c: the  system  function  library.  Contains  the
                     handler req(),      handler chl(),      handler sys(),
                     mpinit(),  mpkill(),  mplhost(),  mprun(),  mpstart(),
                     mpstatus(),  mpterm(),  mpwait() functions.

               d)   mpusr.c:  the  user  function  library.  Contains   the
                     pause handler()*,    getpt(),    trchd(),    imhost(),
                    mprnd(), mpdim(), mynode(), load(),  mvstr(),   rcvm(),
                    recv(),  trcv()*,  send(), probe(), crtshm(), attshm(),
                    detshm() slpmsq()* functions. The ones marked with a  *
                    are still on experimental phase.

SHAR_EOF
fi # end of overwriting check
if test ! -d 'scrs'
then
	echo shar: creating directory "'scrs'"
	mkdir 'scrs'
fi
echo shar: entering directory "'scrs'"
cd 'scrs'
echo shar: extracting "'mpdef.h'" '(3184 characters)'
if test -f 'mpdef.h'
then
	echo shar: will not over-write existing file "'mpdef.h'"
else
cat << \SHAR_EOF > 'mpdef.h'
/* FQSystems -------------------------------------------------------------------

	File  : mpd.h
			Header file for all system files.
	Title :	MultiProcessor Macro Library.
	Author: Felix E. Quevedo Stuva.
	Date  :	May 12, 1989.

----------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
 * System Macro Includes
 */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>

/* -----------------------------------------------------------------------------
 * Global Macro Defines
 */
#define MAX_PRC 32
#define MIN_PRC 1
#define MSG_LEN 512
#define MAX_WAITC 80000
#define PEMPTY   0x0000
#define PREADY   0x0001
#define PRUNNING 0x0002
#define PBLOCKED 0x0003
#define NIL      -1

/* -----------------------------------------------------------------------------
 * Global Data Type Definition
 */
typedef struct {
	short pno,	/* processor number: 0..MAX_PRC */
		  ppw,  /* pause wait flag: 0 pause, 1 continue */
	      pst;	/* processor status:
			         *     0: empty,
					 *     1: ready,
					 *     2: running,
					 *     3: blocked    */
	int pid,	        /* processor UNIX PID */
		msnd,
		mrcv;
	char cdp[50];	    /* command string pointers */
	long cmi;	        /* Msg queue ID */
	struct rusage rsg;  /* processor resource usage */
} MP_NODE;

typedef struct 	/* MP SHM table */
{
	int mpn,       /* number of active processors */
	    mpr,       /* number of running processors */
	    mpq,       /* processor starting request from host */
		mpm,       /* multiprocessor shared memory id */
		mpf,       /* logfile file descriptor */
		mpt;       /* logfile tracer indicator */
	short mps;	   /* multiprocessor status:
				         *     0: empty,
						 *     1: ready,
						 *     2: running */
	char mpl[50];  /* system log file */
				   /* the following two lines MUST always be together! */
	MP_NODE mph;   /* HOST node */
	MP_NODE prc[MAX_PRC]; /* Processor nodes */
} MP_TBL;

typedef struct
{
	long mtype;
	char mtext[MSG_LEN];
} MSG_FORM;

typedef struct
{
	int  mwho;	/* Who send the message */
	int  mlen;	/* length of the message */
	char *mtxt; /* message text */
} MSG_TXT;

/* -----------------------------------------------------------------------------
 * Global external Functions
 */
extern char *shmat(), *mptime(), *ctime();
extern MP_TBL *getpt();

/* -----------------------------------------------------------------------------
 * Global Variables
 */
#ifndef  _MPLIB_

extern MSG_FORM Smsg,  /* sending message */
	            Rmsg;  /* receiving message */
extern MSG_TXT  *Tmsg; /* general message text */
extern MP_TBL   *Ptbl; /* proccesors table */
extern int MsgKey, MsgId, ShmId, _tout, jmp, mpfd, simpid, simsq;

#else

MSG_FORM Smsg,  /* sending message */
         Rmsg;  /* receiving message */
MSG_TXT  *Tmsg; /* general message text */
MP_TBL   *Ptbl; /* proccesors table */
int MsgKey, MsgId, ShmId, _tout, jmp, mpfd, simpid, simsq;

#endif
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mplib.c'" '(2459 characters)'
if test -f 'mplib.c'
then
	echo shar: will not over-write existing file "'mplib.c'"
else
cat << \SHAR_EOF > 'mplib.c'
/* FQSystems -------------------------------------------------------------------

    File  : mplib.c
    Title : MultiProcessor Functions Libraries
    Author: Felix E. Quevedo Stuva.
    Date  : May 12, 1989

----------------------------------------------------------------------------- */
#define _MPLIB_
#include <varargs.h>
#include "mpdef.h"

long MPclk[1]; /* current time of the day */

mpopen(flg)
int flg;
{
    return open((*Ptbl).mpl, flg, 00644);
}
	
char *mptime()
{
    int i=0;
    char *s, *c;

    time(MPclk);
    c = s = ctime(MPclk)+4;
    for(; *c!='\n'; c++);
    *(c-4) = '\0';

    return s;
}


void mpprint(va_alist)
va_dcl
{
    if(Ptbl && (*Ptbl).mpt) {
        va_list args;
        char *fmt, *whr;
        int l;
        va_start(args);

		whr=Smsg.mtext;
        strcpy(whr, mptime());
        fmt = va_arg(args, char *);
        (void)vsprintf(whr+16, fmt, args);
        va_end(args);
		write((*Ptbl).mpf, whr, strlen(whr));
    }
}


mperror(n, wh)
int n;      /* error number */
char *wh;   /* who am I */
{
    (*Ptbl).mpt=1;
    switch(n) {
    case  1:
        mpprint("%s, MP not Active!!\n", wh);
        printf("%s, MP not Active!!\n", wh);
    break;
    case  2:
        mpprint("%s, MP already active!!\n", wh);
        printf("%s, MP already active!!\n", wh);
    break;
    case  3:
        mpprint("%s, MP could not attach the SHM segment!!\n", wh);
        printf("%s, MP could not attach the SHM segment!!\n", wh);
    break;
    case  4:
        mpprint("%s, MP could not assign a SHM segment!!\n", wh);
        printf("%s, MP could not assign a SHM segment!!\n", wh);
    break;
    case  5:
        mpprint("%s, BAD parameter list!!\n", wh);
        printf("%s, BAD parameter list!!\n", wh);
    break;
    case  6:
        mpprint("%s, Illegal command for node process!\n", wh);
        printf("%s, Illegal command for node process!\n", wh);
    break;
    default:
        mpprint("%s", wh);
        printf("%s", wh);
    break;
    }
    exit(n);
}

mehost()
{
    if ((*Ptbl).mph.pid==getpid())
        return 1;
    return 0;
}

_mplnode(cmd, prcn)
char *cmd;
int prcn;
{
    int i, j;
    if(!cmd) return mperror(5, "Sim: lnode");
    i=(prcn<0)?0:prcn;
    j=(prcn<0)?(*Ptbl).mpn-1:i;
    for(;i<=j;
        strcpy((*Ptbl).prc[i].cdp, cmd),
        (*Ptbl).prc[i].pst = PREADY,
        mpprint("Sim:  NODE %2d, Command %s loaded!\n", i, (*Ptbl).prc[i].cdp),
        i++);
    (*Ptbl).mps=PREADY;
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mpsim.c'" '(5692 characters)'
if test -f 'mpsim.c'
then
	echo shar: will not over-write existing file "'mpsim.c'"
else
cat << \SHAR_EOF > 'mpsim.c'
/* FQSystems -------------------------------------------------------------------

    File  : mpsim.c
    Title : MultiProcessor Simulator Interactive Entry.
    Author: Felix E. Quevedo Stuva.
    Date  : May 31, 1989.

----------------------------------------------------------------------------- */
#include "mpdef.h"
#include <sys/stat.h>
#include <setjmp.h>

struct stat stype[1];
int jmp;
jmp_buf env;

static _stop_handler()
{
    if(!jmp) longjmp(env, 1);
}

#define MPLNODE  1
#define MPLHOST  2
#define MPSTART  3
#define MPLSTART 4
#define MPSTATUS 5
#define MPKILL   6
#define MPLOG    7
#define BADCOM   999

main(ac, ar)
int ac;
char *ar[];
{
    int i=MAX_PRC;
    int nr, j, tc;
    char buf[BUFSIZ], *cmd, *par, *opc, fn[50], *mptime();


    if(ac>1) i = atoi(ar[1]);
    _mpinit(i);
    signal(SIGINT, _stop_handler);

    printf("University of Miami\n");
    printf("Department of Mathematics and Computer Science\n");
    printf("MultiProccessor Simulator - Experimental Ver 1.0\n");
    if (((*Ptbl).mpf=mpopen(O_CREAT | O_WRONLY | O_APPEND))==NIL) {
        printf("Sim: WARNING, NOT able to open default logfile %s!!\n",
            (*Ptbl).mpl);
    }

    setjmp(env);
    jmp=1;
    for(;;)
    {
        for(;;) {
            printf("\nMPSim\/%d >> ", (*Ptbl).mpn);
            nr=(int)fgets(buf, BUFSIZ, stdin);
            if(nr==NULL) _mpterm();
            for(i=0; buf[i]==' ' && i<BUFSIZ; i++);
            if(buf[i]!='\n') break;
        }

        for(i=i, cmd=buf+i, opc=par=0;
            i<BUFSIZ && buf[i]!=' ' && buf[i]!='\n'; i++);
        if(buf[i]==' ' || buf[i]=='\n') {
            buf[i] = 0;
            par = &buf[i]+1;
            for(; *par==' ' && i<BUFSIZ; par++, i++);
            if(*par=='\n')
                *par=0;
            else {
                if(*par=='-') {
                    opc = par+1;
                    for(j=0; i<BUFSIZ && opc[j]!='\n' && opc[j]!=' '; i++, j++);
                    if(opc[j]!='\n') par=opc+j+1;
                    opc[j]=0;
                }
                for(j=0; i<BUFSIZ && par[j]!='\n'; i++, j++);
                if(par[j] =='\n') par[j]=0;
            }
        }
        /*printf("cmd %s, par %s, opc %s\n", cmd, par, opc);*/

        tc=NIL;
        if (!strcmp("lhost", cmd)) tc=MPLHOST;
        else
        if (!strcmp("lh", cmd)) tc=MPLHOST;
        else
        if (!strcmp("lnode", cmd)) tc=MPLNODE;
        else
        if (!strcmp("ln", cmd)) tc=MPLNODE;
        else
        if (!strcmp("start", cmd)) tc=MPSTART;
        else
        if (!strcmp("s", cmd)) tc=MPSTART;
        else
        if (!strcmp("lstart", cmd)) tc=MPLSTART;
        else
        if (!strcmp("ls", cmd)) tc=MPLSTART;
        else
        if (!strcmp("kill", cmd)) tc=MPKILL;
        else
        if (!strcmp("status", cmd)) tc=MPSTATUS;
        else
        if (!strcmp("st", cmd)) tc=MPSTATUS;
        else
        if (!strcmp("log", cmd)) tc=MPLOG;
        else
        if (!strcmp("quit", cmd)) _mpterm();
        else
        if (!strcmp("q", cmd)) _mpterm();
        else
        if (!strcmp("trace", cmd) || !strcmp("t", cmd)) {
            (*Ptbl).mpt=(*Ptbl).mpt?0:1;
            printf((*Ptbl).mpt?"Sim: trace ON\n":"Sim: trace OFF\n");
        }
        else tc=BADCOM;

        switch(tc) {
        case MPLNODE:
            if(*par)
                if((i=stat(par, stype))==-1) 
                    printf("Sim: File %s, does NOT exist!\n", par);
                else
                    if ((*stype).st_mode & S_IEXEC) {
                        i=opc?atoi(opc):-1;
                        if (i>-2 && i<MAX_PRC)
                            _mplnode(par, i);
                        else
                            printf("Sim: Option %s, is invalid\n", opc);
                    }
                    else
                        printf("Sim: File %s, is NOT executable\n", par);
            else
                printf("Sim: Sintax error, ln <-node_index> file_name\n");
        break;
        case MPLHOST:
            if(*par)
                if((i=stat(par, stype))==-1) 
                    printf("Sim: File %s, does NOT exist!\n", par);
                else
                    if ((*stype).st_mode & S_IEXEC)
                        _mplhost(par);
                    else
                        printf("Sim: File %s, is NOT executable\n", par);
            else
                printf("Sim: Sintax error, lh file_name\n");
        break;
        case MPSTART:
            if((*Ptbl).mps==PREADY) {
                (*Ptbl).mps=PBLOCKED;
                _mprun(-1);
                (*Ptbl).mps=PRUNNING;
            }
            _mpwait();
        break;
        case MPLSTART:
            if((*Ptbl).mps==PREADY) _mpstart(-1);
            _mpwait();
        break;
        case MPKILL:
            _mpkill(SIGKILL);
        break;
        case MPSTATUS:
            _mpstatus();
        break;
        case MPLOG:
            if(*par) {
                strcpy((*Ptbl).mpl, par);
                strcat((*Ptbl).mpl, ".LOG");
            }
			close((*Ptbl).mpf);
            if (((*Ptbl).mpf=mpopen(O_CREAT | O_WRONLY | O_TRUNC))==NIL) {
                printf("Sim: NOT able to open log file %s!!\n", (*Ptbl).mpl);
                perror("Sim");
            }
            else {
                j=(*Ptbl).mpt;
                (*Ptbl).mpt=1;
                mpprint("Sim: Log file %s, initiated\n", (*Ptbl).mpl);
                (*Ptbl).mpt=j;
                printf("Sim: Log file %s, initiated\n", (*Ptbl).mpl);
            }
        break;
        case BADCOM:
            printf("Sim: Unknown command %s\n", cmd);
        break;
        default:
        break;
        }
    }
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mpsys.c'" '(8549 characters)'
if test -f 'mpsys.c'
then
	echo shar: will not over-write existing file "'mpsys.c'"
else
cat << \SHAR_EOF > 'mpsys.c'
/* FQSystems -------------------------------------------------------------------

    File  : mpsys.c
    Title : MultiProcessor Simulator System File
    Author: Felix E. Quevedo Stuva.
    Date  : May 12, 1989.

----------------------------------------------------------------------------- */
#include "mpdef.h"

static _handler_req()
{
    if((*Ptbl).mpq>=0) {
        _mprun((*Ptbl).mpq);
        (*Ptbl).mps=PRUNNING;
    }
    else {
        (*Ptbl).mps=PREADY;
        _mpstart(0);
    }
}

static _handler_chl()
{
    int p, i, r, j, (*oh)();
    union wait stts[1];
    struct rusage rsg[1];
    char wht[20];

    while((p=wait3(stts, WNOHANG, rsg))>0) {
        r=(*stts).w_retcode;
        for(i=j=0, i--; (*Ptbl).prc[i].pid!=p && (*Ptbl).mpn>i; i++);
        if WIFEXITED(*stts) {
            strcpy(wht, "EXITED\n");
            (*Ptbl).prc[i].pid = 0;
            (*Ptbl).prc[i].pst = PREADY;
            if(r) {
                mpprint("Warning, NODE %d has exited with RC=%d\n", i, r);
            }
			if(i == NIL) _mpkill(9);
        }
        else
        if WIFSIGNALED(*stts) {
            strcpy(wht, "SIGNALED\n");
            (*Ptbl).prc[i].pid = 0;
            (*Ptbl).prc[i].pst = PREADY;
            mpprint("Warning, NODE %d signaled SIG=%d\n", i, (*stts).w_stopval);
        }
        else
        if WIFSTOPPED(*stts) {
            strcpy(wht, "STOPPED\n");
            (*Ptbl).prc[i].pst = PBLOCKED;
        }
        j=(*Ptbl).mpt;
        (*Ptbl).mpt=1;
        mpprint("NODE %2d: RC %2d CPU%6d SYS%6d MSND%4d MRCV%4d %s", i, r,
            (*rsg).ru_utime.tv_usec/1000, (*rsg).ru_stime.tv_usec/1000,
            (*Ptbl).prc[i].msnd, (*Ptbl).prc[i].mrcv, wht);
        (*Ptbl).mpt=j;
        if((*Ptbl).mpr>0) (*Ptbl).mpr--;
    }
    if(!(*Ptbl).mpr) (*Ptbl).mps=PREADY;
}

static _handler_sys()
{
    int i, j, k;
    struct itimerval val[1];
    struct itimerval oval[1];
    if(Ptbl) {
        for(i=0, i--; i<(*Ptbl).mpn; i++) {
            if((*Ptbl).prc[i].pid)
                kill((*Ptbl).prc[i].pid, SIGKILL);
            msgctl((*Ptbl).prc[i].cmi, IPC_RMID, 0);
        }
        shmctl((*Ptbl).mpm, IPC_RMID, 0);
        shmctl(shmget(geteuid(), sizeof(MP_TBL), 0777), IPC_RMID, 0);
    }
    (*val).it_interval.tv_usec=(*val).it_value.tv_usec=0;
    setitimer(ITIMER_REAL, val, oval);
    exit(0);
}


_mpinit(n)
int n;    /* number of starting processors */
{
    int i, j, k;

    if(n < MIN_PRC)
        printf("Minimum # of Nodes (%d) NOT REACHED!\n", MIN_PRC);
    else
    if (n > MAX_PRC)
        printf("Maximum # of Nodes (%d) EXCEEDED!\n", MAX_PRC);
    else {
        signal(SIGCHLD, _handler_chl);
        signal(SIGUSR1, _handler_req);
        signal(SIGUSR2, SIG_IGN);
        for(i=1; i<17; signal(i++, _handler_sys));
        ShmId = shmget(geteuid(), sizeof(MP_TBL), 0777|IPC_CREAT);
        if (ShmId > NIL) {
            Ptbl = (MP_TBL *)shmat(ShmId, 0, 0);
            if (Ptbl > 0) {
                (*Ptbl).mpn = n;
                (*Ptbl).mpm = 0;
                (*Ptbl).mpt = 0;
                (*Ptbl).mps = PEMPTY;
                strcpy((*Ptbl).mpl, "MPSYSLOG");
                for(i=0, i--; i<n; i++) {
                    (*Ptbl).prc[i].pid = 0;
                    (*Ptbl).prc[i].ppw = 0;
                    (*Ptbl).prc[i].pno = i;
                    (*Ptbl).prc[i].pst = PEMPTY;
                    (*Ptbl).prc[i].cmi = 0;
                    (*Ptbl).prc[i].msnd= 0;
                    (*Ptbl).prc[i].mrcv= 0;
                    (*Ptbl).prc[i].cdp[0] = 0;
                }
            }
            else mperror(3, "Sim: init");
        }
        else mperror(4, "Sim: init");
		return;
    }
	mperror(999, "Sim, init");
}

_mpkill(sig)
int sig;
{
    int i;

    if(Ptbl)
    {
        for(i=0, i--;i<(*Ptbl).mpn;i++)
            if((*Ptbl).prc[i].pid)
                kill((*Ptbl).prc[i].pid, sig);
    }
    else mperror(1, "Sim: kill");
}

_mplhost(cmd)
char *cmd;
{
    if(!cmd) return mperror(5, "Sim: lhost");
    strcpy((*Ptbl).mph.cdp, cmd);
    mpprint("HOST, Command %s loaded!\n", (*Ptbl).mph.cdp);
    (*Ptbl).mps=(*Ptbl).mph.pst=PREADY;
}

_mprun(j)
int j;
{
    int n, i, k;

    if (Ptbl > 0) { /* if Mp is setup */
        i=fork();         /* create child process */
        if(i>0) {         /* I'm still daddy. */
            (*Ptbl).prc[j].pid = i;   /* save Unix pid */
            (*Ptbl).mpr++;        /* more running successful */
            msgctl((*Ptbl).prc[j].cmi, IPC_RMID, 0);
            (*Ptbl).prc[j].cmi = msgget(geteuid()+i, 0777|IPC_CREAT);
            (*Ptbl).prc[j].msnd = 0;  /* initiate msg snd counter */
            (*Ptbl).prc[j].mrcv = 0;  /* initiate msg rcv counter */
        } else
        if(!i) {           /* I'm child */
            signal(SIGINT, SIG_IGN);  /* setup ignore INT signal */
            signal(SIGUSR2,SIG_IGN);  /* setup ignore USR2 signal */
            (*Ptbl).prc[j].pst=PBLOCKED; /* status child blocked */
            for(;(*Ptbl).mps!=PRUNNING;);/* wait for MP setup */
            (*Ptbl).prc[j].pst=PRUNNING; /* status child running */
                                         /* exec user process */
            i=execl((*Ptbl).prc[j].cdp, (char *)0);
            if(mehost()) { /* inform system error */
                printf("HOST, SYSTEM ERROR!  Couldn't EXECL\n");
                mpprint("HOST, Couldn't EXECL %s, RC %d\n",
                    (*Ptbl).prc[j].cdp, i);
            }
            else {
                printf("NODE %2d, SYSTEM ERROR!  Couldn't EXECL\n",j);
                mpprint("NODE %2d, Couldn't EXECL %s, RC %d\n",
                    j, (*Ptbl).prc[j].cdp, i);
            }
            exit(999);
        }
        else { /* SYSTEM ERROR!, terminate simulator now! */
            printf("NODE %2d, SYSTEM ERROR!  Couldn't fork \n",j);
            mpprint("NODE %2d, SYSTEM ERROR!  Couldn't fork \n",j);
            _mpterm();
        }
    }
    return 0;
}

_mpstart(b)
int b;      /* initial node to start MP simulation */
{
    int n, i, j, k;

    if (Ptbl > 0) {
        switch ((*Ptbl).mps) {
        case PEMPTY:
            printf("MPStart, MP Simulator is not ready!  MPLoad first!\n",j);
        break;
        case PREADY:
            n=(*Ptbl).mpn;
            for(j=b; j < n;j++) {
                switch ((*Ptbl).prc[j].pst) {
                case PEMPTY:
                break;
                case PREADY:
                    _mprun(j);
                break;
                case PRUNNING:
                    printf("NODE %2d, USER ERROR!  Node is running\n",j);
                break;
                case PBLOCKED:
                    printf("NODE %2d, USER ERROR!  Node is blocked\n",j);
                break;
                default:
                    printf("NODE %2d, STATUS ERROR!  Unknown type %d\n", j,
                        (*Ptbl).prc[j].pst);
                    mpprint("NODE %2d, STATUS ERROR!  Unknown type %d\n", j,
                        (*Ptbl).prc[j].pst);
                    _mpterm();
                break;
                }
            }
            (*Ptbl).mps=PRUNNING;
        break;
        default:
            printf("MPStart, USER ERROR!... MP simulator is running\n");
        break;
        }
    }
    else mperror(3, "Sim: starter");
}

_mpstatus()
{
    int i, j;

    if(Ptbl)
    {
        printf("Nodes : %5d  Logfile : %s\n", (*Ptbl).mpn, (*Ptbl).mpl);
        printf("Status: %5d  #Running: %5d\n", (*Ptbl).mps, (*Ptbl).mpr);
        printf("Node  UNIXId   MsgId  Command     MsgSnd  MsgRcv  Status\n");
        printf("----  ------  ------  ----------  ------  ------  -------\n");
        for(i=0, i--; i<(*Ptbl).mpn; i++)
        {
            if ((*Ptbl).prc[i].pst!=PEMPTY) {
                printf("%4d  %6d  %6d  %10s  %6d  %6d  ",
                 (*Ptbl).prc[i].pno, (*Ptbl).prc[i].pid,
                 (*Ptbl).prc[i].cmi, (*Ptbl).prc[i].cdp,
                 (*Ptbl).prc[i].msnd, (*Ptbl).prc[i].mrcv);
                switch ((*Ptbl).prc[i].pst) {
                case PREADY: printf("ready");
                break;
                case PRUNNING: printf("running");
                break;
                case PBLOCKED: printf("blocked");
                break;
                }
                printf("\n");
            }
        }
    }
    else mperror(1, "Sim: status");
}

_mpterm()
{
    kill(getpid(), SIGTERM);
    pause();
}

_mpwait()
{
    if(Ptbl)
    {
        jmp=0;
        for(;(*Ptbl).mpr;);
        (*Ptbl).mps=PREADY;
    }
    else mperror(1, "Sim: wait");
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mpuser.h'" '(115 characters)'
if test -f 'mpuser.h'
then
	echo shar: will not over-write existing file "'mpuser.h'"
else
cat << \SHAR_EOF > 'mpuser.h'
#include <math.h>

#define lg2(X) X!=8?log((double)X)/log(2.):3.;
#define pw2(X) pow(2.,(double)X);
#define NIL -1
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mpusr.c'" '(6179 characters)'
if test -f 'mpusr.c'
then
	echo shar: will not over-write existing file "'mpusr.c'"
else
cat << \SHAR_EOF > 'mpusr.c'
/* FQSystems -------------------------------------------------------------------

    File  : mpusr.c
    Title : User library
    Author: Felix E. Quevedo Stuva.
    Date  : May 12, 1989

----------------------------------------------------------------------------- */
#define _MPLIB_
#include "mpdef.h"
#include <varargs.h>
#include <sys/stat.h>

struct stat stype[1];
char tmpbf[80];
char tbuf[20];
int bft=0; /* indicate that buffer has been touch */

static _pause_handler()
{
	(*Ptbl).prc[mynode()].ppw = 1;
}

_getpt() /* asure that MP is setup */
{
    int i;

    if(Ptbl<=0)
        if((i=shmget(geteuid(), sizeof(MP_TBL), 0777))>NIL)
            Ptbl=(MP_TBL *)shmat(i, 0, 0);
    if(Ptbl>0) return;
    mperror(1, "User: _getpt");
}

char *_trchd()
{
    _getpt();
    if(!bft) {
        tbuf[0]=0;
        bft=1;
        if(mehost())
            sprintf(tbuf, "User: HOST   ,");
        else
            sprintf(tbuf, "User: NODE %2d,", mynode());
    }
    return tbuf;
}

_imhost() /* security gateguard for host commands */
{
    _getpt();
    if (mehost()) return;
    mperror(6, "User: _imhost");
}

mprnd() /* return number of nodes running */
{
    _getpt();
    return (*Ptbl).mpr;
}

mpdim() /* return maximum number of nodes available */
{
    _getpt();
    return (*Ptbl).mpn;
}

mynode() /* return current node number */
{
    int i, j;

    _getpt();
    j = getpid();
    for(i=NIL; i<(*Ptbl).mpn && (*Ptbl).prc[i].pid != j; i++);
    if (i<(*Ptbl).mpn && (*Ptbl).prc[i].pid == j)
        return (*Ptbl).prc[i].pno;
    sprintf(tmpbf, "UNIX PID: %d is NOT a MP node!\n", getpid());
    mperror(999, tmpbf );
}

load(fn, nd) /* load node command and execute */
char *fn;
int nd;
{
    int i, j;

    mpprint("%s loading node comand\n", _trchd());
    _imhost();                          /* be sure that I'm the host */
    if((i=stat(fn, stype))==-1) {       /* is the node exec exists? */
        sprintf(tmpbf, "%s load, file %s does NOT exist!\n", _trchd(), fn);
        mperror(999, tmpbf );
    }
    else
        if ((*stype).st_mode & S_IEXEC) { /* is the node exec executable */
            if (nd>-2 && nd<MAX_PRC) {       /* is the node a legal one? */
                _mplnode(fn, nd);               /* load nodes */
                (*Ptbl).mpq=nd;                 /* start request */
                kill(getppid(), SIGUSR1);       /* ask simulator to start request */
                for(;(*Ptbl).mps!=PRUNNING;);   /* wait for MPStart to setup */
            }
            else {
                sprintf(tmpbf, "%s load, illegal node %d\n", _trchd(), nd);
                mperror(999, tmpbf);
            }
        }
        else {
            sprintf(tmpbf, "%s load, file %s is NOT executable\n", _trchd(), fn);
            mperror(999, tmpbf);
        }
}

_mvstr(from, to, len)
int len;
char *from, *to;
{
    int i;
    for(i=0; i<len; to[i]=from[i], i++);
}

_rcvm(prcn, txt, len, type, wtyp, mode) /* receive from the msg queue */
int len, *type, *prcn, wtyp, mode;
char *txt;
{
    int i, j;
    _getpt();
    i = mynode();
    (*Ptbl).prc[i].pst = PBLOCKED;
    mpprint("%s waiting for msg type %d\n", _trchd(), wtyp);
    if((j=msgrcv((*Ptbl).prc[i].cmi, &Rmsg, MSG_LEN, wtyp, mode))>NIL) {
        *type= Rmsg.mtype;
        Tmsg = (MSG_TXT *)Rmsg.mtext;		/* this command FIRST */
        *prcn= (*Tmsg).mwho;
        if(len != (*Tmsg).mlen) {       /* if expected len != recv len then abort */
            sprintf(tmpbf, "%s recv, msg len snd %d and rcv %d does NOT match!\n",
                    _trchd(), len, (*Tmsg).mlen);
            mperror(999, tmpbf);
        }
        _mvstr(&(*Tmsg).mtxt, txt, len);
										/* NO mpprint before this line!!!! */
        mpprint("%s recv from %d, len %d, type %d\n", _trchd(), *prcn, len, *type);
        (*Ptbl).prc[i].mrcv++;
    }
    if(j==NIL) mpprint("%s UNSUCCESSFUL recv len %d, type %d\n", _trchd(), len, wtyp);
    (*Ptbl).prc[i].pst = PRUNNING;
    return j;
}

recv(prcn, txt, len, type, wtyp) /* receive from the msg queue */
int len, *type, *prcn, wtyp;
char *txt;
{
    return _rcvm(prcn, txt, len, type, wtyp, 0); /* receive from the msg queue */
}

trcv(prcn, txt, len, type, wtyp) /* test and receive from the msg queue */
int len, *type, *prcn, wtyp;
char *txt;
{
    return _rcvm(prcn, txt, len, type, wtyp, IPC_NOWAIT); /* receive from the msg queue */
}

send(prcn, txt, len, type) /* send a msg */
int prcn, len, type;
char *txt;
{
    int i;
    _getpt();
    Smsg.mtype=type;
    Tmsg = (MSG_TXT *)Smsg.mtext;		/* this command FIRST */
    _mvstr(txt,&(*Tmsg).mtxt, len);
    i=(*Tmsg).mwho = mynode();
    (*Tmsg).mlen = len;
    if(msgsnd((*Ptbl).prc[prcn].cmi, &Smsg, 2*sizeof(int) + len, 0)==0) {
							/* NO mpprint before this line!!!! */
		kill((*Ptbl).prc[prcn].pid, SIGUSR2);
        mpprint("%s sent to %d, len %d, type %d\n", _trchd(), prcn, len, type);
        (*Ptbl).prc[i].msnd++;
        return 0;
    }
    mpprint("%s UNSUCCESSFUL send to %d, len %d, type %d\n", _trchd(), prcn, len, type);
    return NIL;
}

probe(i)
int i;
{
    struct msqid_ds buf[1];

    _getpt();
    if(!i)mpprint("%s testing msg queue\n", _trchd());
    if(msgctl((*Ptbl).prc[mynode()].cmi, IPC_STAT, buf) != NIL)
        return (*buf).msg_qnum;
    return 0;
}

crtshm(sz)
int sz;
{
    _imhost();                          /* be sure that I'm the host */
    mpprint("%s creating shared memory segment\n", _trchd());
    (*Ptbl).mpm = shmget(geteuid()+1, sz, 0777|IPC_CREAT);
    if((*Ptbl).mpm > 0) {
        return attshm();
    }
    else
        mperror(3, _trchd());
}

attshm()
{
    int i;
    _getpt();
    mpprint("%s attaching share memory segment\n", _trchd());
    i=(int)shmat((*Ptbl).mpm, 0, 0);
    if(i>0)
        return i;
    mperror(4, _trchd());
}

detshm()
{
    _getpt();
    mpprint("%s dettaching share memory segment\n", _trchd());
    return shmdt(shmat((*Ptbl).mpm, 0, 0));
}

slpmsq() /* sleep until new message is queued */
{
    int i=mynode();
    mpprint("%s sleeping until new message, current %d\n", _trchd(), probe());
	signal(SIGUSR2, _pause_handler);
	if(!(*Ptbl).prc[i].ppw) {
        pause();
	}
	(*Ptbl).prc[i].ppw=0;
}
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'scrs'"
cd ..
if test ! -d 'tsts'
then
	echo shar: creating directory "'tsts'"
	mkdir 'tsts'
fi
echo shar: entering directory "'tsts'"
cd 'tsts'
if test ! -d 'hi'
then
	echo shar: creating directory "'hi'"
	mkdir 'hi'
fi
echo shar: entering directory "'hi'"
cd 'hi'
echo shar: extracting "'hi.c'" '(892 characters)'
if test -f 'hi.c'
then
	echo shar: will not over-write existing file "'hi.c'"
else
cat << \SHAR_EOF > 'hi.c'
/* ------------------------------------------------------------------------------
 * hi.c
 * Nice test program
 * Uses SHM segment and sends messages to processor i+1.
 * Felix E. Quevedo Stuva
 * Oct 11, 1989
 * --------------------------------------------------------------------------- */
main()
{
	int i,j, l, t, f;
	char txt[50];
	double *mt;

	i=mynode();
	j=mpdim();
	printf("Hi there!, I'm NODE %d\n",i);

	recv(&f, txt, 7, &t, 0);
	printf("NODE %d: recv %s, len %d, type %d, from %d\n", i, txt, l, t, f);

	mt=(double*)attshm();
	mt[i]=i;
	printf("NODE %d: attached shm seg and update index %d\n",i, i);

	if((i+1)%j) {
		printf("NODE %d: sending to %d\n",i, (i+1)%j);
		send((i+1)%j, txt, 7, t+1);
	}

	printf("NODE %d: sending to the host!\n", i);
	if(send(-1, txt, 7, t+1)<0)
		printf("NODE %d, Message not delivered!\n", i);
	else
		printf("NODE %d, Message delivered!\n", i);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'hih.c'" '(752 characters)'
if test -f 'hih.c'
then
	echo shar: will not over-write existing file "'hih.c'"
else
cat << \SHAR_EOF > 'hih.c'
/* ------------------------------------------------------------------------------
 * hih.c
 * Nice test program
 * Allocates SHM segment and sends messages to processors.
 * Felix E. Quevedo Stuva
 * Oct 11, 1989
 * --------------------------------------------------------------------------- */
main()
{
	int i,j, l, t, f;
	char txt[10];
	double *mt;

	printf("HOST: running\n");

	load("hi",-1);

	mt = (double*)crtshm(20*sizeof(double));

	printf("HOST: send message to 0\n");
	send(0, "Howdy!", 7, 1);

	j=mpdim()+1;
	printf("HOST: waiting message type %d\n", j);

	recv(&f, txt, 7, &t, j);

	printf("HOST: received msg type %d from %d\n", t, f);

	printf("Shared Memory content:\n");
	for(i=0; i<t-1; printf("%f ", mt[i++]));
	printf("\n");
}





SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(226 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
MLIB = ../../libmp.a

all:
	$(COMP) -o hih hih.c $(MLIB)
	$(COMP) -o hi   hi.c $(MLIB)

go:
	../../mpsim 8 < go.file

prt:
	ptroff -ms -h README

clean:
	rm hih hi MPSYSLOG
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(1000 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva


Nice test program

This example does not other objective to just test the communication
and share memory features of the simulator. In general allocates
share memory segment and sends a round ribbon greeting message.

The host program (hih), loads the processor program (hi)
to the available processors. Then creates the share memory segment
and saves the pointer. Finally sends a greeting message to processor 0
of type 1, and waits for a message of type number of proecessors plus 1.
Once the message is received it displays the content of the share memory
segment.

The processor programs, waits for a message of any type. Once received
it attaches the shere memory segment and updates an area of index equal
to the processor number with the processor number. Finally sends a message to
the next processor after incrementing the previous type received in 1.
If the processor is the last it send it to the host.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'go.file'" '(15 characters)'
if test -f 'go.file'
then
	echo shar: will not over-write existing file "'go.file'"
else
cat << \SHAR_EOF > 'go.file'
lh hih
ls
st
q
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'hi'"
cd ..
if test ! -d 'max'
then
	echo shar: creating directory "'max'"
	mkdir 'max'
fi
echo shar: entering directory "'max'"
cd 'max'
echo shar: extracting "'max.h'" '(393 characters)'
if test -f 'max.h'
then
	echo shar: will not over-write existing file "'max.h'"
else
cat << \SHAR_EOF > 'max.h'
/* max.h
 * CRCW Parallel Algorithm for Finding Maximum of a set of numbers.
 * Header file for source codes
 * Felix E. Quevedo
 * November 10, 1989.
 */

typedef
    struct {
		short flg,			/* sinchronization semaphore */
	          ij[15][2],	/* compare indexes */
	          lst[6];		/* lost vector */
		int vec[6],			/* data vector */
	        max;			/* maximum value */
    } SMSeg;




SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(1084 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva


Maximum Finding Algorithm CRWR SM MIMD.

This example uses the share memory feature of the MPsim. It also intends
to show how to make a user semaphore and simulate a SIMD machine.
This algorithm is known to be the fastest.

The host program creates the share segment, prepares data, and loads the
processor program one at a time. Once all the processors are loaded, the
host wiats for all the processors to complete the first step. Once all the 
processors has completed the first step, it resets the step flag and
waits for the second step. Finally displays the results on the
corresponding share memory area.

The processor program in the first step obtains the maximum of the two
assigned values, marking the looser vector. Then increments the flag a
and if its a second step processor, waits for the host to reset the flag.
Once the processor resets the flag verifies if the assigned looser index
value is winner (not looser) to save the maximum value on the correspponding
share memory area.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'max_hst.c'" '(1207 characters)'
if test -f 'max_hst.c'
then
	echo shar: will not over-write existing file "'max_hst.c'"
else
cat << \SHAR_EOF > 'max_hst.c'
/* max_hst.c
 *
 * CRCW Parallel Algorithm for Finding Maximum of a set of numbers.
 *
 * Host source code
 * Felix E. Quevedo
 * November 10, 1989.
 */
#include "max.h"

main()
{
	int i, j, k, l;
	SMSeg *seg;

	seg = (SMSeg*)crtshm(sizeof(SMSeg)); /* create share memory segment */
				/* prepare data and parameter for execution */
	srandom(l = time() / 100);		/* seed of random generator */
	for(i=k=0; i < 6; i++) {		/* for all vector number */
		seg->vec[i] = random() / l;	/* generate random integer */
		seg->lst[i] = 0;			/* nobody lost */
		for(j=i+1; j < 6; j++) {	/* prepare Pi,j -> Pk*/
			seg->ij[k][0] = i;
			seg->ij[k][1] = j;
			k++;
		}
	}
	printf("Shared Memory Input Vector:\n");
	for(i=0; i < 6; printf("%d ", seg->vec[i++]));
	printf("\n");

	printf("HOST: First Step\n");
	seg->flg = 0;					/* start 1st step */
	for(i=0; i < 15; load("max_prc",i++)); /* load processors */
	while(seg->flg-i);				/* wait complete 1st step */

	printf("HOST: Second Step\n");
	seg->flg = 0;					/* start 2nd step */
	while(seg->flg+6);				/* wait complete 2nd step */

	printf("Shared Memory content:\n");
	for(i=0; i<6; printf("%d ", seg->lst[i++]));
	printf("\n");
	printf("Max: %d\n", seg->max);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'max_prc.c'" '(870 characters)'
if test -f 'max_prc.c'
then
	echo shar: will not over-write existing file "'max_prc.c'"
else
cat << \SHAR_EOF > 'max_prc.c'
/* max_prc.c
 *
 * CRCW Parallel Algorithm for Finding Maximum of a set of numbers.
 *
 * Processor source code
 * Felix E. Quevedo
 * November 10, 1989.
 */
#include "max.h"

main()
{
	int i, j, k, l;
	SMSeg *seg;

	seg = (SMSeg*)attshm(sizeof(SMSeg));	/* attach share memory segment */

	i = mynode();							/* get node number */
	j = seg->ij[i][0];						/* get compare index */
	k = seg->ij[i][1];						/* get compare index */
	l = (seg->vec[j] < seg->vec[k])? j : k; /* compare */
	seg->lst[l] = 1;						/* mark looser / minimum */

	seg->flg++;								/* increment semaphore */
	printf("Prc: %2d selects index %d from %d, %d\n", i, l, j, k);
	if ( i < 6) {
		while(seg->flg>0);					/* wait for 2nd step go! */
		if (!seg->lst[i])					/* if I'm the looser */
			seg->max = seg->vec[i];				/* I'm the maximum */
	    seg->flg--;							/* decrement semaphore */
	}

}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(252 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
MLIB = ../../libmp.a

all:
	$(COMP) -o max_hst max_hst.c $(MLIB)
	$(COMP) -o max_prc max_prc.c $(MLIB)

go:
	../../mpsim 16 < go.file

prt:
	ptroff -ms -h README

clean:
	rm max_hst max_prc MPSYSLOG
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'go.file'" '(19 characters)'
if test -f 'go.file'
then
	echo shar: will not over-write existing file "'go.file'"
else
cat << \SHAR_EOF > 'go.file'
lh max_hst
ls
st
q
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'max'"
cd ..
if test ! -d 'mmlt'
then
	echo shar: creating directory "'mmlt'"
	mkdir 'mmlt'
fi
echo shar: entering directory "'mmlt'"
cd 'mmlt'
echo shar: extracting "'Makefile'" '(258 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
MLIB = ../../libmp.a

all:
	$(COMP) -o mmlt_hst mmlt_hst.c $(MLIB)
	$(COMP) -o mmlt_prc mmlt_prc.c $(MLIB)

go:
	../../mpsim 16 < go.file

prt:
	ptroff -ms -h README

clean:
	rm mmlt_hst mmlt_prc MPSYSLOG
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(858 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva

Mesh Matrix Multiplication

This example uses the interprocess communication feature, simulating a Mesh 
network. The basic algorithm was taken from Alk [1989] page 179.

The host program setups by loading the processor program and sending the 
matrix dimension as messages. Then prepares data and sends the elements as
describe in the algorithm as messages of type 1 (horizontal) and type 2
(vertical). Finally it waits for the results at each processor.

The processor program after setup, waits for messages type 1 and 2. Once 
received it operates the multiplication. After the given number of 
operations, it sends to the host as a message of type 3.

The output attached shows the results of multiplying two matrices and
status of the processor after the execution.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mmlt_hst.c'" '(2092 characters)'
if test -f 'mmlt_hst.c'
then
	echo shar: will not over-write existing file "'mmlt_hst.c'"
else
cat << \SHAR_EOF > 'mmlt_hst.c'
/* mmlt_hst.c
 *
 * Mesh Matrix Multiplication
 *
 * Host source code
 * Felix E. Quevedo
 * November 24, 1989.
 */
#define M 4
#define N 6
#define O 4

P(i, j)
int i, j;
{
    return i*O+j;
}

main()
{
	int i, j, k, l, f, t, max;
	int mA[M][N];			/* data matrix */
	int mB[N][O];			/* data matrix */
	int mC[M][O];			/* output matrix */
	if (mpdim()<M*O) {
		printf("Requires a MPSim of size %d\n", M*O);
    	exit(); /* save # of processors */
    }

	for(i=0; i < M; i++) {		/* for all ith matrix number */
	    for(j=0; j < O; j++) {		/* for all jth  matrix number */
			l = P(i, j);
            load("mmlt_prc",l);  /* load processor */
			k = M;
    	  	send(l, &k, sizeof(int), 11); /* send matrix */
			k = N;
    	  	send(l, &k, sizeof(int), 12); /* send matrix */
			k = O;
    	  	send(l, &k, sizeof(int), 13); /* send matrix */
		}
	}
				/* prepare data and parameter for execution */
	srandom(k = time() / 10);		/* seed of random generator */
    printf("Matrix A:\n");
	for(i=0; i < M; i++) {		/* for all ith matrix number */
	    for(j=0; j < N; j++) {		/* for all jth  matrix number */
	    	mA[i][j] = random() / k;	/* generate random integer */
	        printf("%3d ", mA[i][j]);
		}
	    printf("\n");
	}
    printf("Matrix B:\n");
	for(i=0; i < N; i++) {		/* for all ith matrix number */
	    for(j=0; j < O; j++) {		/* for all jth  matrix number */
	    	mB[i][j] = random() / k;	/* generate random integer */
	        printf("%3d ", mB[i][j]);
	      	send(P(0,j), &mB[i][j], sizeof(int), 2); /* send matrix */
		}
	    printf("\n");
	}
	for(j=0; j < N; j++) {		/* for all jth  matrix number */
	    for(i=0; i < M; i++) {		/* for all ith matrix number */
    	  	send(P(i,0), &mA[i][j], sizeof(int), 1); /* send matrix */
		}
	}
	for(i=0; i<M*O; i++) {
        recv(&f, &j, sizeof(int), &t, 3); /* wait for result */
        mC[f/O][f%O] = j;
    }
    printf("Matrix C: A * B\n");
	for(i=0; i < M; i++) {		/* for all ith matrix number */
	    for(j=0; j < O; j++) {		/* for all jth  matrix number */
	        printf("%4d ", mC[i][j]);
		}
	    printf("\n");
	}
}




SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'mmlt_prc.c'" '(843 characters)'
if test -f 'mmlt_prc.c'
then
	echo shar: will not over-write existing file "'mmlt_prc.c'"
else
cat << \SHAR_EOF > 'mmlt_prc.c'
/* mmlt_prc.c
 *
 * Mesh Matrix Multiplication
 *
 * Processor source code
 * Felix E. Quevedo
 * November 24, 1989.
 */

int M, N, O;

P(i, j)
int i, j;
{
	return i*O+j;
}

main()
{
	int i, j, f, t;
	int a, b, c;
	int pi, ni, nj;

	pi = mynode(); /* save processor index */

	recv(&f, &M, sizeof(int), &t, 11); /* recv # of elements */
	recv(&f, &N, sizeof(int), &t, 12); /* recv # of elements */
	recv(&f, &O, sizeof(int), &t, 13); /* recv # of elements */

	ni = pi / O;
	nj = pi % O;

    for(i = c = 0; i < N; i++) {
	    recv(&f, &b, sizeof(int), &t, 2); /* recv partition */
	    recv(&f, &a, sizeof(int), &t, 1); /* recv partition */
        c += a*b;
        if(ni < M) send(P(ni+1,nj), &b, sizeof(int), 2);
        if(nj < O) send(P(ni,nj+1), &a, sizeof(int), 1);
	}
    send(-1, &c, sizeof(int), 3); /* send to host the result */
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'go.file'" '(20 characters)'
if test -f 'go.file'
then
	echo shar: will not over-write existing file "'go.file'"
else
cat << \SHAR_EOF > 'go.file'
lh mmlt_hst
ls
st
q
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'mmlt'"
cd ..
if test ! -d 'prim'
then
	echo shar: creating directory "'prim'"
	mkdir 'prim'
fi
echo shar: entering directory "'prim'"
cd 'prim'
echo shar: extracting "'prim.h'" '(635 characters)'
if test -f 'prim.h'
then
	echo shar: will not over-write existing file "'prim.h'"
else
cat << \SHAR_EOF > 'prim.h'
/*------------------------------------------------------------------------------

Title:	Prim's MST Algorithm for INTEL Hybercube Simulator 
File:	prim.h
Dscrp:	Header file for Cube Simulator program.
Author:	Felix E. Quevedo
Date:	Oct. 1989

------------------------------------------------------------------------------*/
#include <math.h>

#define HPID	1
#define NPID	2
#define HNODE	-1
#define HTYPE	10
#define NTYPE	20
#define NHTYPE	30
#define INF 	0x7fffffff
#define NN  	32

#define min(X,Y) X<Y?X:Y

lg2(x)
int x;
{
	int i, j;
	if(!x) return 0;
	for(i=x, j=0; i!=1; i=i>>1, j++);
	return j;
}

pw2(x)
int x;
{
	return 1<<x;
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(835 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva

Prim's MST Algorithm for a Hypercube machine.

This example uses the interprocess communication feacture, simulating a
Hypercube machine.

The host setups by loading the processor program and sending the dimension
and partition of the graph. Then it waits for the node 0 to send the paths
of the MST.

The process program finds the minimum at each entry level and sends to its
parents. A parent receives from its childs their results and compares to
the one they obtained. The parent selects the smallest, after receiving from
all childs, the smallest one, and send to its parent the results, and so on.
If it is the node 0, it sends the new MST path to the host and the new entry
to its child, and its child to its child, up to the the leaf nodes.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'prim_cm.c'" '(2095 characters)'
if test -f 'prim_cm.c'
then
	echo shar: will not over-write existing file "'prim_cm.c'"
else
cat << \SHAR_EOF > 'prim_cm.c'
/*------------------------------------------------------------------------------
Title:	Prim's MST Algorithm for MPSim Simulator 
File:	prim_cm.c
Dscrp:	Cube manager program, generate random weighted graph, loads node
	program to the simulator and waits for edges of the MST given by the
	node 0.
Author:	Felix E. Quevedo
Date:	Oct. 1989
------------------------------------------------------------------------------*/
#include "prim.h"

main()
{
					/* Cube system variables */
	int type, cnt, node, pid, numnodes;

					/* Application variables */
	int wgt[NN][2], wgf[NN][NN], v[3];
	int i, j, k, mx, n, cn;

	numnodes = mpdim();		/* obtain nodes available */

	printf("Parallelized  Prim's  MST  Algorithm\n");
	printf("By Felix E. Quevedo\n");
	n = 16;

	if(n<2||n>numnodes*2) exit(0);

	cn = pw2(i=lg2(n-1));			/* cube nodes requiered */
	printf("nodes:%d, cube nodes:%d\n", n, cn);
			/* create random weighted graph and load cube nodes */
	printf("\nWeighted graph:\n");
	mx = random();				/* initial random number */
	for(i=0; i<n; i++) {			/* random weighted graph */
		wgf[i][i]=INF;
		for(j=i+1; j<n; j++) {		/* random weigth creation */
			k=(random()%mx)/10000000;
			wgf[i][j]=k>1?k:INF;
			wgf[j][i]=wgf[i][j];
		}
		for(; j<2*cn; j++) wgf[i][j]=INF; /* complete weighted graph */
		for(j=0; j<n;			/* pretty output */
			printf((wgf[i][j]==INF?"*** ":"%3d "), wgf[i][j]),j++);
		printf("\n");
		wgf[i][0]=INF;			/* initial entry node */
	}

		/* load cube nodes, prepare and send partition to cube nodes */
	for(i=k=0; i<2*cn; i+=2) {			
		load("prim_node", k=i/2); /* load program to cube node */
						/* send size of partition */
		send(k, &n, sizeof(int), HTYPE);
		for(j=0; j<n; j++) {		/* prepare partition */
			wgt[j][0]=wgf[j][i];
			wgt[j][1]=wgf[j][i+1];
		}				/* send partition */
		send(k, wgt, NN*2*sizeof(int), HTYPE);
	}

					/* wait for node to solve MST */
	printf("\nMinimum Spanning Tree:\n");
	for(i=0; i<n-1; i++) {
		recv(&node, v, sizeof(int)*3, &type, NHTYPE);
		printf("HOST  path:%2d-%2d wgt:%3d\n", v[0],v[1],v[2]);
	}
	printf("Bye, bye...\n");
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'prim_node.c'" '(2540 characters)'
if test -f 'prim_node.c'
then
	echo shar: will not over-write existing file "'prim_node.c'"
else
cat << \SHAR_EOF > 'prim_node.c'
/*------------------------------------------------------------------------------
Title:	Prim's MST Algorithm for MPSim Simulator 
File:	prim_node.c
Dscrp:	Cube node program, obtain from manager the partition of the grap to
	process with the Prim's MST algorithm.
Author:	Felix E. Quevedo
Date:	Oct. 1989
------------------------------------------------------------------------------*/
#include "prim.h"

main()
{
					/* Cube System Variables */
	int node;
	int type, rcnt, rnode, rpid;
	int numnodes;

					/* Application Variables */	
	int i, j, k, n;
	int from, to, dad, mlen;
	int vec[3], rvc[3], wgt[NN][2], bs[2];

					/* SetUp system variables */
	node = mynode();
	numnodes = mpdim();

					/* receive from Host size of graph */
	recv(&rpid, &n, sizeof(int), &type, HTYPE);

					/* SetUp application variables */
	mlen=3*sizeof(int);			/* message length */
	from=node?lg2(pw2(lg2(node)+1)):0;		/* initial child node index */
	to=from+lg2(n/2)-lg2(2*node);		/* final child node index */
	dad=(node)?node-pw2(i=lg2(node)):HNODE; /* parent node index */
	bs[0]=bs[1]=0;				/* initial base */
	/*printf("NODE %d: from %d, to %d, dad %d\n", node, from, to);*/

					/* receive from Host graph partition */
	recv(&rpid, wgt, sizeof(int)*2*NN, &type, HTYPE);

			/* Loop For until all graph nodes have been on base */
	for(i=0; i<n-1; i++) {
        /*printf("%d:%d processing...\n", node, getpid());*/
					/* local minimum */
		k=(wgt[bs[1]][1]<wgt[bs[0]][0])?1:0;
		vec[0]=bs[k];			/* save minimum index from */
		vec[1]=2*node+k;		/* save minimum index to */
		vec[2]=wgt[bs[k]][k];		/* save minimum weight */
					
		for(j=from; j<to; j++) { /* receive from child their minimum */
			recv(&rpid, rvc, mlen, &type, NTYPE);
			if(rvc[2]<vec[2])	/* child has minimum: save it */
				for(k=0; k<3; vec[k]=rvc[k++]);
		}

					/* send and receive from parent */
		if(node){			/* if not first cube node */
			send(dad, vec, mlen, NTYPE);
			recv(&rpid, vec, mlen, &type, NTYPE);
					/* if parent has minimum: change base */
			if(wgt[vec[0]][0]<wgt[bs[0]][0]) bs[0]=vec[0];
			if(wgt[vec[0]][1]<wgt[bs[1]][1]) bs[1]=vec[0];
		}
		else {			/* if first cube node: send to HOST */
			send(HNODE, vec, mlen, NHTYPE);
			vec[0]=vec[1];		/* save new base! */
		}

		k=vec[0]-2*node;	/* if I have base: fill with INF */
		if(k==1||k==0) for(j=0; j<n*2; wgt[j++][k]=INF);

		for(j=from;j<to;	/* send to childs new base */
                        /*printf("%d: send to %d\n", node, node+pw2(j)),*/
			send(node+pw2(j++), vec, mlen, NTYPE));
	}
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(261 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
MLIB = ../../libmp.a -lm

all:
	$(COMP) -o prim_cm prim_cm.c $(MLIB)
	$(COMP) -o prim_node prim_node.c $(MLIB)

go:
	../../mpsim 8 < go.file

prt:
	ptroff -ms -h README

clean:
	rm prim_cm prim_node MPSYSLOG
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'go.file'" '(13 characters)'
if test -f 'go.file'
then
	echo shar: will not over-write existing file "'go.file'"
else
cat << \SHAR_EOF > 'go.file'
lh prim_cm
s
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'prim'"
cd ..
if test ! -d 'tmx'
then
	echo shar: creating directory "'tmx'"
	mkdir 'tmx'
fi
echo shar: entering directory "'tmx'"
cd 'tmx'
echo shar: extracting "'present'" '(5900 characters)'
if test -f 'present'
then
	echo shar: will not over-write existing file "'present'"
else
cat << \SHAR_EOF > 'present'
.nr PO 1.5i
.sp 2i
.ft B
.ce 2
The MultiProcessor Simulator\(co / Experimental Version 1.0
.sp 2
.ft R
by F\*'elix E. Quevedo Stuva
.sp 4
.ad b
.fi
.ls 2
.NH 1
Nice test program
.PP
This example does not other objective to just test the communication
and share memory features of the simulator. In general allocates
share memory segment and sends a round ribbon greeting message.
.PP
The host program (hih), loads the processor program (hi)
to the available processors. Then creates the share memory segment
and saves the pointer. Finally sends a greeting message to processor 0
of type 1, and waits for a message of type number of proecessors plus 1.
Once the message is received it displays the content of the share memory
segment.
.PP
The processor programs, waits for a message of any type. Once received
it attaches the shere memory segment and updates an area of index equal
to the processor number with the processor number. Finally sends a message to
the next processor after incrementing the previous type received in 1.
If the processor is the last it send it to the host.
.bp
.sp 5
.NH 2
Maximum Finding Algorithm CRWR SM MIMD.
.PP
This example uses the share memory feature of the MPsim. It also intends
to show how to make a user semaphore and simulate a SIMD machine.
This algorithm is known to be the fastest.
.PP
The host program creates the share segment, prepares data, and loads the
processor program one at a time. Once all the processors are loaded, the
host wiats for all the processors to complete the first step. Once all the 
processors has completed the first step, it resets the step flag and
waits for the second step. Finally displays the results on the
corresponding share memory area.
.PP
The processor program in the first step obtains the maximum of the two
assigned values, marking the looser vector. Then increments the flag a
and if its a second step processor, waits for the host to reset the flag.
Once the processor resets the flag verifies if the assigned looser index
value is winner (not looser) to save the maximum value on the correspponding
share memory area.
.bp
.sp 5
.NH 2
Maximum Finding Algorithm for a Binary Tree machine, mapped on a
Linear Array Computer.
.PP
This example uses the interprocess communication feature. It also simulates
the mapping of a Binary Tree Machine on a simulated Linear Array Computer.
The algorithm is known to be Cost Optimal.
.PP
The host program prepares data, load to all the processor available the
processor program and send to each one the assigned partition. Finally
waits for the result as a messages from the root processor.
.PP
The processor program receives the partition, finds the maximum and send
the result to its parent. At this moment the mapping of a  binary tree
machine on a linear array computer, proposed by Sarkar and Deo [1988], enters
in effect. Depending on the stage algorithm it will receive, process and
send; or will receive and send. Finally if the processor is the mapped root
of the binary tree, send the result to the host process.
.PP
The output attached to the implementation, shows step by step how the
communication is performed. Observe how the execution of the processors (nodes)
are completely asynchronical at the begining.
.bp
.sp 5
.NH 2
Mesh Matrix Multiplication
.PP
This example uses the interprocess communication feature, simulating a Mesh 
network. The basic algorithm was taken from Alk [1989] page 179.
.PP
The host program setups by loading the processor program and sending
the matrix dimension as messages. Then prepares data and sends the elements as
describe in the algorithm as messages of type 1 (horizontal) and type 2
(vertical). Finally it waits for the results at each processor.
.PP
The processor program after setup, waits for messages type 1 and 2. Once received
it operates the multiplication. After the given number of operations, it sends
to the host as a message of type 3.
.PP
The output attached shows the results of multiplying two matrices and
status of the processor after the execution.
.bp
.sp 5
.NH 2
Prim's MST Algorithm for a Hypercube machine.
.PP
This example uses the interprocess communication feacture, simulating a
Hypercube machine.
.PP
The host setups by loading the processor program and sending the dimension
and partition of the graph. Then it waits for the node 0 to send the paths
of the MST.
.PP
The process program finds the minimum at each entry level and sends to its
parents. A parent receives from its childs their results and compares to
the one they obtained. The parent selects the smallest, after receiving from
all childs, the smallest one, and send to its parent the results, and so on.
If it is the node 0, it sends the new MST path to the host and the new entry
to its child, and its child to its child, up to the the leaf nodes.
.bp
.sp 5
.NH 1
Implementation
.PP
The simulator has been implemented on UNIX C. It is transportability
has been proved between a SUN 3/60 and a VaxStation II. In both cases
the main modules were working, but with no guarantee of full feature
capacity.
.PP
The implementation consist of the following files:
.IP a)
mpsim.c: the interactive module. Contains the
.I main()
and the
.I _stop_handler()
functions.
.IP b)
mplib.c: the common function library. Contains the
.I
mpopen(), mptime(), mpprint(), mperro(), mehost(), _mplnode()
.R
functions.
.IP c)
mpsys.c: the system function library. Contains the
.I
_handler_req(), _handler_chl(), _handler_sys(), _mpinit(), _mpkill(),
_mplhost(), _mprun(), _mpstart(), _mpstatus(), _mpterm(),
.R and
_mpwait()
.R
functions.
.IP d)
mpusr.c: the user function library. Contains the
.I
_pause_handler()*, _getpt(), _trchd(), _imhost(), mprnd(), mpdim(),
mynode(), load(), _mvstr(), _rcvm(), recv(), trcv()*, send(), 
probe(), crtshm(), attshm(), detshm()
.R and
slpmsq()*
.R
functions. The ones marked with a * are still on experimental phase.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(1199 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva

Maximum Finding Algorithm for a Binary Tree machine, mapped on a
Linear Array Computer.

This example uses the interprocess communication feature. It also simulates
the mapping of a Binary Tree Machine on a simulated Linear Array Computer.
The algorithm is known to be Cost Optimal.

The host program prepares data, load to all the processor available the
processor program and send to each one the assigned partition. Finally
waits for the result as a messages from the root processor.

The processor program receives the partition, finds the maximum and send
the result to its parent. At this moment the mapping of a  binary tree
machine on a linear array computer, proposed by Sarkar and Deo [1988], enters
in effect. Depending on the stage algorithm it will receive, process and
send; or will receive and send. Finally if the processor is the mapped root
of the binary tree, send the result to the host process.

The output attached to the implementation, shows step by step how the
communication is performed. Observe how the execution of the processors (nodes)
are completely asynchronical at the begining.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tmx_hst.c'" '(1205 characters)'
if test -f 'tmx_hst.c'
then
	echo shar: will not over-write existing file "'tmx_hst.c'"
else
cat << \SHAR_EOF > 'tmx_hst.c'
/* tmx_hst.c
 *
 * Cost Optimal algorithm for find maximum with
 * Mapping of Binary-Tree Machine to Linear Array.
 *
 * Host source code
 * Felix E. Quevedo
 * November 17, 1989.
 */
#define NN 256

main()
{
	int i, j, k, l, f, t, max;
	int vec[NN];			/* data vector */
	if ((f = mpdim())<32) exit(); /* save # of processors */
				/* prepare data and parameter for execution */
	srandom(l = time() / 100);		/* seed of random generator */
	for(i=k=0; i < NN; i++) {		/* for all vector number */
		vec[i] = random() / l;	/* generate random integer */
	}
	printf("Input Vector:\n");
	for(i=0; i < NN-14;) {
	    for(j=0; j < 22; printf("%3d ", vec[i++]), j++);
	    printf("\n");
	}
    for(j=0; j < 14; printf("%3d ", vec[i++]), j++);
    printf("\n");

    load("tmx_prc",-1);  /* load processor */

	k = NN / f;
	printf("HOST: send partition of size %d to %d processors\n", k, f);
	for(i=0; i < f;
	    send(i,        &k,   sizeof(int), 1), /* send # of elements */
		send(i, &vec[k*i], k*sizeof(int), 2), /* send vector */
		i++
		); /* send messages to processors */

	printf("HOST: wait for result\n");
	recv(&f, &max, sizeof(int), &t, 0); /* wait for result */
	printf("HOST: Maximum %d\n", max);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'tmx_prc.c'" '(1700 characters)'
if test -f 'tmx_prc.c'
then
	echo shar: will not over-write existing file "'tmx_prc.c'"
else
cat << \SHAR_EOF > 'tmx_prc.c'
/* tmx_prc.c
 *
 * Cost Optimal algorithm for find maximum with
 * Mapping of Binary-Tree Machine to Linear Array.
 *
 * Processor source code
 * Felix E. Quevedo
 * November 17, 1989.
 */
#define pw2(X) (1<<X)

lg2(x) /* simple function for log base 2 */
int x;
{
	int i;
	if(x) for(i=0; x>>i+1; i++);
	return i;
}

main()
{
	int i, j, k, l, f, t;
	int ni, ne, np, mx, xm;
	int vec[20];

	ni = mynode(); /* save processor index */
	np = mpdim();  /* save number of processors */

	recv(&f, &ne, sizeof(int)   , &t, 1); /* recv # of elements */
	recv(&f, vec, sizeof(int)*ne, &t, 2); /* recv partition */

	printf("NODE %d: received vector  ", ni);
	for(i = mx = 0; i <  ne;
    	mx = mx > vec[i]? mx : vec[i], /* find partition maximum */
		printf("%3d ", vec[i]),
		i++);
	printf("\n");

	j = lg2(np); /* compute # of max steps */
	for(i = 0; i < j; i++) {
		k = (ni+1) / pw2(i); /* compute x = (j mod 2^i-1) */
		l = k * pw2(i);      /* compute y = x * 2^i-1 */
	    if( (ni+1) == l && k % 2) { 
            printf("NODE %d: send max %d to %d\n", ni, mx, ni+1);
            send(ni+1, &mx, sizeof(int), 3);
		}
		else {
	        if( (ni+1) != l) { 
                printf("NODE %d: waiting to communicate\n", ni);
	            recv(&f, &xm, sizeof(int), &t, 3);
                printf("NODE %d: send max %d to %d\n", ni, xm, ni+1);
                send(ni+1, &xm, sizeof(int), t);
    		}
        	else {
                printf("NODE %d: waiting to process\n", ni);
                recv(&f, &xm, sizeof(int), &t, 3);
	            mx = mx > xm? mx : xm;
	        }
	    }
	}
	if(ni == mpdim()-1) /* if I'm the last processor */
       send(-1, &mx, sizeof(int), t); /* send to host the result */
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(249 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#
COMP = cc -O
MLIB = ../../libmp.a

all:
	$(COMP) -o tmx_hst tmx_hst.c $(MLIB)
	$(COMP) -o tmx_prc tmx_prc.c $(MLIB)

go:
	../../mpsim < go.file

prt:
	ptroff -ms -h README

clean:
	rm tmx_hst tmx_prc MPSYSLOG
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'go.file'" '(18 characters)'
if test -f 'go.file'
then
	echo shar: will not over-write existing file "'go.file'"
else
cat << \SHAR_EOF > 'go.file'
lh tmx_hst
s
st
q
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'tmx'"
cd ..
echo shar: extracting "'Makefile'" '(593 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Multiprocessor Simulator MAKEFILE
#

all:
	cd hi  ; make; cd ..
	cd max ; make; cd ..
	cd mmlt; make; cd ..
	cd prim; make; cd ..
	cd tmx ; make; cd ..

go:
	cd hi  ; make go; cd ..
	cd max ; make go; cd ..
	cd mmlt; make go; cd ..
	cd prim; make go; cd ..
	cd tmx ; make go; cd ..

prt:
	ptroff -ms -h README 
	cd hi  ; make prt; cd ..
	cd max ; make prt; cd ..
	cd mmlt; make prt; cd ..
	cd prim; make prt; cd ..
	cd tmx ; make prt; cd ..

clean:
	cd hi  ; make clean; cd ..
	cd max ; make clean; cd ..
	cd mmlt; make clean; cd ..
	cd prim; make clean; cd ..
	cd tmx ; make clean; cd ..
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'README'" '(481 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

The MultiProcessor Simulator / Experimental Version 1.0

by Fe'lix E. Quevedo Stuva

TEST PROGRAMS

It is not the purpose of the programs to explain an algorithm, just
the implementation method in a very general way.

CONTENTS
hi	- Nice test program
max	- Maximum Finding Algorithm CRWR SM MIMD.
mmlt	- Mesh Matrix Multiplication
prim	- Prim's MST Algorithm for a Hypercube machine.
tmx	- Maximum Finding Algorithm for a Binary Tree machine, 
		mapped on a Linear Array Computer.
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'tsts'"
cd ..
echo shar: extracting "'README'" '(538 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'

This is Felix Quevedo's Multiprocessor simultator package which he wrote 
here at the University of Miami. I've provided a nroff'ed version of his
documentation, for those without the ms macros, or perhaps without *roff
itself. 

The package was developed on a Sun 3 running SunOS 3.5 and has been
tested on Sun 4 running SunOS 4.0.3, a vax running Ultrix 3.0, and
a mac running A/UX 1.1  The Makefile needs to be changed for non-SunOS
systems.

Felix can be reached at fqs at mthvax.cs.miami.edu, but he can not provide
any support. 

aem
SHAR_EOF
fi # end of overwriting check
echo shar: done with directory "'mpsim'"
cd ..
#	End of shell archive
exit 0



More information about the Comp.sources.misc mailing list