Skip to content

Commit 4443681

Browse files
mknyszekpull[bot]
authored andcommitted
runtime: ensure consistency of /gc/scan/*
Currently /gc/scan/total:bytes is computed as a separate sum. Compute it using the same inputs so it's always consistent with the sum of everything else in /gc/scan/*. For #56857. Change-Id: I43d9148a23b1d2eb948ae990193dca1da85df8a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/497880 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Michael Knyszek <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent a9578fa commit 4443681

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

src/runtime/metrics.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,19 +192,25 @@ func initMetrics() {
192192
"/gc/scan/globals:bytes": {
193193
compute: func(in *statAggregate, out *metricValue) {
194194
out.kind = metricKindUint64
195-
out.scalar = gcController.globalsScan.Load()
195+
out.scalar = in.gcStats.globalsScan
196196
},
197197
},
198198
"/gc/scan/heap:bytes": {
199199
compute: func(in *statAggregate, out *metricValue) {
200200
out.kind = metricKindUint64
201-
out.scalar = gcController.heapScan.Load()
201+
out.scalar = in.gcStats.heapScan
202+
},
203+
},
204+
"/gc/scan/stack:bytes": {
205+
compute: func(in *statAggregate, out *metricValue) {
206+
out.kind = metricKindUint64
207+
out.scalar = in.gcStats.stackScan
202208
},
203209
},
204210
"/gc/scan/total:bytes": {
205211
compute: func(in *statAggregate, out *metricValue) {
206212
out.kind = metricKindUint64
207-
out.scalar = gcController.globalsScan.Load() + gcController.heapScan.Load() + gcController.lastStackScan.Load()
213+
out.scalar = in.gcStats.totalScan
208214
},
209215
},
210216
"/gc/heap/allocs-by-size:bytes": {
@@ -318,12 +324,6 @@ func initMetrics() {
318324
hist.counts[len(hist.counts)-1] = memstats.gcPauseDist.overflow.Load()
319325
},
320326
},
321-
"/gc/scan/stack:bytes": {
322-
compute: func(in *statAggregate, out *metricValue) {
323-
out.kind = metricKindUint64
324-
out.scalar = uint64(gcController.lastStackScan.Load())
325-
},
326-
},
327327
"/gc/stack/starting-size:bytes": {
328328
compute: func(in *statAggregate, out *metricValue) {
329329
out.kind = metricKindUint64
@@ -505,6 +505,7 @@ const (
505505
heapStatsDep statDep = iota // corresponds to heapStatsAggregate
506506
sysStatsDep // corresponds to sysStatsAggregate
507507
cpuStatsDep // corresponds to cpuStatsAggregate
508+
gcStatsDep // corresponds to gcStatsAggregate
508509
numStatsDeps
509510
)
510511

@@ -666,6 +667,23 @@ func (a *cpuStatsAggregate) compute() {
666667
// a.cpuStats.accumulate(nanotime(), gcphase == _GCmark)
667668
}
668669

670+
// cpuStatsAggregate represents various GC stats obtained from the runtime
671+
// acquired together to avoid skew and inconsistencies.
672+
type gcStatsAggregate struct {
673+
heapScan uint64
674+
stackScan uint64
675+
globalsScan uint64
676+
totalScan uint64
677+
}
678+
679+
// compute populates the gcStatsAggregate with values from the runtime.
680+
func (a *gcStatsAggregate) compute() {
681+
a.heapScan = gcController.heapScan.Load()
682+
a.stackScan = uint64(gcController.lastStackScan.Load())
683+
a.globalsScan = gcController.globalsScan.Load()
684+
a.totalScan = a.heapScan + a.stackScan + a.globalsScan
685+
}
686+
669687
// nsToSec takes a duration in nanoseconds and converts it to seconds as
670688
// a float64.
671689
func nsToSec(ns int64) float64 {
@@ -682,6 +700,7 @@ type statAggregate struct {
682700
heapStats heapStatsAggregate
683701
sysStats sysStatsAggregate
684702
cpuStats cpuStatsAggregate
703+
gcStats gcStatsAggregate
685704
}
686705

687706
// ensure populates statistics aggregates determined by deps if they
@@ -702,6 +721,8 @@ func (a *statAggregate) ensure(deps *statDepSet) {
702721
a.sysStats.compute()
703722
case cpuStatsDep:
704723
a.cpuStats.compute()
724+
case gcStatsDep:
725+
a.gcStats.compute()
705726
}
706727
}
707728
a.ensured = a.ensured.union(missing)

src/runtime/metrics_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ func TestReadMetricsConsistency(t *testing.T) {
214214
numGC uint64
215215
pauses uint64
216216
}
217+
var totalScan struct {
218+
got, want uint64
219+
}
217220
var cpu struct {
218221
gcAssist float64
219222
gcDedicated float64
@@ -296,6 +299,14 @@ func TestReadMetricsConsistency(t *testing.T) {
296299
for i := range h.Counts {
297300
gc.pauses += h.Counts[i]
298301
}
302+
case "/gc/scan/heap:bytes":
303+
totalScan.want += samples[i].Value.Uint64()
304+
case "/gc/scan/globals:bytes":
305+
totalScan.want += samples[i].Value.Uint64()
306+
case "/gc/scan/stack:bytes":
307+
totalScan.want += samples[i].Value.Uint64()
308+
case "/gc/scan/total:bytes":
309+
totalScan.got = samples[i].Value.Uint64()
299310
case "/sched/gomaxprocs:threads":
300311
if got, want := samples[i].Value.Uint64(), uint64(runtime.GOMAXPROCS(-1)); got != want {
301312
t.Errorf("gomaxprocs doesn't match runtime.GOMAXPROCS: got %d, want %d", got, want)
@@ -387,6 +398,9 @@ func TestReadMetricsConsistency(t *testing.T) {
387398
if gc.pauses < gc.numGC*2 {
388399
t.Errorf("fewer pauses than expected: got %d, want at least %d", gc.pauses, gc.numGC*2)
389400
}
401+
if totalScan.got != totalScan.want {
402+
t.Errorf("/gc/scan/total:bytes doesn't line up with sum of /gc/scan*: total %d vs. sum %d", totalScan.got, totalScan.want)
403+
}
390404
}
391405

392406
func BenchmarkReadMetricsLatency(b *testing.B) {

0 commit comments

Comments
 (0)