00001 #include<config.h>
00002 CPS_START_NAMESPACE
00003
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00047
00048 namespace MPISCU{
00049
00050
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
00081
00086
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
00102
00104 static const int NDIM = 5;
00105
00106 static int peGrid[NDIM];
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 }
00118
00119
00120
00121
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
00143
00144
00145
00146
00147
00148
00149 unsigned int Seed(){ return MPISCU::ReadSeedFile(); }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 unsigned int SeedS(){ if( !MPISCU::Is_Initialised ) MPISCU::CommsInit(); return MPISCU::RNGseed; }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 unsigned int SeedT(){ return Seed(); }
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 unsigned int SeedST(){ return SeedS(); }
00180
00181
00182
00183
00184
00185
00186
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
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
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
00289 if( MPISCU::mpi_dt != NULL ) delete[] MPISCU::mpi_dt;
00290
00291
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
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
00351 MPI_Status *stat = new MPI_Status[numreq];
00352
00353 MPI_Waitall( numreq, MPISCU::ReqMan->ReqArray(), stat );
00354
00355 delete[] stat;
00356 #ifdef MPISCU_DEBUG
00357 MPISCU::fprintf_all(MPISCU::logFile,
00358 "SCUTransComplete: finished.\n", numreq );
00359 #endif
00360 }
00361
00362
00363 MPISCU::ReqMan->Clear();
00364
00365 }
00366
00367
00368
00369
00370 namespace MPISCU{
00371
00372
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;
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};
00416 int pe_reorder = 0;
00417
00418
00419 if( Is_Initialised ) return;
00420
00421
00422
00423
00424 RNGseed = 1;
00425 strcpy(seedFileName,"rng.dat");
00426 strcpy(logFileName, "stderr");
00427
00428
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;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 char *envvar = getenv(ENVVAR);
00452 if(envvar){
00453 if(strlen(envvar) == 0) envvar = default_filename;
00454 ParseCommsParam(envvar);
00455 }
00456
00457
00458
00459
00460 MPI_Cart_create( MPI_COMM_WORLD,
00461 NDIM,
00462 peGrid,
00463 grid_periodicity,
00464 pe_reorder,
00465 &Cart_Comm
00466 );
00467
00468
00469 MPI_Comm_rank( Cart_Comm, &peRank );
00470
00471
00472 MPI_Cart_coords( Cart_Comm, peRank, NDIM, pePos );
00473
00474
00475 MPI_Comm_size( Cart_Comm, &peNum );
00476 #define MPISCU_DEBUG
00477 #ifdef MPISCU_DEBUG
00478
00479
00480 if( strcmp(logFileName,"stderr") == 0 )
00481 logFile = stderr;
00482 else if( strcmp(logFileName,"stdout") == 0 )
00483 logFile = stdout;
00484 else {
00485
00486
00487
00488
00489 int ordPEnum = 1 + (int)log10(peNum);
00490 char *PEnum = (char*)malloc( ( ordPEnum + 1 ) * sizeof(char) );
00491 strcat(logFileName,".");
00492
00493
00494 sprintf(PEnum,"%i", ((int)(exp(((double)ordPEnum)*log(10.0))))+peRank);
00495 strcat(logFileName,&PEnum[1]);
00496 free( PEnum );
00497
00498 logFile = Fopen(logFileName,"w");
00499 }
00500 #endif
00501
00502
00503 printf_all("MPISCU::CommsInit: Initializing.\n");
00504
00505
00506
00507 int root_check = 0;
00508 for(int idirn = 0; idirn < NDIM; idirn++ ) root_check+=pePos[idirn];
00509
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,
00514 1,
00515 MPI_INT,
00516 root_array,
00517 1,
00518 MPI_INT,
00519 Cart_Comm
00520 );
00521
00522
00523 for(int ir = 0; ir < peNum; ir++ )
00524 if( root_array[ir] == 0 ) root_pe = ir;
00525
00526
00527
00528
00529 free(root_array);
00530
00531
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
00538 ReqMan = new MPIRequestManager();
00539
00540
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,
00555 idim,
00556 idir,
00557 &dummy,
00558 &(nnList[dir_index])
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
00578 void SCUGlobalSum(Type_tag t,
00579 size_t tsize,
00580 int n,
00581 void *ivec,
00582 void *ovec
00583 ) {
00584 MPI_Datatype mpitype;
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
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
00601 mpitype = MPITypeConv( t, tsize );
00602
00603
00604
00605 MPI_Allreduce(ivec,
00606 ovec,
00607 n,
00608 mpitype,
00609 MPI_SUM,
00610 Cart_Comm
00611 );
00612
00613 }
00614
00615
00616
00625 void RaiseError( char* errstr ) {
00626
00627
00628 ::fprintf(stderr, "Error: %s\n", errstr);
00629
00630
00631 if( Is_Initialised ) MPI_Finalize();
00632
00633 exit(EXIT_FAILURE);
00634 }
00635
00636
00637
00645 void RaiseError( const char* errstring ) {
00646 RaiseError( const_cast<char*>(errstring) );
00647 }
00648
00649
00650
00651
00652
00653
00654
00655
00660
00661 void Trans(void* addr, MPI_Datatype mpi_dt, SCUDir dir, SCUXR sendrx){
00662
00663 MPI_Request request;
00664
00665
00666 int nnPE = nnList[dir];
00667
00668
00669 if( sendrx == SCU_SEND )
00670 MPI_Issend( addr,
00671 1,
00672 mpi_dt,
00673 nnPE,
00674 dir,
00675 Cart_Comm,
00676 &request
00677 );
00678 else
00679 MPI_Irecv( addr,
00680 1,
00681 mpi_dt,
00682 nnPE,
00683 dir-((dir%2)*2-1),
00684 Cart_Comm,
00685 &request
00686 );
00687
00688
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
00715 logFile = NULL;
00716
00717
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
00728 fseek(fp, 0, SEEK_END);
00729
00730 parameters = (char*)malloc( ftell(fp) * sizeof(char) );
00731 fseek(fp, 0, SEEK_SET);
00732
00733
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
00746 for(int i=0; i<NDIM; i++) peGrid[i] = -1;
00747 strcpy(logFileName,"!!empty!!");
00748
00749
00750
00751 read_state = NULL_READ;
00752 tok_pos = parameters;
00753 while( def_token = (char*)CommsStringTokenizer(parameters,
00754 "{} =,\n\t",
00755 &tok_pos) ) {
00756
00757
00758
00759 if( strcmp(def_token,"GRID") == 0 ) {
00760 read_state = GRID_READ;
00761 idirn = 0;
00762 } else if( read_state == GRID_READ ) {
00763
00764 if( idirn < NDIM ) {
00765 io_state = sscanf(def_token,"%i",&peGrid[idirn]);
00766 idirn++;
00767 if( idirn == NDIM ) read_state = NULL_READ;
00768 }
00769 }
00770
00771
00772 if( strcmp(def_token,"LOGFILE") == 0 ) {
00773 read_state = LOGF_READ;
00774 } else if( read_state == LOGF_READ ) {
00775
00776 strcpy(logFileName,def_token);
00777 read_state = NULL_READ;
00778 }
00779
00780
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
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
00799 if(read_from_file) free(parameters);
00800
00801
00802
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
00824 tokenstr = (char*)malloc( strlen(substr) );
00825 tokenstate = 0; toki = 0;
00826 for( i=0; i<=strlen(substr); i++ ) {
00827
00828 idel = 0; tok_find = 0;
00829 while( idel < strlen(delim)+1 ) {
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
00846 tokenstr[toki] = substr[i];
00847 toki++;
00848 } else if( tokenstate == 1 ) {
00849 if( isgap == 0 ) {
00850
00851 tokenstr[toki] = substr[i];
00852 toki++;
00853 } else {
00854
00855 *tok_pos = &(substr[i]);
00856 tokenstr[toki] = 0;
00857 return( tokenstr );
00858 }
00859 }
00860
00861 }
00862 }
00863
00864
00865 return(NULL);
00866 }
00867
00868
00874
00875
00876 MPI_Datatype MPITypeConv( Type_tag t, size_t tsize ) {
00877
00878
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
00892
00893 if( t == TYPE_int ) {
00894 for( i=0; i < N_INT_TYPES; i++ ) {
00895 MPI_Type_size( int_types[i], &mpisize );
00896 if( tsize == mpisize )
00897 return( int_types[i] );
00898
00899 }
00900
00901 sprintf(err_str,"SCUMPITypeConv: no suitable %i-byte int type among MPI primitive types",tsize);
00902 RaiseError(err_str);
00903
00904
00905 } else if( t == TYPE_IFloat ) {
00906 for( i=0; i < N_FLOAT_TYPES; i++ ) {
00907 MPI_Type_size( IFloat_types[i], &mpisize );
00908 if( tsize == mpisize )
00909 return( IFloat_types[i] );
00910
00911 }
00912
00913 sprintf(err_str,"no suitable %i-byte IFloat type among MPI primitive types",tsize);
00914 RaiseError(err_str);
00915
00916 }
00917
00918
00919
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
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
00944 iseed = new unsigned int[n+1];
00945
00946
00947 seedfp = Fopen(seedFileName, "r" );
00948 if( seedfp == NULL )
00949 RaiseError("SCUReadSeedFile: could not open seed file!\n");
00950
00951
00952 i = 0; while( i < n && fscanf(seedfp,"%u",&(iseed[i])) != EOF ) i++;
00953
00954
00955 Fclose(seedfp); seedfp = NULL;
00956
00957
00958 if( i < n )
00959 RaiseError("SCUReadSeedFile: not enough seeds have been supplied in the seed file!");
00960
00961
00962
00963 seed = iseed[peRank];
00964
00965
00966 delete [] iseed;
00967
00968
00969 return seed;
00970 }
00971
00972 }
00973
00974
00975
00976
00977
00978
00979 CPS_END_NAMESPACE