-
Notifications
You must be signed in to change notification settings - Fork 8
/
MpiUtils.f90
191 lines (159 loc) · 4.66 KB
/
MpiUtils.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
module MpiUtils
implicit none
#ifdef MPI
! use mpi leads to .mod compiler incompatibility errors unless you are very careful
! so stick to old method and add manual interface for gcc10+ compatibility
include "mpif.h"
#if __GNUC__ > 9
interface
subroutine MPI_BCAST(BUFFER, COUNT, DATATYPE, ROOT, COMM, IERROR)
!GCC$ ATTRIBUTES NO_ARG_CHECK :: BUFFER
Type(*) BUFFER
INTEGER COUNT, DATATYPE, ROOT, COMM, IERROR
end subroutine
end interface
#endif
#endif
integer, parameter :: TTimer_dp = Kind(1.d0)
Type TTimer
real(TTimer_dp) start_time
contains
procedure :: Start => TTimer_Start
procedure :: Time => TTimer_Time
procedure :: WriteTime => TTimer_WriteTime
end type TTimer
contains
function GetMpiRank()
integer GetMpiRank
#ifdef MPI
integer ierror
call mpi_comm_rank(mpi_comm_world,GetMPIrank,ierror)
if (ierror/=MPI_SUCCESS) call MpiStop('MPI fail')
#else
GetMpiRank=0
#endif
end function GetMpiRank
function IsMainMPI()
logical IsMainMPI
IsMainMPI = GetMpiRank() == 0
end function IsMainMPI
subroutine MpiStop(Msg)
character(LEN=*), intent(in), optional :: Msg
integer i
#ifdef MPI
integer ierror, MpiRank
#endif
if (present(Msg)) write(*,*) trim(Msg)
#ifdef MPI
call mpi_comm_rank(mpi_comm_world,MPIrank,ierror)
write (*,*) 'MpiStop: ', MpiRank
call MPI_ABORT(MPI_COMM_WORLD,i, ierror)
#endif
i=1 !put breakpoint on this line to debug
#ifndef MPI
if (msg/='') error stop
#endif
stop
end subroutine MpiStop
subroutine MpiStat(MpiID, MpiSize)
implicit none
integer MpiID,MpiSize
#ifdef MPI
integer ierror
call mpi_comm_rank(mpi_comm_world,MpiID,ierror)
if (ierror/=MPI_SUCCESS) call MpiStop('MpiStat: MPI rank')
call mpi_comm_size(mpi_comm_world,MpiSize,ierror)
#else
MpiID=0
MpiSize=1
#endif
end subroutine MpiStat
subroutine MpiQuietWait
!Set MPI thread to sleep, e.g. so can run openmp on cpu instead
#ifdef MPI
integer ierr, STATUS(MPI_STATUS_SIZE)
logical flag
integer i, MpiId, MpiSize
call MpiStat(MpiID, MpiSize)
if (MpiID/=0) then
do
call MPI_IPROBE(0,0,MPI_COMM_WORLD,flag, MPI_STATUS_IGNORE,ierr)
if (flag) then
call MPI_RECV(i,1,MPI_INTEGER, 0,0,MPI_COMM_WORLD,status,ierr)
exit
end if
call sleep(1)
end do
end if
#endif
end subroutine
subroutine MpiWakeQuietWait
#ifdef MPI
integer j, MpiId, MpiSize, ierr,r
call MpiStat(MpiID, MpiSize)
if (MpiID==0) then
do j=1, MpiSize-1
call MPI_ISSEND(MpiId,1,MPI_INTEGER, j,0,MPI_COMM_WORLD,r,ierr)
end do
end if
#endif
end subroutine MpiWakeQuietWait
subroutine MpiShareString(S, from)
character(LEN=:), allocatable :: S
integer from
#ifdef MPI
integer inlen, rank, ierror
rank = GetMpiRank()
if (rank==from) inlen=len(S)
CALL MPI_Bcast(inlen, 1, MPI_INTEGER, from, MPI_COMM_WORLD, ierror)
if (ierror/=MPI_SUCCESS) call MpiStop('MpiShareString: fail')
if (rank /= from ) allocate(character(inlen)::S)
CALL MPI_Bcast(S, LEN(S), MPI_CHARACTER, from, MPI_COMM_WORLD, ierror)
#endif
end subroutine MpiShareString
function TimerTime()
real(TTimer_dp) time
real(TTimer_dp) :: TimerTime
!$ real(TTimer_dp), external :: omp_get_wtime
#ifdef MPI
TimerTime = MPI_WTime()
#else
time = 0
!$ time = OMP_GET_WTIME()
if (time==0) call cpu_time(time)
TimerTime= time
#endif
end function TimerTime
subroutine TTimer_Start(this, time)
class(TTimer) :: this
real(TTimer_dp), intent(out), optional :: time
this%start_time = TimerTime()
if (present(time)) time = this%start_time
end subroutine TTimer_Start
real(TTimer_dp) function TTimer_Time(this)
class(TTimer) :: this
TTimer_Time = TimerTime() - this%start_time
end function TTimer_Time
subroutine TTimer_WriteTime(this,Msg, start)
class(TTimer) :: this
character(LEN=*), intent(in), optional :: Msg
real(TTimer_dp), optional :: start
real(TTimer_dp) T, DeltaT
character(LEN=:), allocatable :: tmp
if (present(start)) then
T=start
else
T=this%start_time
end if
DeltaT = TimerTime() - T
if (present(Msg)) then
tmp = trim(Msg)//': '
if (DeltaT > 0.00002 .and. DeltaT < 1000 .and. len_trim(tmp)<24) then
write (*,'(a25,f10.5)') tmp, DeltaT
else
write (*,*) trim(Msg)//': ', DeltaT
end if
end if
if (.not. present(start)) this%start_time = TimerTime()
end subroutine TTimer_WriteTime
end module MpiUtils