Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime/pprof: block and mutex profile stacks sometimes have "gowrap" root frames #69294

Open
nsrip-dd opened this issue Sep 5, 2024 · 3 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@nsrip-dd
Copy link
Contributor

nsrip-dd commented Sep 5, 2024

Go version

go version go1.23.0 darwin/arm64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/nick.ripley/Library/Caches/go-build'
GOENV='/Users/nick.ripley/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/nick.ripley/go/pkg/mod'
GONOPROXY='redacted'
GONOSUMDB='redacted'
GOOS='darwin'
GOPATH='/Users/nick.ripley/go'
GOPRIVATE='redacted'
GOPROXY='redacted'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.0'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/nick.ripley/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/nick.ripley/sandbox/go/gowrap/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/f3/g91d13pd6kd3vdxts_gsgd1r0000gn/T/go-build334561956=/tmp/go-build -gno-record-gcc-switches -fno-common'

What did you do?

Ran the following program:

package main

import (
	"os"
	"runtime"
	"runtime/pprof"
	"sync"
)

func block1(ch chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	ch <- struct{}{}
}

func block2(ch chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	<-ch
}

func main() {
	runtime.SetBlockProfileRate(1)
	ch := make(chan struct{})
	var wg sync.WaitGroup
	wg.Add(2)
	go block1(ch, &wg)
	go block2(ch, &wg)
	wg.Wait()
	pprof.Lookup("block").WriteTo(os.Stdout, 1)
}

Playground link: https://go.dev/play/p/f_80E-mywSz

EDIT: updated playground example that more clearly demonstrates how aggregation
changes with this issue: https://go.dev/play/p/2dMLkn2MOxt

What did you see happen?

I saw a gowrap function in the root frame:

--- contention:
cycles/second=3158102000
352356 1 @ 0x476488 0x4cc711 0x4380eb 0x46f8e1
#	0x476487	sync.(*WaitGroup).Wait+0x47	/usr/local/go-faketime/src/sync/waitgroup.go:118
#	0x4cc710	main.main+0xf0			/tmp/sandbox2366213254/prog.go:27
#	0x4380ea	runtime.main+0x28a		/usr/local/go-faketime/src/runtime/proc.go:272

2512 1 @ 0x406312 0x4cc565 0x4cc785 0x46f8e1
#	0x406311	runtime.chanrecv1+0x11	/usr/local/go-faketime/src/runtime/chan.go:489
#	0x4cc564	main.block2+0x44	/tmp/sandbox2366213254/prog.go:17
#	0x4cc784	main.main.gowrap2+0x24	/tmp/sandbox2366213254/prog.go:26

What did you expect to see?

I thought it would look roughly similar to what it looked like with Go 1.22:

--- contention:
cycles/second=2272924666
384662 1 @ 0x46bea8 0x4b4e91 0x437eeb 0x465641
#	0x46bea7	sync.(*WaitGroup).Wait+0x47	/usr/local/go-faketime/src/sync/waitgroup.go:116
#	0x4b4e90	main.main+0xf0			/tmp/sandbox198902667/prog.go:27
#	0x437eea	runtime.main+0x28a		/usr/local/go-faketime/src/runtime/proc.go:271

4166 1 @ 0x406852 0x4b4ce7 0x465641
#	0x406851	runtime.chanrecv1+0x11	/usr/local/go-faketime/src/runtime/chan.go:442
#	0x4b4ce6	main.block2+0x46	/tmp/sandbox198902667/prog.go:17

This change wasn't intentional, and I think it would affect how stacks from go foo() calls at different call sites are aggregated. Probably changed due to https://go.dev/cl/598515. I'm not sure exactly where main.main.gowrap2 would have come from. The stack for the mutex and block profile gets modified a few times (here and here) and I'm not sure if we're either failing to remove that wrapper or adding it back. We may also need to drop the wrapper frames at sample time.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Sep 5, 2024
@dmitshur
Copy link
Contributor

dmitshur commented Sep 5, 2024

CC @golang/runtime.

@dmitshur dmitshur added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Sep 5, 2024
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/611241 mentions this issue: runtime/pprof: properly handle wrapper frames in block/mutex profiles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
Development

No branches or pull requests

5 participants