Skip to content

Commit

Permalink
runtime/metrics: add CPU stats
Browse files Browse the repository at this point in the history
This changes adds a breakdown for estimated CPU usage by time. These
estimates are not based on real on-CPU counters, so each metric has a
disclaimer explaining so. They can, however, be more reasonably
compared to a total CPU time metric that this change also adds.

Fixes #47216.

Change-Id: I125006526be9f8e0d609200e193da5a78d9935be
Reviewed-on: https://go-review.googlesource.com/c/go/+/404307
Reviewed-by: Michael Pratt <[email protected]>
Reviewed-by: Josh MacDonald <[email protected]>
Auto-Submit: Michael Knyszek <[email protected]>
Reviewed-by: David Chase <[email protected]>
Run-TryBot: Michael Knyszek <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
mknyszek authored and gopherbot committed Sep 16, 2022
1 parent 87eda2a commit b7c28f4
Show file tree
Hide file tree
Showing 11 changed files with 459 additions and 21 deletions.
98 changes: 98 additions & 0 deletions src/runtime/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,83 @@ func initMetrics() {
out.scalar = uint64(NumCgoCall())
},
},
"/cpu/classes/gc/mark/assist:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.gcAssistTime))
},
},
"/cpu/classes/gc/mark/dedicated:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.gcDedicatedTime))
},
},
"/cpu/classes/gc/mark/idle:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.gcIdleTime))
},
},
"/cpu/classes/gc/pause:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.gcPauseTime))
},
},
"/cpu/classes/gc/total:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.gcTotalTime))
},
},
"/cpu/classes/idle:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.idleTime))
},
},
"/cpu/classes/scavenge/assist:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.scavengeAssistTime))
},
},
"/cpu/classes/scavenge/background:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.scavengeBgTime))
},
},
"/cpu/classes/scavenge/total:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.scavengeTotalTime))
},
},
"/cpu/classes/total:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.totalTime))
},
},
"/cpu/classes/user:cpu-seconds": {
deps: makeStatDepSet(cpuStatsDep),
compute: func(in *statAggregate, out *metricValue) {
out.kind = metricKindFloat64
out.scalar = float64bits(nsToSec(in.cpuStats.userTime))
},
},
"/gc/cycles/automatic:gc-cycles": {
deps: makeStatDepSet(sysStatsDep),
compute: func(in *statAggregate, out *metricValue) {
Expand Down Expand Up @@ -345,6 +422,7 @@ type statDep uint
const (
heapStatsDep statDep = iota // corresponds to heapStatsAggregate
sysStatsDep // corresponds to sysStatsAggregate
cpuStatsDep // corresponds to cpuStatsAggregate
numStatsDeps
)

Expand Down Expand Up @@ -490,6 +568,23 @@ func (a *sysStatsAggregate) compute() {
})
}

// cpuStatsAggregate represents CPU stats obtained from the runtime
// acquired together to avoid skew and inconsistencies.
type cpuStatsAggregate struct {
cpuStats
}

// compute populates the cpuStatsAggregate with values from the runtime.
func (a *cpuStatsAggregate) compute() {
a.cpuStats = work.cpuStats
}

// nsToSec takes a duration in nanoseconds and converts it to seconds as
// a float64.
func nsToSec(ns int64) float64 {
return float64(ns) / 1e9
}

// statAggregate is the main driver of the metrics implementation.
//
// It contains multiple aggregates of runtime statistics, as well
Expand All @@ -499,6 +594,7 @@ type statAggregate struct {
ensured statDepSet
heapStats heapStatsAggregate
sysStats sysStatsAggregate
cpuStats cpuStatsAggregate
}

// ensure populates statistics aggregates determined by deps if they
Expand All @@ -517,6 +613,8 @@ func (a *statAggregate) ensure(deps *statDepSet) {
a.heapStats.compute()
case sysStatsDep:
a.sysStats.compute()
case cpuStatsDep:
a.cpuStats.compute()
}
}
a.ensured = a.ensured.union(missing)
Expand Down
116 changes: 116 additions & 0 deletions src/runtime/metrics/description.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,122 @@ var allDesc = []Description{
Kind: KindUint64,
Cumulative: true,
},
{
Name: "/cpu/classes/gc/mark/assist:cpu-seconds",
Description: "Estimated total CPU time goroutines spent performing GC tasks " +
"to assist the GC and prevent it from falling behind the application. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/gc/mark/dedicated:cpu-seconds",
Description: "Estimated total CPU time spent performing GC tasks on " +
"processors (as defined by GOMAXPROCS) dedicated to those tasks. " +
"This includes time spent with the world stopped due to the GC. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/gc/mark/idle:cpu-seconds",
Description: "Estimated total CPU time spent performing GC tasks on " +
"spare CPU resources that the Go scheduler could not otherwise find " +
"a use for. This should be subtracted from the total GC CPU time to " +
"obtain a measure of compulsory GC CPU time. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/gc/pause:cpu-seconds",
Description: "Estimated total CPU time spent with the application paused by " +
"the GC. Even if only one thread is running during the pause, this is " +
"computed as GOMAXPROCS times the pause latency because nothing else " +
"can be executing. This is the exact sum of samples in /gc/pause:seconds " +
"if each sample is multiplied by GOMAXPROCS at the time it is taken. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/gc/total:cpu-seconds",
Description: "Estimated total CPU time spent performing GC tasks. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics. Sum of all metrics in /cpu/classes/gc.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/idle:cpu-seconds",
Description: "Estimated total available CPU time not spent executing any Go or Go runtime code. " +
"In other words, the part of /cpu/classes/total:cpu-seconds that was unused. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/scavenge/assist:cpu-seconds",
Description: "Estimated total CPU time spent returning unused memory to the " +
"underlying platform in response eagerly in response to memory pressure. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/scavenge/background:cpu-seconds",
Description: "Estimated total CPU time spent performing background tasks " +
"to return unused memory to the underlying platform. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/scavenge/total:cpu-seconds",
Description: "Estimated total CPU time spent performing tasks that return " +
"unused memory to the underlying platform. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics. Sum of all metrics in /cpu/classes/scavenge.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/total:cpu-seconds",
Description: "Estimated total available CPU time for user Go code " +
"or the Go runtime, as defined by GOMAXPROCS. In other words, GOMAXPROCS " +
"integrated over the wall-clock duration this process has been executing for. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics. Sum of all metrics in /cpu/classes.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/cpu/classes/user:cpu-seconds",
Description: "Estimated total CPU time spent running user Go code. This may " +
"also include some small amount of time spent in the Go runtime. " +
"This metric is an overestimate, and not directly comparable to " +
"system CPU time measurements. Compare only with other /cpu/classes " +
"metrics.",
Kind: KindFloat64,
Cumulative: true,
},
{
Name: "/gc/cycles/automatic:gc-cycles",
Description: "Count of completed GC cycles generated by the Go runtime.",
Expand Down
84 changes: 84 additions & 0 deletions src/runtime/metrics/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,90 @@ Below is the full list of supported metrics, ordered lexicographically.
/cgo/go-to-c-calls:calls
Count of calls made from Go to C by the current process.
/cpu/classes/gc/mark/assist:cpu-seconds
Estimated total CPU time goroutines spent performing GC tasks
to assist the GC and prevent it from falling behind the application.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/gc/mark/dedicated:cpu-seconds
Estimated total CPU time spent performing GC tasks on
processors (as defined by GOMAXPROCS) dedicated to those tasks.
This includes time spent with the world stopped due to the GC.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/gc/mark/idle:cpu-seconds
Estimated total CPU time spent performing GC tasks on
spare CPU resources that the Go scheduler could not otherwise find
a use for. This should be subtracted from the total GC CPU time to
obtain a measure of compulsory GC CPU time.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/gc/pause:cpu-seconds
Estimated total CPU time spent with the application paused by
the GC. Even if only one thread is running during the pause, this is
computed as GOMAXPROCS times the pause latency because nothing else
can be executing. This is the exact sum of samples in /gc/pause:seconds
if each sample is multiplied by GOMAXPROCS at the time it is taken.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/gc/total:cpu-seconds
Estimated total CPU time spent performing GC tasks.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics. Sum of all metrics in /cpu/classes/gc.
/cpu/classes/idle:cpu-seconds
Estimated total available CPU time not spent executing any Go or Go
runtime code. In other words, the part of /cpu/classes/total:cpu-seconds
that was unused.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/scavenge/assist:cpu-seconds
Estimated total CPU time spent returning unused memory to the
underlying platform in response eagerly in response to memory pressure.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/scavenge/background:cpu-seconds
Estimated total CPU time spent performing background tasks
to return unused memory to the underlying platform.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/cpu/classes/scavenge/total:cpu-seconds
Estimated total CPU time spent performing tasks that return
unused memory to the underlying platform.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics. Sum of all metrics in /cpu/classes/scavenge.
/cpu/classes/total:cpu-seconds
Estimated total available CPU time for user Go code or the Go runtime, as
defined by GOMAXPROCS. In other words, GOMAXPROCS integrated over the
wall-clock duration this process has been executing for.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics. Sum of all metrics in /cpu/classes.
/cpu/classes/user:cpu-seconds
Estimated total CPU time spent running user Go code. This may
also include some small amount of time spent in the Go runtime.
This metric is an overestimate, and not directly comparable to
system CPU time measurements. Compare only with other /cpu/classes
metrics.
/gc/cycles/automatic:gc-cycles
Count of completed GC cycles generated by the Go runtime.
Expand Down
Loading

0 comments on commit b7c28f4

Please sign in to comment.