diff options
| author | Vlad Saioc <vsaioc@uber.com> | 2025-11-06 09:53:28 +0000 |
|---|---|---|
| committer | Michael Knyszek <mknyszek@google.com> | 2025-11-12 08:08:34 -0800 |
| commit | 8873e8bea29ac6de5fecee88b8b81239bd2eb179 (patch) | |
| tree | 611e017bb3870c45c3d0ab213269e88fddbd9046 /src/runtime/mprof.go | |
| parent | b8b84b789e4275aeea491dbdb50536facd1fa7d7 (diff) | |
| download | go-8873e8bea29ac6de5fecee88b8b81239bd2eb179.tar.xz | |
runtime,runtime/pprof: clean up goroutine leak profile writing
Cleaned up goroutine leak profile extraction:
- removed the acquisition of goroutineProfile semaphore
- inlined the call to saveg when recording stacks instead of using
doRecordGoroutineProfile, which had side-effects over
goroutineProfile fields.
Added regression tests for goroutine leak profiling frontend for binary
and debug=1 profile formats.
Added stress tests for concurrent goroutine and goroutine leak profile requests.
Change-Id: I55c1bcef11e9a7fb7699b4c5a2353e594d3e7173
GitHub-Last-Rev: 5e9eb3b1d80c4d2d9b668a01f6b39a7b42f7bb45
GitHub-Pull-Request: golang/go#76045
Reviewed-on: https://go-review.googlesource.com/c/go/+/714580
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Diffstat (limited to 'src/runtime/mprof.go')
| -rw-r--r-- | src/runtime/mprof.go | 25 |
1 files changed, 10 insertions, 15 deletions
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index d745d5f5b9..f1703a7eba 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -1261,7 +1261,7 @@ func goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.P //go:linkname pprof_goroutineLeakProfileWithLabels func pprof_goroutineLeakProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { - return goroutineLeakProfileWithLabelsConcurrent(p, labels) + return goroutineLeakProfileWithLabels(p, labels) } // labels may be nil. If labels is non-nil, it must have the same length as p. @@ -1323,30 +1323,26 @@ func goroutineLeakProfileWithLabelsConcurrent(p []profilerecord.StackRecord, lab return work.goroutineLeak.count, false } - // Use the same semaphore as goroutineProfileWithLabelsConcurrent, - // because ultimately we still use goroutine profiles. - semacquire(&goroutineProfile.sema) - - // Unlike in goroutineProfileWithLabelsConcurrent, we don't need to - // save the current goroutine stack, because it is obviously not leaked. - pcbuf := makeProfStack() // see saveg() for explanation // Prepare a profile large enough to store all leaked goroutines. n = work.goroutineLeak.count if n > len(p) { - // There's not enough space in p to store the whole profile, so (per the - // contract of runtime.GoroutineProfile) we're not allowed to write to p - // at all and must return n, false. - semrelease(&goroutineProfile.sema) + // There's not enough space in p to store the whole profile, so + // we're not allowed to write to p at all and must return n, false. return n, false } // Visit each leaked goroutine and try to record its stack. + var offset int forEachGRace(func(gp1 *g) { - if readgstatus(gp1) == _Gleaked { - doRecordGoroutineProfile(gp1, pcbuf) + if readgstatus(gp1)&^_Gscan == _Gleaked { + systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &p[offset], pcbuf) }) + if labels != nil { + labels[offset] = gp1.labels + } + offset++ } }) @@ -1354,7 +1350,6 @@ func goroutineLeakProfileWithLabelsConcurrent(p []profilerecord.StackRecord, lab raceacquire(unsafe.Pointer(&labelSync)) } - semrelease(&goroutineProfile.sema) return n, true } |
