Skip to content

Commit 777ab5c

Browse files
committed
runtime: fix MemStats.{PauseNS,PauseEnd,PauseTotalNS,LastGC}
These memstats are currently being computed by gcMark, which was appropriate in Go 1.4, but gcMark is now just one part of a bigger picture. In particular, it can't account for the sweep termination pause time, it can't account for all of the mark termination pause time, and the reported "pause end" and "last GC" times will be slightly earlier than they really are. Lift computing of these statistics into func gc, which has the appropriate visibility into the process to compute them correctly. Fixes one of the issues in #10323. This does not add new statistics appropriate to the concurrent collector; it simply fixes existing statistics that are being misreported. Change-Id: I670cb16594a8641f6b27acf4472db15b6e8e086e Reviewed-on: https://go-review.googlesource.com/11794 Reviewed-by: Russ Cox <[email protected]>
1 parent ad60cd8 commit 777ab5c

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

src/runtime/malloc_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestMemStats(t *testing.T) {
3232
st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
3333
st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
3434
st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
35-
st.NextGC > 1e10 || st.NumGC > 1e9 {
35+
st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 {
3636
t.Fatalf("Insanely high value (overflow?): %+v", *st)
3737
}
3838

@@ -48,6 +48,21 @@ func TestMemStats(t *testing.T) {
4848
if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe {
4949
t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe)
5050
}
51+
52+
var pauseTotal uint64
53+
for _, pause := range st.PauseNs {
54+
pauseTotal += pause
55+
}
56+
if int(st.NumGC) < len(st.PauseNs) {
57+
// We have all pauses, so this should be exact.
58+
if st.PauseTotalNs != pauseTotal {
59+
t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
60+
}
61+
} else {
62+
if st.PauseTotalNs < pauseTotal {
63+
t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
64+
}
65+
}
5166
}
5267

5368
func TestStringConcatenationAllocs(t *testing.T) {

src/runtime/mgc.go

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,9 @@ func gc(mode int) {
855855
var tSweepTerm, tScan, tInstallWB, tMark, tMarkTerm int64
856856
var heap0, heap1, heap2, heapGoal uint64
857857

858+
// memstats statistics
859+
var now, pauseStart, pauseNS int64
860+
858861
// Ok, we're doing it! Stop everybody else
859862
semacquire(&worldsema, false)
860863

@@ -869,12 +872,17 @@ func gc(mode int) {
869872
sweep.nbgsweep++
870873
}
871874

875+
if trace.enabled {
876+
traceGCStart()
877+
}
878+
872879
if mode == gcBackgroundMode {
873880
gcBgMarkStartWorkers()
874881
}
882+
now = nanotime()
875883
if debug.gctrace > 0 {
876884
stwprocs, maxprocs = gcprocs(), gomaxprocs
877-
tSweepTerm = nanotime()
885+
tSweepTerm = now
878886
if mode == gcBackgroundMode {
879887
// We started GC when heap_live == next_gc,
880888
// but the mutator may have allocated between
@@ -885,10 +893,7 @@ func gc(mode int) {
885893
}
886894
}
887895

888-
if trace.enabled {
889-
traceGCStart()
890-
}
891-
896+
pauseStart = now
892897
systemstack(stopTheWorldWithSema)
893898
systemstack(finishsweep_m) // finish sweep before we start concurrent scan.
894899
// clearpools before we start the GC. If we wait they memory will not be
@@ -931,8 +936,10 @@ func gc(mode int) {
931936

932937
// Concurrent scan.
933938
startTheWorldWithSema()
939+
now = nanotime()
940+
pauseNS += now - pauseStart
934941
if debug.gctrace > 0 {
935-
tScan = nanotime()
942+
tScan = now
936943
}
937944
gcscan_m()
938945

@@ -985,9 +992,11 @@ func gc(mode int) {
985992
}
986993

987994
// Begin mark termination.
995+
now = nanotime()
988996
if debug.gctrace > 0 {
989-
tMarkTerm = nanotime()
997+
tMarkTerm = now
990998
}
999+
pauseStart = now
9911000
systemstack(stopTheWorldWithSema)
9921001
// The gcphase is _GCmark, it will transition to _GCmarktermination
9931002
// below. The important thing is that the wb remains active until
@@ -1090,13 +1099,22 @@ func gc(mode int) {
10901099
throw("gc done but gcphase != _GCoff")
10911100
}
10921101

1102+
// Update timing memstats
1103+
now, unixNow := nanotime(), unixnanotime()
1104+
pauseNS += now - pauseStart
1105+
atomicstore64(&memstats.last_gc, uint64(unixNow)) // must be Unix time to make sense to user
1106+
memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(pauseNS)
1107+
memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow)
1108+
memstats.pause_total_ns += uint64(pauseNS)
1109+
1110+
memstats.numgc++
1111+
10931112
systemstack(startTheWorldWithSema)
10941113
semrelease(&worldsema)
10951114

10961115
releasem(mp)
10971116
mp = nil
10981117

1099-
memstats.numgc++
11001118
if debug.gctrace > 0 {
11011119
tEnd := nanotime()
11021120

@@ -1335,7 +1353,6 @@ func gcMark(start_time int64) {
13351353
if gcphase != _GCmarktermination {
13361354
throw("in gcMark expecting to see gcphase as _GCmarktermination")
13371355
}
1338-
t0 := start_time
13391356
work.tstart = start_time
13401357

13411358
gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
@@ -1434,13 +1451,6 @@ func gcMark(start_time int64) {
14341451
traceHeapAlloc()
14351452
traceNextGC()
14361453
}
1437-
1438-
t4 := nanotime()
1439-
unixNow := unixnanotime()
1440-
atomicstore64(&memstats.last_gc, uint64(unixNow)) // must be Unix time to make sense to user
1441-
memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(t4 - t0)
1442-
memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow)
1443-
memstats.pause_total_ns += uint64(t4 - t0)
14441454
}
14451455

14461456
func gcSweep(mode int) {

0 commit comments

Comments
 (0)