Commit fa9b57bb authored by Austin Clements's avatar Austin Clements

runtime: make next_gc ^0 when GC is disabled

When GC is disabled, we set gcpercent to -1. However, we still use
gcpercent to compute several values, such as next_gc and gc_trigger.
These calculations are meaningless when gcpercent is -1 and result in
meaningless values. This is okay in a sense because we also never use
these values if gcpercent is -1, but they're confusing when exposed to
the user, for example via MemStats or the execution trace. It's
particularly unfortunate in the execution trace because it attempts to
plot the underflowed value of next_gc, which scales all useful
information in the heap row into oblivion.

Fix this by making next_gc ^0 when gcpercent < 0. This has the
advantage of being true in a way: next_gc is effectively infinite when
gcpercent < 0. We can also detect this special value when updating the
execution trace and report next_gc as 0 so it doesn't blow up the
display of the heap line.

Change-Id: I4f366e4451f8892a4908da7b2b6086bdc67ca9a9
Reviewed-on: https://go-review.googlesource.com/30016Reviewed-by: default avatarRick Hudson <rlh@golang.org>
parent f8a0c15e
...@@ -187,6 +187,9 @@ func gcinit() { ...@@ -187,6 +187,9 @@ func gcinit() {
// goal = marked * (1 + GOGC/100) // goal = marked * (1 + GOGC/100)
// = trigger / (1 + triggerRatio) * (1 + GOGC/100) // = trigger / (1 + triggerRatio) * (1 + GOGC/100)
memstats.next_gc = uint64(float64(memstats.gc_trigger) / (1 + gcController.triggerRatio) * (1 + float64(gcpercent)/100)) memstats.next_gc = uint64(float64(memstats.gc_trigger) / (1 + gcController.triggerRatio) * (1 + float64(gcpercent)/100))
if gcpercent < 0 {
memstats.next_gc = ^uint64(0)
}
work.startSema = 1 work.startSema = 1
work.markDoneSema = 1 work.markDoneSema = 1
} }
...@@ -434,6 +437,9 @@ func (c *gcControllerState) startCycle() { ...@@ -434,6 +437,9 @@ func (c *gcControllerState) startCycle() {
// Re-compute the heap goal for this cycle in case something // Re-compute the heap goal for this cycle in case something
// changed. This is the same calculation we use elsewhere. // changed. This is the same calculation we use elsewhere.
memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100 memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
if gcpercent < 0 {
memstats.next_gc = ^uint64(0)
}
// Ensure that the heap goal is at least a little larger than // Ensure that the heap goal is at least a little larger than
// the current live heap size. This may not be the case if GC // the current live heap size. This may not be the case if GC
...@@ -1658,6 +1664,9 @@ func gcMark(start_time int64) { ...@@ -1658,6 +1664,9 @@ func gcMark(start_time int64) {
// The next GC cycle should finish before the allocated heap // The next GC cycle should finish before the allocated heap
// has grown by GOGC/100. // has grown by GOGC/100.
memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100 memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
if gcpercent < 0 {
memstats.next_gc = ^uint64(0)
}
if memstats.next_gc < memstats.gc_trigger { if memstats.next_gc < memstats.gc_trigger {
memstats.next_gc = memstats.gc_trigger memstats.next_gc = memstats.gc_trigger
} }
......
...@@ -71,7 +71,7 @@ type mstats struct { ...@@ -71,7 +71,7 @@ type mstats struct {
// Statistics about garbage collector. // Statistics about garbage collector.
// Protected by mheap or stopping the world during GC. // Protected by mheap or stopping the world during GC.
next_gc uint64 // goal heap_live for when next GC ends next_gc uint64 // goal heap_live for when next GC ends; ^0 if disabled
last_gc uint64 // last gc (in absolute time) last_gc uint64 // last gc (in absolute time)
pause_total_ns uint64 pause_total_ns uint64
pause_ns [256]uint64 // circular buffer of recent gc pause lengths pause_ns [256]uint64 // circular buffer of recent gc pause lengths
......
...@@ -1006,5 +1006,10 @@ func traceHeapAlloc() { ...@@ -1006,5 +1006,10 @@ func traceHeapAlloc() {
} }
func traceNextGC() { func traceNextGC() {
if memstats.next_gc == ^uint64(0) {
// Heap-based triggering is disabled.
traceEvent(traceEvNextGC, -1, 0)
} else {
traceEvent(traceEvNextGC, -1, memstats.next_gc) traceEvent(traceEvNextGC, -1, memstats.next_gc)
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment