vide_public/external/libsdf/libmpmy/mpmy_generic.c
2013-02-27 13:27:23 -05:00

286 lines
7.8 KiB
C

/* This file is included in most (all?) of the mpmy_PAROS files.
It defines several of the required mpmy functions in terms of a
more primitive set. In some cases, however, there will be a PAROS
specific way to achieve these results defined in the mpmy_PAROS file
When that happens, the mpmy_PAROS file will also
#define HAVE_MPMY_FUNCNAME
so we know that we shouldn't define it here. */
/* These are set to the "right" thing on a uniprocessor, where it is
most likely that we will neglect to call MPMY_Init, but where
we really can proceed without any problems. I tried
setting them to -1, but that just led to hard-to-understand
crashes. We really should test occasionally that MPMY_Init has
been called. But I'll leave that for another day... */
int _MPMY_procnum_ = 0;
int _MPMY_nproc_ = 1;
int _MPMY_procs_per_node_ = 1;
int _MPMY_initialized_ = 0;
Counter_t MPMYSendCnt;
Counter_t MPMYRecvCnt;
Counter_t MPMYDoneCnt;
#ifndef HAVE_MPMY_FLICK
int MPMY_Flick(void){return MPMY_SUCCESS;}
#endif /* HAVE_MPMY_FLICK */
#ifndef HAVE_MPMY_IRSEND
int MPMY_Irsend(const void *buf, int cnt, int dest, int tag, MPMY_Comm_request *req){
return MPMY_Isend(buf, cnt, dest, tag, req);
}
#endif /* HAVE_MPMY_IRSEND */
#ifndef HAVE_MPMY_SHIFT
/* An implementation of shift that just uses mpmy_isend/irecv */
/* Some systems will have a better option, but this should always work. */
#define SHIFT_TAG 0x1492
/* Because NX can't distinguish different sources when reading */
/* messages, we help it out by adding processor info to the tag. */
/* Is this really necessary for the "generic" implementation? */
int MPMY_Shift(int proc, void *recvbuf, int recvcnt,
const void *sendbuf, int sendcnt, MPMY_Status *stat){
MPMY_Comm_request inreq, outreq;
Msgf(("Starting MPMY_Shift(proc=%d, recvcnt=%d, sendcnt=%d:\n",
proc, recvcnt, sendcnt));
if (proc > _MPMY_procnum_) {
MPMY_Irecv(recvbuf, recvcnt, proc, SHIFT_TAG+proc, &inreq);
Msgf(("Irecv posted\n"));
MPMY_Wait(inreq, stat);
Msgf(("Irecv done\n"));
MPMY_Isend(sendbuf, sendcnt, proc, SHIFT_TAG+MPMY_Procnum(), &outreq);
Msgf(("Isend posted\n"));
MPMY_Wait(outreq, NULL);
Msgf(("Isend done\n"));
} else {
MPMY_Isend(sendbuf, sendcnt, proc, SHIFT_TAG+MPMY_Procnum(), &outreq);
Msgf(("Isend posted\n"));
MPMY_Wait(outreq, NULL);
Msgf(("Isend done\n"));
MPMY_Irecv(recvbuf, recvcnt, proc, SHIFT_TAG+proc, &inreq);
Msgf(("Irecv posted\n"));
MPMY_Wait(inreq, stat);
Msgf(("Irecv done\n"));
}
Msgf(("Finished MPMY_Shift\n"));
return MPMY_SUCCESS;
}
#endif /* HAVE_MPMY_SHIFT */
/*
This could be smarter. In particular, it could recover gracefully
from malloc failing to deliver.
*/
#ifndef HAVE_MPMY_SHIFT_OVERLAP
#include "Malloc.h"
#include <stdlib.h>
int MPMY_Shift_overlap(int proc, void *recvbuf, int recvcnt,
const void *sendbuf, int sendcnt, MPMY_Status *stat){
void *tmp = Malloc(sendcnt);
int ret;
if( tmp == NULL && sendcnt>0 )
return MPMY_FAILED;
memcpy(tmp, sendbuf, sendcnt);
ret = MPMY_Shift(proc, recvbuf, recvcnt, tmp, sendcnt, stat);
Free(tmp);
return ret;
}
#endif /* HAVE_MPMY_SHIFT_OVERLAP */
#ifndef HAVE_MPMY_SYNC
/* Implementation of MPMY_Sync in terms of the 'combine' functions. */
/* Some systems might provide a more useful interface. */
int MPMY_Sync(void){
int junk=0;
/* I'm sure this is overkill! */
return MPMY_Combine(&junk, &junk, 1, MPMY_INT, MPMY_BOR);
}
#endif
#ifndef HAVE_MPMY_FINALIZE
/* Any system specific stuff gets handled by a system-specific finalizer */
int MPMY_Finalize(void){
return MPMY_SUCCESS;
}
#endif
#ifndef HAVE_MPMY_WAIT
/* An implementation of mpmy_wait that just busy-waits on MPMY_Test. */
/* Some systems will have a better option, but this should always work. */
int MPMY_Wait(MPMY_Comm_request req, MPMY_Status *stat){
/* Should we do a 'MPMY_Flick'' ? */
int flag = 0;
int ret;
do{
MPMY_Flick();
ret = MPMY_Test(req, &flag, stat);
}while( ret == MPMY_SUCCESS && flag==0 );
return ret;
}
#endif /* HAVE_MPMY_WAIT */
#ifndef HAVE_MPMY_WAIT2
int MPMY_Wait2(MPMY_Comm_request req1, MPMY_Status *stat1,
MPMY_Comm_request req2, MPMY_Status *stat2){
/* Should we do a 'MPMY_Flick'' ? */
int done1, done2;
int ret;
done1 = done2 = 0;
do{ /* loop until at least one is finished */
MPMY_Flick();
ret = MPMY_Test(req1, &done1, stat1);
if( ret != MPMY_SUCCESS )
return ret;
ret = MPMY_Test(req2, &done2, stat2);
if( ret != MPMY_SUCCESS )
return ret;
}while( done1 == 0 && done2 == 0 );
/* Now there's only one left, so we can call MPMY_Wait */
if( !done1 ){
ret = MPMY_Wait(req1, stat1);
if( ret != MPMY_SUCCESS )
return ret;
}
if( !done2 ){
ret = MPMY_Wait(req2, stat2);
if( ret != MPMY_SUCCESS )
return ret;
}
return MPMY_SUCCESS;
}
#endif
#ifndef HAVE_MPMY_DIAGNOSTIC
void MPMY_Diagnostic(int (*printflike)(const char *, ...)){
(*printflike)("No Diagnostic info for this MPMY\n");
}
#endif
#ifndef HAVE_MPMY_INITIALIZED
int MPMY_Initialized(void){
return _MPMY_initialized_;
}
#endif
#ifndef HAVE_MPMY_PHYSNODE
const char *MPMY_Physnode(void){
return "?";
}
#endif
#ifndef HAVE_MPMY_TIMERS
/* This is a nightmare! Timers should really be ARCH dependent */
/* but because of the CM5's special closeness to ARCH=sun4, they */
/* are PAROS dependent, instead. That means that we would otherwise */
/* repeat this code block in lots of mpmy_PAROS.c files */
#ifdef _AIX
/* No longer working?? Nov 3 1994
# include "timers_readrtc.c" */
#if !defined(USE_HWCLOCK) && !defined(USE_GETTIME)
#include "timers_posix.c"
#endif
/* it's not inconceivable to compile sequentially for the intels */
/* However, we won't necessarily be linking against, e.g, hwclock
#elif defined(__INTEL_SSD__)
# include "timers_nx.c"
*/
#else
#if !defined(USE_HWCLOCK) && !defined(USE_GETTIME)
# include "timers_posix.c"
#endif
#endif /* _AIX */
#endif /* HAVE_MPMY_TIMERS */
static time_t job_start;
static time_t job_end;
static time_t checkpoint_last;
static time_t checkpoint_next;
static time_t checkpoint_interval;
static int checkpoint_setup;
void
MPMY_CheckpointSetup(int job_seconds, int interval_seconds, int step_seconds)
{
if (MPMY_Procnum() == 0) {
job_start = time(NULL);
if (job_seconds == -1) job_end = -1;
else job_end = job_start + job_seconds - step_seconds;
checkpoint_interval = interval_seconds - step_seconds;
checkpoint_last = job_start;
checkpoint_next = job_start + checkpoint_interval;
Msg_do("Checkpoint Setup interval %ld start %ld next %ld end %ld\n",
checkpoint_interval, job_start, checkpoint_next, job_end);
}
checkpoint_setup = 1;
}
int
MPMY_CheckpointDue(int next_output_seconds)
{
time_t t;
int retval = 0;
if (MPMY_Procnum() == 0) {
t = time(NULL);
if (t >= checkpoint_next) retval = 1;
if (next_output_seconds < checkpoint_interval/4) {
Msg_do("Postponing checkpoint since output expected in %d seconds\n",
next_output_seconds);
retval = 0;
}
if (job_end > 0 && t >= job_end) retval = 1;
}
if (retval) Msg_do("Checkpoint Due\n");
MPMY_Bcast(&retval, 1, MPMY_INT, 0);
return retval;
}
void
MPMY_CheckpointFinished(void)
{
time_t t;
if (MPMY_Procnum() == 0) {
t = time(NULL);
checkpoint_last = t;
checkpoint_next = t + checkpoint_interval;
if (job_end > 0 && checkpoint_next > job_end) checkpoint_next = job_end;
Msg_do("next checkpoint %ld (%ld from now)\n", checkpoint_next, checkpoint_next-t);
}
}
int
MPMY_JobDone(void)
{
time_t t;
int retval = 0;
if (MPMY_Procnum() == 0) {
t = time(NULL);
if (job_end > 0 && t >= job_end) {
retval = 1;
Msg_do("Job Done\n");
}
}
MPMY_Bcast(&retval, 1, MPMY_INT, 0);
return retval;
}
#ifndef HAVE_MPMY_JOBREMAINING
int
MPMY_JobRemaining(void)
{
return -1;
}
#endif