C $Header: /u/gcmpack/MITgcm/eesupp/src/bar2.F,v 1.7 2009/08/04 18:01:37 jmc Exp $ C $Name: $ #include "CPP_EEOPTIONS.h" CBOP C !ROUTINE: BAR2_INIT C !INTERFACE: SUBROUTINE BAR2_INIT( myThid ) IMPLICIT NONE C !DESCRIPTION: C *=====================================================================* C | SUBROUTINE BAR2\_INIT C | o Setup global barrier data structures. C *=====================================================================* C | Initialise global barrier data structures that can be used in C | conjunction with MPI or that can also be used to create C *=====================================================================* C !USES: C == Global variables == #include "SIZE.h" #include "EEPARAMS.h" #include "EESUPPORT.h" #include "BAR2.h" C C !INPUT/OUTPUT PARAMETERS: C == Routine arguments == C myThid :: Thread number of this instance of BAR2_INIT INTEGER myThid C !LOCAL VARIABLES: C == Local variables == C I :: Loop counter INTEGER I CEOP C DO I = 1, lShare4 BAR2_level(I,myThid) = 0 BAR2_barrierCount(I,myThid) = 0 BAR2_spinsCount(I,myThid) = 0 BAR2_spinsCount(I,myThid) = 0 BAR2_spinsMax (I,myThid) = 0 BAR2_spinsMin (I,myThid) = 1000000000 ENDDO C bar2CollectStatistics = .TRUE. C RETURN END CBOP C !ROUTINE: BAR2 C !INTERFACE: SUBROUTINE BAR2( myThid ) IMPLICIT NONE C !DESCRIPTION: C *=====================================================================* C | SUBROUTINE BAR2 C | o Global barrier routine. C *=====================================================================* C | Implements a simple true shared memory barrier that uses a global C | heap array that all threads can access to synchronise. Each thread C | writes to a predefined location. One thread polls the locations. Other C | threads poll an all clear assertion location. Once the polling C | thread that is looping over locations sees writes for each thread is C | writes the all clear assertion location and everyone proceeds. A C | cyclic series of locations is used to ensure that race conditions do C | not occur. A few simple statistics are recorded giving number of C | barrier calls, max, min and aggregate polling loop counts. C *=====================================================================* C !USES: C == Global variables == #include "SIZE.h" #include "EEPARAMS.h" #include "EESUPPORT.h" #include "BAR2.h" C !INPUT/OUTPUT PARAMETERS: C == Routine arguments == C myThid :: Thread number of this instance of BAR2 INTEGER myThid C !LOCAL VARIABLES: C == Local variables == C myLevel :: Temp. to hold "active" barrier level C nDone :: Temp. for counting number of threads that C have reached the barrier. C I :: Loop counter C spinCount :: Temp. for doing statistics on how many C times barrier code looped. INTEGER myLevel INTEGER nDone INTEGER I INTEGER spinCount CEOP #ifdef USE_OMP_THREADING C$OMP BARRIER BAR2_barrierCount(1,myThid) = BAR2_barrierCount(1,myThid)+1 Cdbg C$OMP BARRIER Cdbg DO I = 2, nThreads Cdbg IF ( BAR2_barrierCount(1,I) .NE. BAR2_barrierCount(1,1) ) THEN Cdbg PRINT *, BAR2_barrierCount(1,1:nThreads) Cdbg CALL SYSTEM('sleep 1') Cdbg PRINT *, BAR2_barrierCount(1,1:nThreads) Cdbg Stop ' bar2 OUT OF SYNC ' Cdbg ENDIF Cdbg ENDDO Cdbg C$OMP BARRIER RETURN #endif spinCount = 0 IF ( myThid .NE. 1 ) THEN BAR2_level(1,myThid) = BAR2_level(1,myThid)+1 myLevel = BAR2_level(1,myThid) 10 CONTINUE IF ( BAR2_level(1,1) .EQ. myLevel ) GOTO 11 spinCount = spinCount+1 CALL FOOL_THE_COMPILER( BAR2_level(1,1) ) GOTO 10 11 CONTINUE ELSE myLevel = BAR2_level(1,1) 12 CONTINUE CALL FOOL_THE_COMPILER( BAR2_level(1,1) ) nDone = 1 DO I = 2, nThreads IF ( BAR2_level(1,1) .EQ. BAR2_level(1,I)-1 ) nDone = nDone+1 ENDDO spinCount = spinCount+1 IF ( nDone .LT. nThreads ) GOTO 12 BAR2_level(1,1) = myLevel+1 ENDIF BAR2_barrierCount(1,myThid) = BAR2_barrierCount(1,myThid)+1 BAR2_spinsCount(1,myThid) = BAR2_spinsCount(1,myThid)+spinCount BAR2_spinsMax (1,myThid) = MAX(BAR2_spinsMax(1,myThid),spinCount) BAR2_spinsMin (1,myThid) = MIN(BAR2_spinsMin(1,myThid),spinCount) RETURN END