Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

sysfunc.C

Go to the documentation of this file.
00001 #include<config.h>
00002 CPS_START_NAMESPACE
00003 /*----------------------------------------------------------*/
00009 /*----------------------------------------------------------------------
00010 /* The Sysfunc Comms Interface: sysfunc.C
00011 
00012   The MPI implementation of the QCDSP SCU comms-layer.
00013 
00014   A.N.Jackson: ajackson@epcc.ed.ac.uk                      
00015   -----------------------------------------------------------
00016   CVS keywords
00017  
00018   $Author: chulwoo $
00019   $Date: 2008/02/08 18:35:06 $
00020   $Header: /space/cvs/cps/cps++/src/comms/mpi/scu/sysfunc.C,v 1.10 2008/02/08 18:35:06 chulwoo Exp $
00021   $Id: sysfunc.C,v 1.10 2008/02/08 18:35:06 chulwoo Exp $
00022   $Name: v5_0_8 $
00023   $Locker:  $
00024   $RCSfile: sysfunc.C,v $
00025   $Revision: 1.10 $
00026   $Source: /space/cvs/cps/cps++/src/comms/mpi/scu/sysfunc.C,v $
00027   $State: Exp $  */
00028 /*----------------------------------------------------------*/
00029 
00030 CPS_END_NAMESPACE
00031 #include<comms/sysfunc_cps.h>
00032 #include <util/qcdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 CPS_START_NAMESPACE
00037 
00046 // File-scoped data used by MPISCU functions.
00047 
00048 namespace MPISCU{
00049 
00050 // Emulation layer things
00051 
00052     bool Is_Initialised = false;
00054 
00060 
00061 
00064     static char *ENVVAR = "COMMS_DEF";
00065 
00067     static char *default_filename = "commsMPI.def";
00068 
00069     static const int STRING_MAX_LEN = 10000;
00070     
00071     static char  logFileName[STRING_MAX_LEN];
00074     static FILE *logFile;      
00075     static unsigned int RNGseed;       
00076     static char         seedFileName[STRING_MAX_LEN];
00080 // MPI things
00081 
00086 //    static int Datasize = COMMS_DATASIZE;
00087 
00089     static const int N_INT_TYPES =   4;                  
00090 
00092     static const int N_FLOAT_TYPES = 3;                  
00093 
00094     static MPI_Comm Cart_Comm;          
00096     static MPIRequestManager   *ReqMan;   
00098     static MPI_Datatype *mpi_dt;        
00101 // Grid geometry
00102 
00104     static const int NDIM = 5;
00105 
00106     static int peGrid[NDIM]; // initialise to invalid value.
00108 
00109     static int peRank;        
00110     static int peNum;          
00111     static int pePos[NDIM];  
00112     static int root_pe;        
00114     static int          nnList[2*NDIM];
00117 } //namespace
00118 
00119 
00120 /*-------------------------------------------------------------------------*/
00121 /* Definitions of the actual emulated SCU system functions                 */
00122 /*-------------------------------------------------------------------------*/
00123 
00124 int UniqueID() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peRank+1; }
00125 
00126 int CoorT() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::pePos[SCU_T]; }
00127 int CoorX() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::pePos[SCU_X]; }
00128 int CoorY() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::pePos[SCU_Y]; }
00129 int CoorZ() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::pePos[SCU_Z]; }
00130 int CoorS() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::pePos[SCU_S]; }
00131 
00132 int SizeT() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peGrid[SCU_T]; }
00133 int SizeX() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peGrid[SCU_X]; }
00134 int SizeY() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peGrid[SCU_Y]; }
00135 int SizeZ() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peGrid[SCU_Z]; }
00136 int SizeS() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peGrid[SCU_S]; }
00137 
00138 int NumNodes() { if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::peNum; }
00139 
00140 //----------------------------------------------------------------
00141 /*
00142   The seed can be different for each node and can
00143   change every time the machine is reset.
00144 
00145   \note The behaviour of the MPI and serial implementations
00146   may differ from that of the QCDSP/QCDOC system function.
00147 */
00148 //----------------------------------------------------------------
00149 unsigned int Seed(){ return MPISCU::ReadSeedFile(); }
00150 //----------------------------------------------------------------
00151 /*
00152   The seed is the same for each node (spatially fixed, hence the S), but
00153   can change every time the machine is reset.
00154 
00155   \note The behaviour of the MPI and serial implementations may differ
00156   from that of the QCDSP/QCDOC system function.
00157 */
00158 //----------------------------------------------------------------
00159 unsigned int SeedS(){ if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::RNGseed; }
00160 //----------------------------------------------------------------
00161 /*
00162   SeedT can be different for each node, but is fixed in time (the T), so it is
00163   unchanged by a reset.
00164 
00165   \note The behaviour of the MPI and serial implementations may
00166   differ from that of the QCDSP/QCDOC system function.
00167 */
00168 //----------------------------------------------------------------
00169 unsigned int SeedT(){ return Seed(); }
00170 //----------------------------------------------------------------
00171 /*
00172   SeedST is the same for each node (spatially fixed, hence the S), and the
00173   same after every reset (fixed time, hence T).
00174 
00175   \note The behaviour of the MPI and serial implementations may differ
00176   from that of the QCDSP/QCDOC system function.
00177 */
00178 //----------------------------------------------------------------
00179 unsigned int SeedST(){ return SeedS(); }
00180 
00181 //----------------------------------------------------------------
00182 /*
00183   This function blocks further code execution until all
00184   nodes in the machine have begun executing the code in the sync()
00185   routine.
00186   \return 0
00187 */
00188 //----------------------------------------------------------------
00189 unsigned int sync() {
00190     if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); 
00191     MPI_Barrier( MPISCU::Cart_Comm );
00192     return 0;
00193 }
00194 
00195 //----------------------------------------------------------------
00196 /*
00197   On QCDSP this function returns the explicit wire
00198   number (0 - 7) of the physics direction given by \a dir. In the MPI
00199   version this returns the internal direction from the cartesian
00200   communicator which corresponds to the given physics direction.
00201   \param dir The physics (lattice) direction.
00202   \return The number used by the comms layer to represents that direction.
00203 
00204   Possibly.
00205 */
00206 /* In this implementation, this just returns the integer value
00207   associated with the direction from the SCUDir enum */
00208 int SCURemap( SCUDir dir ) {
00209     return (int)dir;
00210 }
00211 
00212 
00221 //----------------------------------------------------------------
00222 void SCUTrans( SCUDirArg * arg ) {
00223     SCUTrans( &arg, 1 );
00224 }
00225 
00226 //----------------------------------------------------------------
00232 //----------------------------------------------------------------
00233 void SCUTrans( SCUDirArg ** arg, int n ) {
00234 
00235     for(int i=0; i<n; i++ ) 
00236         MPISCU::Trans( arg[i]->Addr(), 
00237                       arg[i]->Datatype(), 
00238                       arg[i]->CommDir(), 
00239                       arg[i]->CommType() );
00240 
00241 }
00242 
00243 //----------------------------------------------------------------
00255 //----------------------------------------------------------------
00256 void SCUTrans( SCUDirArg * arg, unsigned int * offset, int n ) {
00257 
00258     for(int i=0; i<n; i++ ) 
00259         MPISCU::Trans( (void*)((unsigned int)arg->Addr() + offset[i]), 
00260                       arg->Datatype(), 
00261                       arg->CommDir(), 
00262                       arg->CommType() );
00263 
00264 }
00265 
00266 //----------------------------------------------------------------
00274 //----------------------------------------------------------------
00275 void SCUSetDMA( SCUDirArg * arg ) { SCUSetDMA( &arg, 1 ); }
00276 
00277 //----------------------------------------------------------------
00286 void SCUSetDMA( SCUDirArg ** arg, int n ) {
00287 
00288     // remove old settings if necessary:
00289     if( MPISCU::mpi_dt != NULL ) delete[] MPISCU::mpi_dt;
00290 
00291     // Remember the set of datatypes:
00292     MPISCU::mpi_dt = new MPI_Datatype[n];
00293     for(int  i=0; i<n; i++ ) MPISCU::mpi_dt[i] = arg[i]->Datatype();
00294 
00295 }
00296 
00297 //----------------------------------------------------------------
00306 //----------------------------------------------------------------
00307 void SCUTransAddr( SCUDirArg * arg ) { SCUTransAddr( &arg, 1 ); }
00308 
00309 //----------------------------------------------------------------
00320 //----------------------------------------------------------------
00321 void SCUTransAddr( SCUDirArg ** arg, int n ) {
00322 
00323     for(int i=0; i<n; i++ ) 
00324         MPISCU::Trans( arg[i]->Addr(), 
00325                       MPISCU::mpi_dt[i], 
00326                       arg[i]->CommDir(), 
00327                       arg[i]->CommType() );
00328     
00329 }
00330 
00331 
00332 //----------------------------------------------------------------
00337 //----------------------------------------------------------------
00338 void SCUTransComplete( void ) {
00339 
00340     
00341 
00342     // Check how many requests are pending:
00343     int numreq = MPISCU::ReqMan->NumReq();
00344     
00345     if( numreq > 0 ) {
00346 #ifdef MPISCU_DEBUG
00347         MPISCU::fprintf_all(MPISCU::logFile,
00348                             "SCUTransComplete: numreq = %i\n", numreq ); 
00349 #endif
00350         /* Grab the requires status array */
00351         MPI_Status *stat = new MPI_Status[numreq];
00352         /* WAIT for all the previously initiated communications to finish */
00353         MPI_Waitall( numreq, MPISCU::ReqMan->ReqArray(), stat );
00354         /* Throw away the status */
00355         delete[] stat;
00356 #ifdef MPISCU_DEBUG
00357         MPISCU::fprintf_all(MPISCU::logFile,
00358                             "SCUTransComplete: finished.\n", numreq );      
00359 #endif
00360     }
00361 
00362     // Clear the request manager:
00363     MPISCU::ReqMan->Clear();
00364 
00365 }
00366 
00367 
00368 // Functions used by the SCU syscall emulations.
00369 
00370 namespace MPISCU{
00371 
00372 // To record whether the following function has been called.
00373     static bool grid_is_set = false;
00374 
00386     void set_pe_grid(int x, int y, int z, int t, int s){
00387 
00388         if(grid_is_set) return; // issue a warning?
00389     
00390         peGrid[0] = t;
00391         peGrid[1] = x;
00392         peGrid[2] = y;
00393         peGrid[3] = z;
00394         peGrid[4] = s;
00395         
00396         grid_is_set = true;
00397 
00398     }
00399     
00400 
00401 //----------------------------------------------------------------
00412 //----------------------------------------------------------------
00413     void CommsInit(  ) {
00414     
00415         int  grid_periodicity[NDIM] = {1,1,1,1,1};  /* Array used to specify periodic BCs */
00416         int  pe_reorder = 0;      /* Flag to disallow PE reordering for the cart-comm */
00417 
00418         // If we have already been initialized, don't try to do it twice:
00419         if( Is_Initialised ) return;
00420 
00421    
00422     
00423         // Set-up the default values for the comms parameters:
00424         RNGseed = 1;
00425         strcpy(seedFileName,"rng.dat");
00426         strcpy(logFileName, "stderr");
00427 
00428         // If MPI has not already been started somewhere else, start it here.
00429     
00430         int initialised_remotely;
00431         MPI_Initialized(&initialised_remotely);
00432         if(initialised_remotely){
00433             if(!grid_is_set)
00434                 RaiseError("MPISCU_CommsInit: Processor grid must be set using MPISCU::set_pe_grid.");
00435         }else{
00436             int dummy_argc;
00437             char  **dummy_argv;
00438             MPI_Init(&dummy_argc, &dummy_argv);
00439             grid_is_set = true; // just in case.
00440         }
00441 
00442 
00443         // Check the environment variable MPISCU::ENVVAR. If it is defined and
00444         // is a non-zero length string, then that is either the name of a file
00445         // from which to read the read the parameters, or it is the parameters
00446         // themselves. If it is defined but zero length, then we use the 
00447         // default parameter filename.
00448         // If it is not defined, then MPISCU::peGrid had better be
00449         // initialised already.
00450     
00451         char *envvar = getenv(ENVVAR);
00452         if(envvar){ 
00453             if(strlen(envvar) == 0) envvar = default_filename;
00454             ParseCommsParam(envvar);
00455         }
00456 
00457 
00458         /* Define the (cartesian, periodic) topology of the MPI communicator */
00459 
00460         MPI_Cart_create( MPI_COMM_WORLD,   /* Original communicator */
00461                          NDIM,             /* No. dimensions */
00462                          peGrid,           /* No. PEs in each direction */
00463                          grid_periodicity, /* Periodicity of PE grid in each direction */
00464                          pe_reorder,       /* True/false flag to allow PE re-ordering */
00465                          &Cart_Comm      /* The new, cartesian, communicator */
00466             );
00467 
00468         /* Look up process number */
00469         MPI_Comm_rank( Cart_Comm, &peRank );
00470 
00471         /* Look-up processor position */
00472         MPI_Cart_coords( Cart_Comm, peRank, NDIM, pePos );
00473 
00474         /* Look up number of processors */
00475         MPI_Comm_size( Cart_Comm, &peNum );
00476 #define MPISCU_DEBUG    
00477 #ifdef MPISCU_DEBUG
00478         /* Initialise the log-file, which may actually be stdout or stderr */
00479 
00480         if( strcmp(logFileName,"stderr") == 0 )
00481             logFile = stderr;
00482         else if( strcmp(logFileName,"stdout") == 0 )
00483             logFile = stdout;
00484         else {
00485             /* Create a logfile name with the PE number as a suffix,
00486                such that we have logfile.01, logfile.02 ... logfile.15 etc */
00487 
00488             /* ordPEnum is no. of orders of magnitude (base10) of number of PEs */ 
00489             int ordPEnum = 1 + (int)log10(peNum);
00490             char *PEnum = (char*)malloc( ( ordPEnum + 1 ) * sizeof(char) );
00491             strcat(logFileName,".");
00492 
00493             /* Create filenumber based on PE number + leading zeros */
00494             sprintf(PEnum,"%i", ((int)(exp(((double)ordPEnum)*log(10.0))))+peRank);
00495             strcat(logFileName,&PEnum[1]); /* Skip the leading 1 */
00496             free( PEnum );
00497             /* Open the logfile associated with this PE */
00498             logFile = Fopen(logFileName,"w");
00499         }
00500 #endif
00501 
00502         /* Inform user that initialization has started */
00503         printf_all("MPISCU::CommsInit:  Initializing.\n");
00504 
00505         /* identify the root processor as that which lies at pos[i]=0 forall i */
00506         /* calculate the identifier on every process */
00507         int root_check = 0;
00508         for(int idirn = 0; idirn < NDIM; idirn++ ) root_check+=pePos[idirn];
00509         /* Gather the values of root_check from every PE onto every PE */
00510         int *root_array = (int*)malloc(peNum*sizeof(int));
00511         if( root_array == NULL ) 
00512             RaiseError("MPISCU::CommsInit: malloc failed for root_array.");
00513         MPI_Allgather( &root_check, /* Pointer to number to be gathered */
00514                        1,           /* i.e. gathering a single item */
00515                        MPI_INT,     /* which is a standard C integer */
00516                        root_array,  /* Pointer to the array which will recieve the data */
00517                        1,           /* One thing from each PE */
00518                        MPI_INT,     /* and that thing is an int. */
00519                        Cart_Comm /* Using the cartesian communicator */
00520             );
00521 
00522         /* Every PE goes through the list and identifies the root PE */
00523         for(int ir = 0; ir < peNum; ir++ ) 
00524             if( root_array[ir] == 0 ) root_pe = ir;
00525 
00526 
00527 
00528         /* Free the memory associated with the root-checking array */
00529         free(root_array);
00530 
00531         /* Log that the initialization has completed and give this PEs rank */
00532 #ifdef MPISCU_DEBUG
00533         fprintf_all(logFile,"MPISCU::CommsInit:  Initialization complete [PE=%i of %i, ROOT_PE=%i].\n",peRank, peNum, root_pe );
00534 #endif
00535 
00536 
00537         /* Initialise the MPI Request handler */
00538         ReqMan = new MPIRequestManager();
00539 
00540         /* Initialise the table of NNs, indexed by SCUDir */
00541         int dir_index, dummy;
00542         for( int idim = 0; idim < NDIM; idim++ ) {
00543             for( int idir = -1; idir <=1 ; idir+=2 ) {
00544                 if( idim == 0 && idir == +1 ) dir_index = SCU_TP;
00545                 if( idim == 0 && idir == -1 ) dir_index = SCU_TM;
00546                 if( idim == 1 && idir == +1 ) dir_index = SCU_XP;
00547                 if( idim == 1 && idir == -1 ) dir_index = SCU_XM;
00548                 if( idim == 2 && idir == +1 ) dir_index = SCU_YP;
00549                 if( idim == 2 && idir == -1 ) dir_index = SCU_YM;
00550                 if( idim == 3 && idir == +1 ) dir_index = SCU_ZP;
00551                 if( idim == 3 && idir == -1 ) dir_index = SCU_ZM;
00552                 if( idim == 4 && idir == +1 ) dir_index = SCU_SP;
00553                 if( idim == 4 && idir == -1 ) dir_index = SCU_SM;
00554                 MPI_Cart_shift( Cart_Comm,  // Using the cartesian communicator
00555                                 idim,       // Do this dimension 
00556                                 idir,       // Look up nearest neighbour 
00557                                 &dummy,     // Rank of this PE
00558                                 &(nnList[dir_index]) // Rank of neighbour PE 
00559                     );
00560             }
00561         }
00562 
00563         Is_Initialised = true;
00564     
00565     }
00566 
00567 
00570     void SCUCommsFinalize( void ) {
00571         if( Is_Initialised ) MPI_Finalize();
00572     }
00573 
00574 
00575 /* The global summation */
00578     void SCUGlobalSum(Type_tag t,   
00579                       size_t tsize, 
00580                       int n,        
00581                       void *ivec,   
00582                       void *ovec    
00583         ) {
00584         MPI_Datatype mpitype; /* This will hold the MPI_Datatype for type (t + size) */
00585 
00586         if( !Is_Initialised ) CommsInit(); 
00587 
00588 #ifdef MPISCU_DEBUG
00589         MPISCU::fprintf(logFile,"SCUGlobalSum: Performing a global summation.\n");
00590 #endif
00591 
00592         /* Check args make sense */
00593         if( n <= 0 )
00594             RaiseError("SCUGlobalSum: no. of values to sum is <= 0!");
00595         if( ivec == NULL )
00596             RaiseError("SCUGlobalSum: input vector points to NULL!");
00597         if( ovec == NULL )
00598             RaiseError("SCUGlobalSum: output vector points to NULL!");
00599 
00600         /* Map the requested type onto an MPI_Datatype */
00601         mpitype = MPITypeConv( t, tsize );
00602 
00603         /* Invoke the relevent MPI call, so that all processors get the global sum*/
00604     
00605         MPI_Allreduce(ivec,         /* Array containing data to be summed */
00606                       ovec,         /* Array to receive the summations */
00607                       n,            /* Number of items in the array */
00608                       mpitype,      /* MPI datatype corresponding to Type_tag */
00609                       MPI_SUM,      /* Do a global sum operation */
00610                       Cart_Comm  /* Use the cartesian communicator */
00611             );
00612 
00613     }
00614 
00615 /* SCU-layer error handler:
00616    Should map onto the ERR class for the QCDSP code. */
00625     void RaiseError( char* errstr ) {
00626 
00627         /* Report the error: */
00628         ::fprintf(stderr, "Error: %s\n", errstr);  
00629 
00630         /* Finish with MPI if it has been initialised: */
00631         if( Is_Initialised ) MPI_Finalize();
00632 
00633         exit(EXIT_FAILURE);
00634     }
00635 
00636 
00637 // Extra error wrapper to deal with string literals. */
00645     void RaiseError( const char* errstring ) { 
00646         RaiseError( const_cast<char*>(errstring) ); 
00647     }
00648 
00649 
00650 /*-------------------------------------------------------------------------*/
00651 /*                   Implementation-specific subroutines:                  */
00652 /*              If this were a class, these would be private.              */
00653 /*-------------------------------------------------------------------------*/
00654 
00655 //----------------------------------------------------------------
00660 //----------------------------------------------------------------
00661     void Trans(void* addr, MPI_Datatype mpi_dt, SCUDir dir, SCUXR sendrx){
00662     
00663         MPI_Request request;
00664 
00665         // Determine the NN in the given direction:
00666         int nnPE = nnList[dir];
00667 
00668         // Initiate the send or recieve:
00669         if( sendrx == SCU_SEND ) 
00670             MPI_Issend( addr,            // base-address of the data 
00671                         1,               // Number of items to send, one datatype 
00672                         mpi_dt,          // MPI datatype to send 
00673                         nnPE,            // ID of destination PE 
00674                         dir,             // Message-tag based on dirn 
00675                         Cart_Comm,     // The communicator 
00676                         &request         // RETURNS, the request handle 
00677                 );
00678         else 
00679             MPI_Irecv( addr,              // base-address of the data 
00680                        1,                 // Number of items to recieve, one struct
00681                        mpi_dt,            // MPI datatype to recv 
00682                        nnPE,              // ID of source PE 
00683                        dir-((dir%2)*2-1), // Tag based on dirn 
00684                        Cart_Comm,       // The communicator 
00685                        &request           // RETURNS, the request handle 
00686                 );
00687     
00688         // Add the new request to the req. handler:
00689         ReqMan->AddRequest(request);
00690 
00691         return;
00692     }
00693 
00694 //----------------------------------------------------------------
00705 /* ----------------------------------------------------------------- */
00706     void ParseCommsParam(char *envvar) {
00707     
00708         enum { NULL_READ, GRID_READ, LOGF_READ, SEED_READ, SEEDFILE_READ};
00709 
00710         char *parameters;
00711         char  f_line[STRING_MAX_LEN], *def_token, *tok_pos;
00712         int  idirn, read_state, io_state;
00713 
00714         /* NULL the file pointer in case this routine fails */
00715         logFile = NULL;
00716 
00717         // Determine if the string holds the parameters or a file name
00718     
00719         bool read_from_file = true;
00720         for(int i=0; i<strlen(envvar) && read_from_file==true; i++ )
00721             if( envvar[i] == '{' ) read_from_file = false;
00722         
00723         if(read_from_file) {    
00724 
00725             FILE *fp = Fopen(envvar,"r");
00726             if( fp == NULL ) RaiseError("MPIParseCommsParam: Could not open comms parameter file!");
00727             /* Lookup the file size and define a suitably sized buffer */
00728             fseek(fp, 0, SEEK_END);
00729 
00730             parameters = (char*)malloc( ftell(fp) * sizeof(char) );
00731             fseek(fp, 0, SEEK_SET);
00732 
00733             // Read the file line-by-line and put the whole thing into parameters.
00734         
00735             if(!parameters)
00736                 RaiseError("MPIParseCommsParam: malloc failed for file buffer.");
00737             strcpy(parameters,"");
00738 
00739             while( fscanf(fp,"%[^\n]\n",f_line) != EOF ) strcat(parameters,f_line);
00740             Fclose(fp);
00741 
00742         }else
00743             parameters = envvar;
00744 
00745         /* Set initial (null/invalid) values for the user parameters: */
00746         for(int i=0; i<NDIM; i++) peGrid[i] = -1;
00747         strcpy(logFileName,"!!empty!!");
00748 
00749         /* Now attempt to decipher the definition string held in comm_def */
00750         /* This is done by breaking the string down into a stream of tokens */
00751         read_state = NULL_READ;
00752         tok_pos = parameters;
00753         while( def_token = (char*)CommsStringTokenizer(parameters, 
00754                                                               "{} =,\n\t", 
00755                                                               &tok_pos) ) {
00756                 
00757             /* Look up the number of processors in each direction. */
00758             /* If we find the `grid' token, change into GRID_READ mode */
00759             if( strcmp(def_token,"GRID") == 0 ) {
00760                 read_state = GRID_READ;
00761                 idirn = 0;
00762             } else if( read_state == GRID_READ ) { 
00763                 /* After `grid', read NDIM*ints into the peGrid array */
00764                 if( idirn < NDIM ) {
00765                     io_state = sscanf(def_token,"%i",&peGrid[idirn]);
00766                     idirn++;
00767                     if( idirn == NDIM ) read_state = NULL_READ; /* Have we finished? */
00768                 }
00769             }
00770 
00771             /* Get the name of the logfile for verbose output */
00772             if( strcmp(def_token,"LOGFILE") == 0 ) {
00773                 read_state = LOGF_READ;
00774             } else if( read_state == LOGF_READ ) {
00775                 /* Grab the filename token */
00776                 strcpy(logFileName,def_token);
00777                 read_state = NULL_READ; /* and finish */
00778             }
00779 
00780             /* Get the specified RNG seed */
00781             if( strcmp(def_token,"SEED") == 0 ) {
00782                 read_state = SEED_READ;
00783             } else if( read_state == SEED_READ ) {
00784                 io_state = sscanf(def_token,"%i", &RNGseed );
00785                 read_state = NULL_READ;
00786             }
00787 
00788             /* Get the specified RNG seeds filename*/
00789             if( strcmp(def_token,"SEEDFILE") == 0 ) {
00790                 read_state = SEEDFILE_READ;
00791             } else if( read_state == SEEDFILE_READ ) {
00792                 io_state = sscanf(def_token,"%s", &seedFileName );
00793                 read_state = NULL_READ;
00794             }
00795 
00796         }
00797 
00798         /* Free the memory associated with the file buffer if required */
00799         if(read_from_file) free(parameters);
00800 
00801         /* If any necessary parameters have not been specified properly, exit */
00802         /* Checking the processor-element grid specification: */
00803         for( idirn = 0; idirn < NDIM; idirn++ ) 
00804             if( peGrid[idirn] < 0 ) 
00805                 RaiseError("MPIParseCommsParam: Processor array dimensions have not been specified correctly.");
00806         
00807 
00808     }
00809 
00810 //----------------------------------------------------------------
00814 //----------------------------------------------------------------
00815 
00816     char *CommsStringTokenizer(char* str, const char* delim, char** tok_pos ) {
00817         char *tokenstr, *substr;
00818         int i, tokenstate, toki, isgap, idel, tok_find;
00819     
00820         substr = *tok_pos;
00821 
00822         if( substr[0] != '0' ) {
00823             // Not at the end of the string, so find the next token:
00824             tokenstr = (char*)malloc( strlen(substr) );
00825             tokenstate = 0; toki = 0;
00826             for( i=0; i<=strlen(substr); i++ ) {
00827                 // Determine if the current character is one of the delimiters;
00828                 idel = 0; tok_find = 0;
00829                 while( idel < strlen(delim)+1 ) { //<The end-of-string 0 is a delimiter.
00830                     if( substr[i] == delim[idel] ) {
00831                         tok_find = idel+1;
00832                         idel = strlen(delim)+1;
00833                     }
00834                     idel++;
00835                 }
00836                 if( tok_find == 0 ) {
00837                     isgap = 0;
00838                 } else {
00839                     isgap = 1;
00840                 }
00841 
00842                 if( i == 0 && isgap == 0 ) tokenstate = 1;
00843                 if( tokenstate == 0 && isgap == 0 ) {
00844                     tokenstate = 1;
00845                     // A token has begun:
00846                     tokenstr[toki] = substr[i];
00847                     toki++;
00848                 } else if( tokenstate == 1 ) {
00849                     if( isgap == 0 ) {
00850                         // A token continues:
00851                         tokenstr[toki] = substr[i];
00852                         toki++;
00853                     } else {
00854                         // We have found a token, so return it:
00855                         *tok_pos = &(substr[i]);
00856                         tokenstr[toki] = 0;
00857                         return( tokenstr );
00858                     }
00859                 }
00860                 //printf("tokenizer: %i %i %i\n", tokenstate, isgap, toki );
00861             }
00862         }
00863 
00864         // If the code gets to here we are at the end of the string:
00865         return(NULL);
00866     }
00867 
00868 //----------------------------------------------------------------
00874 //----------------------------------------------------------------
00875 
00876     MPI_Datatype MPITypeConv( Type_tag t, size_t tsize ) {
00877 
00878         /* Check arguments make sense */
00879         if( t != TYPE_IFloat && t != TYPE_int )
00880             RaiseError("SCUMPITypeConv: unknown data type!");
00881         if( tsize <= 0 )
00882             RaiseError("SCUMPITypeConv: size of data type is <= 0!");
00883 
00884 
00885         MPI_Datatype int_types[N_INT_TYPES] = { MPI_CHAR, MPI_SHORT, MPI_INT, MPI_LONG };
00886         MPI_Datatype IFloat_types[N_FLOAT_TYPES] = { MPI_FLOAT, MPI_DOUBLE, MPI_LONG_DOUBLE };
00887         char err_str[STRING_MAX_LEN];
00888 
00889         int i, mpisize;
00890 
00891         /* Go through int OR IFloat types */
00892 
00893         if( t == TYPE_int ) {
00894             for( i=0; i < N_INT_TYPES; i++ ) {
00895                 MPI_Type_size( int_types[i], &mpisize );  /* Get size of this MPI type */
00896                 if( tsize == mpisize )               // If we have a match 
00897                     return( int_types[i] );          // return the matched type. 
00898             
00899             }
00900             /* if this executes, no suitable type has not been found, so raise an error */
00901             sprintf(err_str,"SCUMPITypeConv: no suitable %i-byte int type among MPI primitive types",tsize);
00902             RaiseError(err_str);
00903 
00904             /* IFloat types */
00905         } else if( t == TYPE_IFloat ) {
00906             for( i=0; i < N_FLOAT_TYPES; i++ ) {
00907                 MPI_Type_size( IFloat_types[i], &mpisize );  /* Get size of this MPI type */
00908                 if( tsize == mpisize )                // If we have a match
00909                     return( IFloat_types[i] );        // return the matched type.
00910             
00911             }
00912             /* if this executes, no suitable type has not been found, so raise an error */
00913             sprintf(err_str,"no suitable %i-byte IFloat type among MPI primitive types",tsize);
00914             RaiseError(err_str);
00915 
00916         }
00917 
00918         /* This statement should never execute, however just to check, and keep 
00919            the compiler happy, we shall say: */
00920         RaiseError("SCUMPITypeConv: running unrunnable section of SCUMPITypeConv!  Possible memory access problem?");
00921         return(( MPI_Datatype)0 );
00922 
00923     }
00924 
00925 //----------------------------------------------------------------
00929 //----------------------------------------------------------------
00930 
00931     unsigned int ReadSeedFile( void ) {
00932         FILE *seedfp = NULL;
00933         int i, io_state, n = peNum;
00934         unsigned int *iseed, seed; 
00935 
00936         // Check we have actually been initialised:
00937         if( !Is_Initialised ) CommsInit();
00938 
00939 #ifdef MPISCU_DEBUG
00940         fprintf_all(logFile,"MPISCU::ReadSeedFile: Opening seed file %s.\n", seedFileName);
00941 #endif
00942 
00943         // Create the seeds buffer:
00944         iseed = new unsigned int[n+1];
00945     
00946         // Open the file:
00947         seedfp = Fopen(seedFileName, "r" );
00948         if( seedfp == NULL ) 
00949             RaiseError("SCUReadSeedFile: could not open seed file!\n");
00950     
00951         // Read in n seeds:
00952         i = 0; while( i < n && fscanf(seedfp,"%u",&(iseed[i])) != EOF ) i++;
00953     
00954         // Close the file:
00955         Fclose(seedfp); seedfp = NULL;
00956     
00957         // Die if the file ended before all seeds had been read in:
00958         if( i < n )
00959             RaiseError("SCUReadSeedFile: not enough seeds have been supplied in the seed file!");
00960         // XXX, EXTREME warning.  This killed one thread and then hung.
00961     
00962         // Get the seed which belongs to this PE:
00963         seed = iseed[peRank];
00964 
00965         // Delete the seeds buffer:
00966         delete [] iseed;
00967 
00968         // Return this PE's seed:
00969         return seed;
00970     }
00971     
00972 } //namespace MPISCU
00973 
00974 
00975 
00976 
00977 
00978 
00979 CPS_END_NAMESPACE

Generated on Sat Oct 10 14:11:22 2009 for Columbia Physics System by  doxygen 1.3.9.1