Skip to content

Commit a544996

Browse files
committed
Measure phase nesting at run time so the budget residual sums only top-level rows
The RESIDUAL was wall minus the sum of every row, including rows nested inside others, so it read strongly negative (-9.9 % on a run whose true residual is +2.3 %). s_phase_tic now keeps a stack of open brackets and records the shallowest and deepest depth each phase opens at; s_phase_toc counts interleaved and orphan closes. The report appends a tier column (T1, T2, or T1-2 when a phase opens at two depths), sums only rows that were top-level on every rank, and says whether every bracket closed innermost-first. The column is appended, never inserted, so existing positional parsers read the same fields. Verified: AMR goldens F57C3A5B and 09E0D257 pass; the budget is valid on both on CPU and on the amdflang OpenMP-offload build, with an identical tier map on each.
1 parent 13788bc commit a544996

1 file changed

Lines changed: 52 additions & 8 deletions

File tree

src/simulation/m_phase_timing.fpp

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,15 @@ module m_phase_timing
188188
integer(8) :: ncall(PH_N) = 0
189189
integer(8) :: tic_c(PH_N) = 0
190190
integer :: depth(PH_N) = 0
191-
real(wp) :: t_wall0 = -1._wp
191+
!> Observed nesting, so the budget validates itself instead of trusting a hand-kept list of top-level rows. open_ids is the
192+
!! stack of brackets open on this rank (each id at most once, by the depth guard, so PH_N bounds it); tier_lo/tier_hi are the
193+
!! shallowest and deepest depth each phase was ever opened at. A phase with tier_lo /= tier_hi is opened both inside and outside
194+
!! another bracket - a shared routine - and cannot be summed at either level. n_interleave counts a toc that was not the
195+
!! innermost open bracket, n_orphan a toc with no tic: either one means some row double counts.
196+
integer :: open_ids(PH_N) = 0, n_open = 0
197+
integer :: tier_lo(PH_N) = huge(1), tier_hi(PH_N) = 0
198+
integer :: n_interleave = 0, n_orphan = 0
199+
real(wp) :: t_wall0 = -1._wp
192200
193201
contains
194202
@@ -201,6 +209,8 @@ contains
201209
if (.not. rank_time_wrt) return
202210
depth(id) = depth(id) + 1
203211
if (depth(id) > 1) return ! outermost bracket only, so nesting cannot double count
212+
n_open = n_open + 1; open_ids(n_open) = id
213+
tier_lo(id) = min(tier_lo(id), n_open); tier_hi(id) = max(tier_hi(id), n_open)
204214
do i = 1, 3
205215
if (id == SR_PH(i)) then; sr_t0(i) = mpi_sr_wait; sr_n0(i) = mpi_sr_calls; end if
206216
end do
@@ -219,9 +229,15 @@ contains
219229
integer :: i
220230
221231
if (.not. rank_time_wrt) return
222-
if (depth(id) <= 0) then; depth(id) = 0; return; end if
232+
if (depth(id) <= 0) then; depth(id) = 0; n_orphan = n_orphan + 1; return; end if
223233
depth(id) = depth(id) - 1
224234
if (depth(id) > 0) return
235+
if (open_ids(n_open) /= id) n_interleave = n_interleave + 1
236+
do i = n_open, 1, -1
237+
if (open_ids(i) == id) then
238+
open_ids(i:n_open - 1) = open_ids(i + 1:n_open); n_open = n_open - 1; exit
239+
end if
240+
end do
225241
$:GPU_WAIT()
226242
call system_clock(c, rate)
227243
acc(id) = acc(id) + real(c - tic_c(id), wp)/real(rate, wp)
@@ -259,7 +275,9 @@ contains
259275
impure subroutine s_phase_report(wall)
260276

261277
real(wp), intent(in) :: wall
262-
real(wp) :: tot, gmax(PH_N), gsum(PH_N)
278+
real(wp) :: tot, gmax(PH_N), gsum(PH_N), t1sum
279+
integer :: gtlo(PH_N), gthi(PH_N), gbad(2), nbad(2)
280+
character(len=8) :: tl
263281
integer(8) :: gcall(PH_N)
264282
integer :: i, ierr, ip
265283
!> Per-rank times for the phases whose IMBALANCE moves with simulation time. mean/max cannot say WHICH rank is slow or
@@ -280,8 +298,13 @@ contains
280298
call MPI_ALLREDUCE(acc, gmax, PH_N, mpi_p, MPI_MAX, MPI_COMM_WORLD, ierr)
281299
call MPI_ALLREDUCE(acc, gsum, PH_N, mpi_p, MPI_SUM, MPI_COMM_WORLD, ierr)
282300
call MPI_ALLREDUCE(ncall, gcall, PH_N, MPI_INTEGER8, MPI_SUM, MPI_COMM_WORLD, ierr)
301+
call MPI_ALLREDUCE(tier_lo, gtlo, PH_N, MPI_INTEGER, MPI_MIN, MPI_COMM_WORLD, ierr)
302+
call MPI_ALLREDUCE(tier_hi, gthi, PH_N, MPI_INTEGER, MPI_MAX, MPI_COMM_WORLD, ierr)
303+
nbad = [n_interleave, n_orphan]
304+
call MPI_ALLREDUCE(nbad, gbad, 2, MPI_INTEGER, MPI_SUM, MPI_COMM_WORLD, ierr)
283305
#else
284306
gmax = acc; gsum = acc*real(num_procs, wp); gcall = ncall*int(num_procs, 8)
307+
gtlo = tier_lo; gthi = tier_hi; gbad = [n_interleave, n_orphan]
285308
#endif
286309
allocate (prank(0:num_procs - 1,NPR))
287310
do i = 1, NPR
@@ -337,16 +360,37 @@ contains
337360
if (proc_rank /= 0) return
338361
print '(A)', '[phase] PHASE BUDGET'
339362
print '(A,F10.3,A)', '[phase] step-loop wall = ', wall, ' s'
340-
print '(A)', '[phase] name mean s max s % wall imbalance calls/rank ms/call'
363+
print '(A)', '[phase] name mean s max s % wall imbalance calls/rank ms/call tier'
341364
do i = 1, PH_N
342365
if (gsum(i) <= 0._wp) cycle
343-
print '(A,A8,F10.3,F9.3,F9.1,A,F8.3,I12,F11.4)', '[phase] ', PH_NAME(i), gsum(i)/real(num_procs, wp), gmax(i), &
366+
if (gtlo(i) == gthi(i)) then
367+
write (tl, '(A,I0)') 'T', gtlo(i)
368+
else
369+
write (tl, '(A,I0,A,I0)') 'T', gtlo(i), '-', gthi(i)
370+
end if
371+
print '(A,A8,F10.3,F9.3,F9.1,A,F8.3,I12,F11.4,2X,A)', '[phase] ', PH_NAME(i), gsum(i)/real(num_procs, wp), gmax(i), &
344372
& 100._wp*(gsum(i)/real(num_procs, wp))/wall, '%', gmax(i)/max(gsum(i)/real(num_procs, wp), tiny(1._wp)), &
345373
& gcall(i)/int(num_procs, 8), 1000._wp*(gsum(i)/real(num_procs, wp))/max(real(gcall(i)/int(num_procs, 8), wp), &
346-
& 1._wp)
374+
& 1._wp), trim(tl)
347375
end do
348-
print '(A,F10.3,F19.1,A)', '[phase] RESIDUAL', wall - sum(gsum)/real(num_procs, wp), &
349-
& 100._wp*(wall - sum(gsum)/real(num_procs, wp))/wall, '%'
376+
! Only rows that were top-level on EVERY rank sum against wall; summing nested rows is what used to drive this negative.
377+
t1sum = sum(gsum, mask=(gthi == 1))/real(num_procs, wp)
378+
print '(A,F10.3,F19.1,A)', '[phase] RESIDUAL', wall - t1sum, 100._wp*(wall - t1sum)/wall, '%'
379+
print '(A,F10.3,A,F6.1,A)', '[phase-tier] T1 rows sum to ', t1sum, ' s =', 100._wp*t1sum/wall, &
380+
& ' % of wall; RESIDUAL is wall minus T1 only'
381+
if (any(gsum > 0._wp .and. gtlo /= gthi)) then
382+
write (*, '(A)', advance='no') '[phase-tier] opened at more than one depth, excluded from T1, not summable:'
383+
do i = 1, PH_N
384+
if (gsum(i) > 0._wp .and. gtlo(i) /= gthi(i)) write (*, '(1X,A)', advance='no') trim(PH_NAME(i))
385+
end do
386+
write (*, '(A)') ''
387+
end if
388+
if (any(gbad > 0)) then
389+
print '(A,I0,A,I0,A)', '[phase-tier] BUDGET INVALID: ', gbad(1), ' interleaved and ', gbad(2), &
390+
& ' orphan brackets, so some row double counts'
391+
else
392+
print '(A)', '[phase-tier] budget valid: every bracket closed innermost-first'
393+
end if
350394

351395
end subroutine s_phase_report
352396

0 commit comments

Comments
 (0)