@@ -1232,6 +1232,11 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
12321232 dumpgstatus (gp )
12331233 throw ("casfrom_Gscanstatus: gp->status is not in scan state" )
12341234 }
1235+ // We're transitioning into the running state, record the timestamp for
1236+ // subsequent use.
1237+ if newval == _Grunning {
1238+ gp .lastsched = nanotime ()
1239+ }
12351240 releaseLockRankAndM (lockRankGscan )
12361241}
12371242
@@ -1247,6 +1252,11 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool {
12471252 r := gp .atomicstatus .CompareAndSwap (oldval , newval )
12481253 if r {
12491254 acquireLockRankAndM (lockRankGscan )
1255+ // We're transitioning out of running, record how long we were in the
1256+ // state.
1257+ if oldval == _Grunning {
1258+ gp .runningnanos += nanotime () - gp .lastsched
1259+ }
12501260 }
12511261 return r
12521262
@@ -1312,7 +1322,18 @@ func casgstatus(gp *g, oldval, newval uint32) {
13121322 })
13131323 }
13141324
1325+ now := nanotime ()
1326+ if newval == _Grunning {
1327+ // We're transitioning into the running state, record the timestamp for
1328+ // subsequent use.
1329+ gp .lastsched = now
1330+ }
1331+
13151332 if oldval == _Grunning {
1333+ // We're transitioning out of running, record how long we were in the
1334+ // state.
1335+ gp .runningnanos += now - gp .lastsched
1336+
13161337 // Track every gTrackingPeriod time a goroutine transitions out of running.
13171338 if casgstatusAlwaysTrack || gp .trackingSeq % gTrackingPeriod == 0 {
13181339 gp .tracking = true
@@ -1333,7 +1354,6 @@ func casgstatus(gp *g, oldval, newval uint32) {
13331354 // We transitioned out of runnable, so measure how much
13341355 // time we spent in this state and add it to
13351356 // runnableTime.
1336- now := nanotime ()
13371357 gp .runnableTime += now - gp .trackingStamp
13381358 gp .trackingStamp = 0
13391359 case _Gwaiting :
@@ -1346,7 +1366,6 @@ func casgstatus(gp *g, oldval, newval uint32) {
13461366 // a more representative estimate of the absolute value.
13471367 // gTrackingPeriod also represents an accurate sampling period
13481368 // because we can only enter this state from _Grunning.
1349- now := nanotime ()
13501369 sched .totalMutexWaitTime .Add ((now - gp .trackingStamp ) * gTrackingPeriod )
13511370 gp .trackingStamp = 0
13521371 }
@@ -1357,12 +1376,10 @@ func casgstatus(gp *g, oldval, newval uint32) {
13571376 break
13581377 }
13591378 // Blocking on a lock. Write down the timestamp.
1360- now := nanotime ()
13611379 gp .trackingStamp = now
13621380 case _Grunnable :
13631381 // We just transitioned into runnable, so record what
13641382 // time that happened.
1365- now := nanotime ()
13661383 gp .trackingStamp = now
13671384 case _Grunning :
13681385 // We're transitioning into running, so turn off
@@ -1411,6 +1428,10 @@ func casGToPreemptScan(gp *g, old, new uint32) {
14111428 // ordering between the gscan and synctest locks. The bubble doesn't
14121429 // distinguish between _Grunning and _Gpreempted anyway, so not
14131430 // notifying it is fine.
1431+
1432+ // We're transitioning out of running, record how long we were in the
1433+ // state.
1434+ gp .runningnanos += nanotime () - gp .lastsched
14141435}
14151436
14161437// casGFromPreempted attempts to transition gp from _Gpreempted to
@@ -4220,6 +4241,14 @@ func dropg() {
42204241 setGNoWB (& gp .m .curg , nil )
42214242}
42224243
4244+ // Grunningnanos returns the wall time spent by current g in the running state.
4245+ // A goroutine may be running on an OS thread that's descheduled by the OS
4246+ // scheduler, this time still counts towards the metric.
4247+ func Grunningnanos () int64 {
4248+ gp := getg ()
4249+ return gp .runningnanos + nanotime () - gp .lastsched
4250+ }
4251+
42234252func parkunlock_c (gp * g , lock unsafe.Pointer ) bool {
42244253 unlock ((* mutex )(lock ))
42254254 return true
@@ -4472,6 +4501,8 @@ func gdestroy(gp *g) {
44724501 gp .labels = nil
44734502 gp .timer = nil
44744503 gp .bubble = nil
4504+ gp .lastsched = 0
4505+ gp .runningnanos = 0
44754506
44764507 if gcBlackenEnabled != 0 && gp .gcAssistBytes > 0 {
44774508 // Flush assist credit to the global pool. This gives
0 commit comments