aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mprof.go
diff options
context:
space:
mode:
authorVlad Saioc <vsaioc@uber.com>2025-11-06 09:53:28 +0000
committerMichael Knyszek <mknyszek@google.com>2025-11-12 08:08:34 -0800
commit8873e8bea29ac6de5fecee88b8b81239bd2eb179 (patch)
tree611e017bb3870c45c3d0ab213269e88fddbd9046 /src/runtime/mprof.go
parentb8b84b789e4275aeea491dbdb50536facd1fa7d7 (diff)
downloadgo-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.go25
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
}