Skip to content

Commit 0e1761f

Browse files
authored
nifmake: compute memory peaks properly (#2566)
1 parent 86c0e94 commit 0e1761f

1 file changed

Lines changed: 36 additions & 4 deletions

File tree

src/nifmake/nifmake.nim

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ type
9898
cmdStats: Table[string, CmdStats]
9999
heaviest: seq[tuple[kib: int, cmdName, label: string]]
100100
## the `HeaviestShown` hungriest nodes, descending
101+
spans: seq[tuple[start, finish: int64, kib: int]]
102+
## lifetime (monotonic nanoseconds) and peak RSS of every executed node;
103+
## `concurrentPeak` sweeps these for the build's memory high-water mark
101104
execWallTime: float
102105

103106
proc addSpace(result: var string) {.inline.} =
@@ -367,15 +370,16 @@ proc toSeconds(d: Duration): float =
367370
const HeaviestShown = 10
368371

369372
proc recordCmd(profile: var ProfileData; cmdName, label: string;
370-
sec: float; peakKiB: int) =
373+
start, finish: MonoTime; peakKiB: int) =
371374
let e = addr profile.cmdStats.mgetOrPut(cmdName, CmdStats())
372-
e.sec += sec
375+
e.sec += toSeconds(finish - start)
373376
inc e.count
374377
e.sumKiB += peakKiB
375378
if peakKiB > e.peakKiB:
376379
e.peakKiB = peakKiB
377380
e.peakLabel = label
378381
if peakKiB > 0:
382+
profile.spans.add (start.ticks, finish.ticks, peakKiB)
379383
var i = profile.heaviest.len
380384
while i > 0 and profile.heaviest[i-1].kib < peakKiB: dec i
381385
if i < HeaviestShown:
@@ -641,8 +645,8 @@ proc runDag(dag: var Dag; opt: set[CliOption]; profile: ptr ProfileData = nil;
641645
pool.del k
642646
close job.process
643647
if profile != nil:
644-
profile[].recordCmd(job.cmdName, job.label,
645-
toSeconds(getMonoTime() - job.start), peakKiB)
648+
profile[].recordCmd(job.cmdName, job.label, job.start, getMonoTime(),
649+
peakKiB)
646650
inc prog.done
647651
prog.draw job.label
648652
if exitCode == 0:
@@ -912,6 +916,30 @@ proc printReport(profile: ProfileData) =
912916
stdout.write $total
913917
stdout.write "\n"
914918

919+
proc concurrentPeak(profile: ProfileData): tuple[kib, jobs: int] =
920+
## Upper bound on the whole build's memory high-water mark: sweeps the node
921+
## lifetimes and sums the peak RSS of everything alive at the same instant.
922+
## Pessimistic on purpose -- a process only sits at its peak briefly, but the
923+
## peaks are all `wait4` hands back, so this is the cheapest honest bound.
924+
## Note that the `peak` column above is a single process, which is why this
925+
## number can be much larger with `--parallel`.
926+
result = (0, 0)
927+
var events = newSeqOfCap[(int64, int)](profile.spans.len * 2)
928+
for s in profile.spans:
929+
events.add (s.start, s.kib)
930+
events.add (s.finish, -s.kib)
931+
# Ties must release before they acquire, otherwise a node that exits exactly
932+
# as its successor starts is counted twice.
933+
events.sort(proc (a, b: (int64, int)): int =
934+
result = cmp(a[0], b[0])
935+
if result == 0: result = cmp(a[1], b[1]))
936+
var cur = 0
937+
var live = 0
938+
for (_, delta) in events:
939+
cur += delta
940+
if delta > 0: inc live else: dec live
941+
if cur > result.kib: result = (cur, live)
942+
915943
proc fmtKiB(kib: int): string =
916944
if kib >= 1024 * 1024: formatFloat(kib / (1024 * 1024), ffDecimal, 1) & " GiB"
917945
else: $(kib div 1024) & " MiB"
@@ -935,6 +963,10 @@ proc printProfile(profile: ProfileData) =
935963
let execTotal = profile.cmdStats.values.toSeq.foldl(a + b.sec, 0.0)
936964
stderr.writeLine " exec total: ", execTotal.formatFloat(ffDecimal, 3), "s"
937965
stderr.writeLine " wall time: ", profile.execWallTime.formatFloat(ffDecimal, 3), "s"
966+
let cp = concurrentPeak(profile)
967+
if cp.kib > 0:
968+
stderr.writeLine " concurrent RSS: ", fmtKiB(cp.kib),
969+
" (upper bound, ", $cp.jobs, " jobs live)"
938970
if profile.heaviest.len > 0:
939971
stderr.writeLine " heaviest nodes (peak RSS):"
940972
for h in profile.heaviest:

0 commit comments

Comments
 (0)