out.scalar = uint64(in.heapStats.tinyAllocCount)
},
},
+ "/gc/limiter/last-enabled:gc-cycle": {
+ compute: func(_ *statAggregate, out *metricValue) {
+ out.kind = metricKindUint64
+ out.scalar = uint64(gcCPULimiter.lastEnabledCycle.Load())
+ },
+ },
"/gc/pauses:seconds": {
compute: func(_ *statAggregate, out *metricValue) {
hist := out.float64HistOrInit(timeHistBuckets)
Kind: KindUint64,
Cumulative: true,
},
+ {
+ Name: "/gc/limiter/last-enabled:gc-cycle",
+ Description: "GC cycle the last time the GC CPU limiter was enabled. " +
+ "This metric is useful for diagnosing the root cause of an out-of-memory " +
+ "error, because the limiter trades memory for CPU time when the GC's CPU " +
+ "time gets too high. This is most likely to occur with use of SetMemoryLimit. " +
+ "The first GC cycle is cycle 1, so a value of 0 indicates that it was never enabled.",
+ Kind: KindUint64,
+ },
{
Name: "/gc/pauses:seconds",
Description: "Distribution individual GC-related stop-the-world pause latencies.",
only their block. Each block is already accounted for in
allocs-by-size and frees-by-size.
+ /gc/limiter/last-enabled:gc-cycle
+ GC cycle the last time the GC CPU limiter was enabled.
+ This metric is useful for diagnosing the root cause of an out-of-memory
+ error, because the limiter trades memory for CPU time when the GC's CPU
+ time gets too high. This is most likely to occur with use of SetMemoryLimit.
+ The first GC cycle is cycle 1, so a value of 0 indicates that it was never enabled.
+
/gc/pauses:seconds
Distribution individual GC-related stop-the-world pause latencies.
// - fill <= capacity
fill, capacity uint64
}
- // TODO(mknyszek): Export this as a runtime/metric to provide an estimate of
- // how much GC work is being dropped on the floor.
+ // overflow is the cumulative amount of GC CPU time that we tried to fill the
+ // bucket with but exceeded its capacity.
overflow uint64
// gcEnabled is an internal copy of gcBlackenEnabled that determines
// Updated under lock, but may be read concurrently.
lastUpdate atomic.Int64
+ // lastEnabledCycle is the GC cycle that last had the limiter enabled.
+ lastEnabledCycle atomic.Uint32
+
// nprocs is an internal copy of gomaxprocs, used to determine total available
// CPU time.
//
l.bucket.fill = l.bucket.capacity
if !enabled {
l.enabled.Store(true)
+ l.lastEnabledCycle.Store(memstats.numgc + 1)
}
return
}
if l.bucket.fill > l.bucket.capacity {
l.bucket.fill = l.bucket.capacity
l.enabled.Store(true)
+ l.lastEnabledCycle.Store(memstats.numgc + 1)
} else if l.bucket.fill < l.bucket.capacity {
l.enabled.Store(false)
}