Skip to content

Commit 8ac98e7

Browse files
committed
runtime: add scavtrace debug flag and remove scavenge info from gctrace
Currently, scavenging information is printed if the gctrace debug variable is >0. Scavenging information is also printed naively, for every page scavenged, resulting in a lot of noise when the typical expectation for GC trace is one line per GC. This change adds a new GODEBUG flag called scavtrace which prints scavenge information roughly once per GC cycle and removes any scavenge information from gctrace. The exception is debug.FreeOSMemory, which may force an additional line to be printed. Fixes #32952. Change-Id: I4177dcb85fe3f9653fd74297ea93c97c389c1811 Reviewed-on: https://go-review.googlesource.com/c/go/+/212640 Run-TryBot: Michael Knyszek <[email protected]> Reviewed-by: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 509592d commit 8ac98e7

File tree

5 files changed

+51
-28
lines changed

5 files changed

+51
-28
lines changed

src/runtime/extern.go

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,6 @@ It is a comma-separated list of name=val pairs setting these named variables:
7878
If the line ends with "(forced)", this GC was forced by a
7979
runtime.GC() call.
8080
81-
Setting gctrace to any value > 0 also causes the garbage collector
82-
to emit a summary when memory is released back to the system.
83-
This process of returning memory to the system is called scavenging.
84-
The format of this summary is subject to change.
85-
Currently it is:
86-
scvg#: # MB released printed only if non-zero
87-
scvg#: inuse: # idle: # sys: # released: # consumed: # (MB)
88-
where the fields are as follows:
89-
scvg# the scavenge cycle number, incremented at each scavenge
90-
inuse: # MB used or partially used spans
91-
idle: # MB spans pending scavenging
92-
sys: # MB mapped from the system
93-
released: # MB released to the system
94-
consumed: # MB allocated from the system
95-
9681
madvdontneed: setting madvdontneed=1 will use MADV_DONTNEED
9782
instead of MADV_FREE on Linux when returning memory to the
9883
kernel. This is less efficient, but causes RSS numbers to drop
@@ -114,6 +99,19 @@ It is a comma-separated list of name=val pairs setting these named variables:
11499
115100
scavenge: scavenge=1 enables debugging mode of heap scavenger.
116101
102+
scavtrace: setting scavtrace=1 causes the runtime to emit a single line to standard
103+
error, roughly once per GC cycle, summarizing the amount of work done by the
104+
scavenger as well as the total amount of memory returned to the operating system
105+
and an estimate of physical memory utilization. The format of this line is subject
106+
to change, but currently it is:
107+
scav # KiB work, # KiB total, #% util
108+
where the fields are as follows:
109+
# KiB work the amount of memory returned to the OS since the last scav line
110+
# KiB total how much of the heap at this point in time has been released to the OS
111+
#% util the fraction of all unscavenged memory which is in-use
112+
If the line ends with "(forced)", then scavenging was forced by a
113+
debug.FreeOSMemory() call.
114+
117115
scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
118116
detailed multiline info every X milliseconds, describing state of the scheduler,
119117
processors, threads and goroutines.

src/runtime/mgcscavenge.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,16 +264,10 @@ func bgscavenge(c chan int) {
264264
// Scavenge one page, and measure the amount of time spent scavenging.
265265
start := nanotime()
266266
released = mheap_.pages.scavengeOne(physPageSize, false)
267+
atomic.Xadduintptr(&mheap_.pages.scavReleased, released)
267268
crit = nanotime() - start
268269
})
269270

270-
if debug.gctrace > 0 {
271-
if released > 0 {
272-
print("scvg: ", released>>10, " KB released\n")
273-
}
274-
print("scvg: inuse: ", memstats.heap_inuse>>20, ", idle: ", memstats.heap_idle>>20, ", sys: ", memstats.heap_sys>>20, ", released: ", memstats.heap_released>>20, ", consumed: ", (memstats.heap_sys-memstats.heap_released)>>20, " (MB)\n")
275-
}
276-
277271
if released == 0 {
278272
lock(&scavenge.lock)
279273
scavenge.parked = true
@@ -346,12 +340,39 @@ func (s *pageAlloc) scavenge(nbytes uintptr, locked bool) uintptr {
346340
return released
347341
}
348342

343+
// printScavTrace prints a scavenge trace line to standard error.
344+
//
345+
// released should be the amount of memory released since the last time this
346+
// was called, and forced indicates whether the scavenge was forced by the
347+
// application.
348+
func printScavTrace(released uintptr, forced bool) {
349+
printlock()
350+
print("scav ",
351+
released>>10, " KiB work, ",
352+
atomic.Load64(&memstats.heap_released)>>10, " KiB total, ",
353+
(atomic.Load64(&memstats.heap_inuse)*100)/heapRetained(), "% util",
354+
)
355+
if forced {
356+
print(" (forced)")
357+
}
358+
println()
359+
printunlock()
360+
}
361+
349362
// resetScavengeAddr sets the scavenge start address to the top of the heap's
350363
// address space. This should be called each time the scavenger's pacing
351364
// changes.
352365
//
353366
// s.mheapLock must be held.
354367
func (s *pageAlloc) resetScavengeAddr() {
368+
released := atomic.Loaduintptr(&s.scavReleased)
369+
if debug.scavtrace > 0 {
370+
printScavTrace(released, false)
371+
}
372+
// Subtract from scavReleased instead of just setting it to zero because
373+
// the scavenger could have increased scavReleased concurrently with the
374+
// load above, and we may miss an update by just blindly zeroing the field.
375+
atomic.Xadduintptr(&s.scavReleased, -released)
355376
s.scavAddr = chunkBase(s.end) - 1
356377
}
357378

src/runtime/mheap.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type mheap struct {
7070
// on the swept stack.
7171
sweepSpans [2]gcSweepBuf
7272

73-
_ uint32 // align uint64 fields on 32-bit for atomics
73+
// _ uint32 // align uint64 fields on 32-bit for atomics
7474

7575
// Proportional sweep
7676
//
@@ -1434,11 +1434,8 @@ func (h *mheap) scavengeAll() {
14341434
unlock(&h.lock)
14351435
gp.m.mallocing--
14361436

1437-
if debug.gctrace > 0 {
1438-
if released > 0 {
1439-
print("forced scvg: ", released>>20, " MB released\n")
1440-
}
1441-
print("forced scvg: inuse: ", memstats.heap_inuse>>20, ", idle: ", memstats.heap_idle>>20, ", sys: ", memstats.heap_sys>>20, ", released: ", memstats.heap_released>>20, ", consumed: ", (memstats.heap_sys-memstats.heap_released)>>20, " (MB)\n")
1437+
if debug.scavtrace > 0 {
1438+
printScavTrace(released, true)
14421439
}
14431440
}
14441441

src/runtime/mpagealloc.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,11 @@ type pageAlloc struct {
240240
// The address to start a scavenge candidate search with.
241241
scavAddr uintptr
242242

243+
// The amount of memory scavenged since the last scavtrace print.
244+
//
245+
// Read and updated atomically.
246+
scavReleased uintptr
247+
243248
// start and end represent the chunk indices
244249
// which pageAlloc knows about. It assumes
245250
// chunks in the range [start, end) are

src/runtime/runtime1.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ var debug struct {
312312
madvdontneed int32 // for Linux; issue 28466
313313
sbrk int32
314314
scavenge int32
315+
scavtrace int32
315316
scheddetail int32
316317
schedtrace int32
317318
tracebackancestors int32
@@ -332,6 +333,7 @@ var dbgvars = []dbgVar{
332333
{"madvdontneed", &debug.madvdontneed},
333334
{"sbrk", &debug.sbrk},
334335
{"scavenge", &debug.scavenge},
336+
{"scavtrace", &debug.scavtrace},
335337
{"scheddetail", &debug.scheddetail},
336338
{"schedtrace", &debug.schedtrace},
337339
{"tracebackancestors", &debug.tracebackancestors},

0 commit comments

Comments
 (0)