127 lines
4.5 KiB
Diff
127 lines
4.5 KiB
Diff
diff --git a/src/runtime/metrics.go b/src/runtime/metrics.go
|
|
index 2061dc0cf0..d0297a7cec 100644
|
|
--- a/src/runtime/metrics.go
|
|
+++ b/src/runtime/metrics.go
|
|
@@ -395,6 +395,12 @@ func initMetrics() {
|
|
out.scalar = uint64(gomaxprocs)
|
|
},
|
|
},
|
|
+ "/sched/goroutine/running:nanoseconds": {
|
|
+ compute: func(_ *statAggregate, out *metricValue) {
|
|
+ out.kind = metricKindUint64
|
|
+ out.scalar = uint64(grunningnanos())
|
|
+ },
|
|
+ },
|
|
"/sched/goroutines:goroutines": {
|
|
compute: func(_ *statAggregate, out *metricValue) {
|
|
out.kind = metricKindUint64
|
|
diff --git a/src/runtime/metrics/description.go b/src/runtime/metrics/description.go
|
|
index dcfe01e67c..50d9392387 100644
|
|
--- a/src/runtime/metrics/description.go
|
|
+++ b/src/runtime/metrics/description.go
|
|
@@ -356,6 +356,11 @@ var allDesc = []Description{
|
|
Description: "The current runtime.GOMAXPROCS setting, or the number of operating system threads that can execute user-level Go code simultaneously.",
|
|
Kind: KindUint64,
|
|
},
|
|
+ {
|
|
+ Name: "/sched/goroutine/running:nanoseconds",
|
|
+ Description: "Wall time spent by the current goroutine in the running state.",
|
|
+ Kind: KindUint64,
|
|
+ },
|
|
{
|
|
Name: "/sched/goroutines:goroutines",
|
|
Description: "Count of live goroutines.",
|
|
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
|
|
index b593d8d812..05f081b4c3 100644
|
|
--- a/src/runtime/metrics/doc.go
|
|
+++ b/src/runtime/metrics/doc.go
|
|
@@ -266,6 +266,9 @@ Below is the full list of supported metrics, ordered lexicographically.
|
|
operating system threads that can execute user-level Go code
|
|
simultaneously.
|
|
|
|
+ /sched/goroutine/running:nanoseconds
|
|
+ Wall time spent by the current goroutine in the running state.
|
|
+
|
|
/sched/goroutines:goroutines
|
|
Count of live goroutines.
|
|
|
|
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
|
|
index 7cd6898a93..027dbf505d 100644
|
|
--- a/src/runtime/proc.go
|
|
+++ b/src/runtime/proc.go
|
|
@@ -1028,13 +1028,24 @@ func casgstatus(gp *g, oldval, newval uint32) {
|
|
}
|
|
}
|
|
|
|
+ now := nanotime()
|
|
if oldval == _Grunning {
|
|
// Track every gTrackingPeriod time a goroutine transitions out of running.
|
|
if casgstatusAlwaysTrack || gp.trackingSeq%gTrackingPeriod == 0 {
|
|
gp.tracking = true
|
|
}
|
|
gp.trackingSeq++
|
|
+
|
|
+ // We're transitioning out of running, record how long we were in the
|
|
+ // state.
|
|
+ gp.runningnanos += now - gp.lastsched
|
|
}
|
|
+ if newval == _Grunning {
|
|
+ // We're transitioning into the running state, record the timestamp for
|
|
+ // subsequent use.
|
|
+ gp.lastsched = now
|
|
+ }
|
|
+
|
|
if !gp.tracking {
|
|
return
|
|
}
|
|
@@ -3413,6 +3424,14 @@ func dropg() {
|
|
setGNoWB(&gp.m.curg, nil)
|
|
}
|
|
|
|
+// grunningnanos returns the wall time spent by current g in the running state.
|
|
+// A goroutine may be running on an OS thread that's descheduled by the OS
|
|
+// scheduler, this time still counts towards the metric.
|
|
+func grunningnanos() int64 {
|
|
+ gp := getg()
|
|
+ return gp.runningnanos + nanotime() - gp.lastsched
|
|
+}
|
|
+
|
|
// checkTimers runs any timers for the P that are ready.
|
|
// If now is not 0 it is the current time.
|
|
// It returns the passed time or the current time if now was passed as 0.
|
|
@@ -3647,6 +3666,8 @@ func goexit0(gp *g) {
|
|
gp.param = nil
|
|
gp.labels = nil
|
|
gp.timer = nil
|
|
+ gp.lastsched = 0
|
|
+ gp.runningnanos = 0
|
|
|
|
if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
|
|
// Flush assist credit to the global pool. This gives
|
|
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
|
|
index 9381d1e3f7..64caf80e7e 100644
|
|
--- a/src/runtime/runtime2.go
|
|
+++ b/src/runtime/runtime2.go
|
|
@@ -488,6 +488,8 @@ type g struct {
|
|
labels unsafe.Pointer // profiler labels
|
|
timer *timer // cached timer for time.Sleep
|
|
selectDone atomic.Uint32 // are we participating in a select and did someone win the race?
|
|
+ lastsched int64 // timestamp when the G last started running
|
|
+ runningnanos int64 // wall time spent in the running state
|
|
|
|
// goroutineProfiled indicates the status of this goroutine's stack for the
|
|
// current in-progress goroutine profile
|
|
diff --git a/src/runtime/sizeof_test.go b/src/runtime/sizeof_test.go
|
|
index 9ce0a3afcd..6ccba1a070 100644
|
|
--- a/src/runtime/sizeof_test.go
|
|
+++ b/src/runtime/sizeof_test.go
|
|
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
|
|
_32bit uintptr // size on 32bit platforms
|
|
_64bit uintptr // size on 64bit platforms
|
|
}{
|
|
- {runtime.G{}, 240, 392}, // g, but exported for testing
|
|
+ {runtime.G{}, 256, 416}, // g, but exported for testing
|
|
{runtime.Sudog{}, 56, 88}, // sudog, but exported for testing
|
|
}
|
|
|