[CONTACT]

[ABOUT]

[POLICY]

This is the parallel version of

Found at: ftp.icm.edu.pl:70/packages/netlib/magic/magic.u

/*                           MaGIC.U           Version of 11-11-89 

   This is the parallel version of MaGIC using the GETSUb and 
   BARRIEr macros.  It requires such structures as JOB to be 
   defined in MAGIC.h and expects the large body of external
   variables to be declared in lid.c.                              */



#define TICK 100
#define DONE gm->prob_done
                                 /***  The flag DONE is recognised
                                  ***  by "transref" as an interrupt
                                  ***  which needs therefore to be
                                  ***  in global memory.           */

#include "MaGIC.h"

JOB *theJob;                                  /* Run specification */


ENV

CLoCK(x)  int *x; CLOCK(*x)        /***  This allows CLOCk to be used
                                         by functions elsewhere.   ***/

nt begin_timer, end_timer;       /***  For timing of serial version */

/********************************************************************
********************************************************************/


                      nprobs,                 /* Number of cases   */
                      nprocs,                 /* Processes         */
					  bad_create,             /* CREATe failed     */
                      ready[PROBMAX],         /* Case finished     */
                      iso[PROBMAX],           /* Isomorphs omitted */
                      tott[PROBMAX],          /* Tests this job    */
                      p_siz[PROBMAX],
                      p_N[PROBMAX],
                      p_index[PROBMAX];
             unsigned p_ord[PROBMAX*3],
                      p_true[PROBMAX];        /* Case specifics    */
             MATRIX   limbo[MMAX],            /* Unused matrices   */
                      mat_buffer[MBMAX],      /* Emergency supply  */
                      *mat_list[PROBMAX];     /* The same as used  */
             GSDEC(GS)                        /* GETSUB monitor    */
             BARDEC(BA)                       /* BARRIER monitor   */
             LSDEC(LS)                        /* LIST monitor      */
             RSDEC(RS)                        /* RESULTS monitor   */
             MQDEC(MQ)                        /* MATRIX QUEUE      */
           } *gm;


FILE   *infil,                                /* For data input    */
       *outfil,                               /* "Real" output     */
       *fopen();
nt    offset,                                /* My current job    */
       noclear = 0,                           /* Suppress "clear"  */
       old_siz,
       old_negno,
       old_ord[SZ][SZ],                       /* Previous setup    */
       start_time;                            /* Clock reading     */
MATRIX *mymat;                                /* Latest one found  */


#include "lid.c"
#include "TR.c"
#include "setup.c"

/*******************************************************************/

main(argc,argv)  int argc; char *argv[];
{
   int i, j, option, nplocal = 2;
   extern char *optarg;
   extern int optind;
   
   while ((option = getopt (argc, argv, "x#:")) != -1)
   switch (option) 
   {
      case 'x': noclear = 1; break;
      case '#': if (! isdigit (*optarg))
                {
                   fprintf (stderr, "usage: magic [-x], [-# number]\n");
                   fflush (stderr);
                   exit (1);
                }
                sscanf (optarg, "%d", &nplocal);
                if (nplocal < 2 || nplocal > PARALLEL)
                {
                   fprintf (stderr, 
                   "ERROR: number of processes must be in range 2 - %d\n",
                   PARALLEL);	
                   fflush (stderr);
                   exit (1);
                }
                break;
   }
		
   
   INITENV
   
   theJob = (JOB*) G_MALLOC(sizeof(JOB));
   gm = (struct g_m*) G_MALLOC(sizeof(struct g_m));
   
   GSINIT(gm->GS)
   BARINIT(gm->BA)
   LSINIT(gm->LS)
   RSINIT(gm->RS)
   MQINIT(gm->MQ)
   
   gm->prog_done = 0;
   gm->nprocs = nplocal;
   makeprocs(1);

/***
 ***     Note that the slaves hang in a barrier until the master 
 ***     releases them for work.  They then work repeatedly on
 ***     the problems until  gm->prog_done  gets to be true.
 ***
 ***     The slaves generate the matrices, storing what they find
 ***     in global memory.  The master looks after IO (which is 
 ***     inherently serial).
 ***/

   job_defaults();   
   while ( nplocal = dialog() )
   if ( nplocal > 1 ) new_nprocs(nplocal);
   else
   {
      printf("\n Searching.....\n");  fflush(stdout);
      job_start();
      DONE = 0;
      while ( !DONE && infil )
      {
         MONITORS_RESET
         read_data();
         siz = old_siz; negno = old_negno;
         FORALL(i) FORALL(j) ord[i][j] = old_ord[i][j];
         BARRIER(gm->BA,gm->nprocs)
         for ( offset = 0; offset < gm->nprobs && !DONE; offset++ )
         transfer();
      }
      job_stop();
/***
 ***     It is just possible that some slaves are hanging at this point,
 ***     waiting for a matrix from the global pool, so:
 ***/
      MENTER(gm->LS)
         CONTINUE(gm->LS,0)
      MEXIT(gm->LS)
   }
   
/***
 ***     Now just ensure the slaves die gracefully.
 ***/
   while ( !finished() ) catnap(1);        /***  Lazy wait  ***/
   gm->prog_done = 1;  gm->nprobs = 0;
   BARRIER(gm->BA,gm->nprocs)
   WAIT_FOR_END
   system("clear");
}

/*****************************************************************/

makeprocs(already)  int already;   /*** Kreate enough slaves to
                                        bring the number up to
                                        gm->nprocs.  The integer
                                        "already" records how many
                                        processes there are now ***/
{
   int i;
   
   for ( i = already; i < gm->nprocs; i++ )
   {
      KREATE(slave,gm->bad_create);
      if ( gm->bad_create )
      {
         if ( i == 1 )
         {
            printf("\n Sorry: we failed to create any workers.\n");
            paws();
            exit(1);
         }
         printf("\n It appears you can't have %d processes.", 
                    gm->nprocs);
         printf("\n Let's settle for %d.\n\n", i);
         paws();
         gm->nprocs = i;
      }
   }
}


new_nprocs(x)  int x;        /*** Change number of slaves to x ***/
{
   int i, j;

   while ( !finished() ) catnap(1);        /***  Lazy wait  ***/
   gm->nprobs = 0;  DONE = 1;
   j = gm->nprocs;  gm->nprocs = x;
   if ( x >= j ) makeprocs(j);
   else
   {
      gm->prog_done = 1;
      BARRIER(gm->BA,0)
      WAIT_FOR_END
/*
 *  Now the scary bit: re-initialise the table of active processes
 *  just as in the beginning.  This is done without a lock!!
 */
     DEAD_SLAVES
/*
 *  There.  If that didn't work blame the authors of the Argonne 
 *  macros, not me!  
 *  Re-initialisation is necessary so that repeated changes of 
 *  gm->nprocs don't take the number of undead slaves over the 
 *  maximum (which is 50 by default).
 */
      gm->prog_done = 0;
      makeprocs(1);
   }
}

/*****************************************************************/

finished()                   /***  (Boolean): barrier is full  ***/
{
   int i;
   
   MENTER(gm->BA)
      i = gm->BA.count[0];
   MEXIT(gm->BA)
   return( i == gm->nprocs-1 );
}

/*****************************************************************/

catnap(x)    int x;                 /***  Sleep for 0.1x sec.  ***/
{
   int cn_start, cn_stop;
   
   CLOCK(cn_start);
   do { 
         CLOCK(cn_stop)
         if ( theJob->maxtime && cn_stop > theJob->maxtime ) DONE = 1;
      } 
   while ( cn_stop-cn_start < x*TICK/10 );
}   

/*****************************************************************/

{
   perm_initial();
   BARRIER(gm->BA,gm->nprocs)
   while ( !gm->prog_done )
   {
      subf_set();
      while ( work() ) ;
      BARRIER(gm->BA,gm->nprocs)
   }
}


/****************************************************************/

{
   int Good_matrix(), set_poss(), i;
   
   GETSUB(gm->GS,offset,gm->nprobs-1,gm->nprocs-1)
   if ( offset < 0 || DONE ) return(0);
   
   initial_setup();
   mymat = 0;
   tot = isoms = 0;
   LOOK(i)
   if ( pre_set() )
   {
      setperm();
      transref(Vlength,Good_matrix,set_poss);
   }
   gm->iso[offset] = isoms;
   gm->tott[offset] = tot;
   READY
   return(1);
}



/******************************************************************/

nitial_setup()               /*** Called from work() before TR ***/
{
   int i,j,k,m;
   unsigned u;
   
   siz = gm->p_siz[offset];
   if ( theJob->f_n)
   {
      FORALL(i) N[i] = siz-i;
      for ( i = 0; i < N[i]; i++ ) ;
      for ( j = 1; j < gm->p_N[offset]; j++ )
      {
         N[i-j] = i-j;
         N[siz-(i-j)] = siz-(i-j);
      }
   }
   m = gm->p_index[offset];  k = 0;
   FORALL(i) FORALL(j)
   {
      ord[i][j] = ((gm->p_ord[m] & (1 << k)) != 0);
      if ( ++k == SUI ) { m++; k = 0; }
   }
   FORALL(i) true[i] = ((gm->p_true[offset] & (1 << i)) > 0);
   FORaLL(i) if ( true[i]) des = i;
   
   FORALL(i)
  {
     maximal[i] = 1;
     for ( j = i+1; j <=siz; j++ ) maximal[i] *= !ord[i][j];
  }
  if ( theJob->f_lat ) 
  {
     FORALL(i)
     { 
        for ( j = i; j <= siz; j++ )
        { 
           for ( k = j; !(ord[i][k] && ord[j][k]); k++ ) ;
           { A[i][j] = A[j][i] = k; }
           for ( k = i; !(ord[k][i] && ord[k][j]); k-- ) ;
           { K[i][j] = K[j][i] = k; }
        }
     }
  }
  Vlength = 0;
  FORALL(i) FORALL(j)
  if ( !( F_N && i < N[j] ))
  {
     cc[i][j] = Vlength++;
     if ( F_N ) cc[N[j]][N[i]] = cc[i][j];
  }
  if ( theJob->f_t)
  {
     subf[4].val = des;
     if ( theJob->f_n ) subf[5].val = N[des];
  }
}

/*****************************************************************/

{
   int i,j,care;
   MATRIX *m;
   
   TAKE(m,care)
   FORALL(i) FORALL(j) m->MC[i][j] = C[i][j];
   for ( i = 0; i < 4; i++ ) m->badval[i] = badvalue[i];
   PUSHMAT(m,care)
}


/******************************************************************/ 

{
   if (x) 
   {
      if ( theJob->tty_out==UGLY ) printf(" -1\n");
      if ( theJob->fil_out==UGLY ) fprintf(outfil, " -1\n");
   }
}

/******************************************************************/

new_case()                /*** Offset has just been incremented ***/
{
   int i,j,k,m;
   unsigned u;
   
   if ( gm->p_siz[offset] > siz )
   {
      if ( theJob->f_n ) sep(negno);
      siz = gm->p_siz[offset];
      negno = ordno = desno = 0;
      *N = **ord = 0;
   }
   if ( theJob->f_n)
   {
      if ( gm->p_N[offset] != negno )
      {
         sep(ordno);
         FORALL(i)  N[i] = siz-i;
         for ( i = 0; i < N[i]; i++ ) ;
         for ( j = 1; j < gm->p_N[offset]; j++ )
         {
            N[i-j] = i-j;
            N[siz-i+j] = siz-i+j;
         }
         ordno = desno = 0;
         **ord = 0;
      }
   }
   m = gm->p_index[offset];  k = 0;
   FORALL(i) FORALL(j) 
   {
      u = gm->p_ord[m] & (1 << k);
      if ( ++k == SUI ) { m++; k = 0; }
      if ( !IFF(u, ord[i][j]) ) 
      {
         ord[i][j] = (u != 0);
         sep(desno);
         desno = 0;
      }
   }
   FORALL(i) true[i] = ((gm->p_true[offset] & (1 << i)) > 0);
   FORaLL(i) if ( true[i]) des = i;
   matno = 0;
}   

/******************************************************************/

transfer()             /*** Move matrices from memory to output ***/
{
   int i,j;
   
   new_case();
   POPMAT
   while ( mymat && !DONE )
   {
      FORALL(i) FORALL(j) C[i][j] = mymat->MC[i][j];
      for ( i = 0; i < 4; i++ ) badvalue[i] = mymat->badval[i];
      mat_print();
      GIVE
      POPMAT
   }
   gm->ready[offset] = 0;
   isoms += gm->iso[offset];
   tot += gm->tott[offset];
   
   if ( matno )
   {
      if ( theJob->tty_out == SUMMARY ) 
      {
         printf("     %d matri%s", matno, (matno>1? "ces": "x"));
         fflush(stdout);
      }
      if ( theJob->fil_out == SUMMARY ) 
      fprintf(outfil, "     %d matri%s", matno, (matno>1? "ces": "x"));
      sep(matno);
   }
}


.


AD:

NEW PAGES:

[ODDNUGGET]

[GOPHER]