Open rhysh opened 4 months ago
Similar Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
I have a suspicion as to how this is happening, but not a complete picture yet.
The problematic transition you point out also happens from a thread stack. The two cases where such a transition may appear are gopreempt_m
and goyield_m
. The former is only called from newstack
while the latter is only called from goyield
which is on the sema path (for a direct handoff).
I suspect that in one of these paths, gp.sched
is still empty somehow, though I'm not sure how that's possible. That's at least a case where traceStack
may produce a length-1 buffer with a single zero PC in it.
Here's a simple reproducer:
package main
import (
"log"
"os"
"runtime"
"runtime/trace"
)
func main() {
f, err := os.Create("trace.out")
if err != nil {
log.Fatal(err)
}
defer f.Close()
trace.Start(f)
go func() {
for {
// Non-stop preemption points.
g()
}
}()
runtime.GC()
trace.Stop()
}
//go:noinline
func g() {
}
It disproves my theory about gp.sched
being empty. Also, funnily enough, the goroutine created in main
always shows up fine -- it's the GC mark worker that's the problem.
OK, I figured it out. It's that the stack trace has exactly 1 frame in it, but the skip
count is also 1.
In the reproducer, the victim goroutine is the GC mark worker (just like in the original post) and when I lower the skip count from 1 to 0, I see:
M=683710 P=2 G=68 StateTransition Time=253871909721536 Resource=Goroutine(68) Reason="preempted" GoID=68 Running->Runnable
TransitionStack=
runtime.gcMarkDone @ 0x416865
/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgc.go:824
Stack=
runtime.gcMarkDone @ 0x416865
/usr/local/google/home/mknyszek/work/go-1/src/runtime/mgc.go:824
Unfortunately, there's still the question as to why the bottom frame in the mark worker isn't showing up.
Go version
go version devel go1.23-477ad7dd51 Thu Jun 20 16:46:54 2024 +0000 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
What did you see happen?
Some StateTransition Events include a Stack and StateTransition.Stack that are not equal to NoStack, but which also don't contain a stack from the Event's goroutine. Instead, they yield a single zeroed StackFrame (PC of 0x0, Line of 0, File and Func of "").
I've only seen this on
Running->Runnable
transitions, withReason="preempted"
.It's also present in go1.22.4.
Here's the sort of stack I'd expect to see from that execution trace's view of goroutines 25, 26, and 2881:
What did you expect to see?
I expected the stack to be trace.NoStack when no stack was available, or for the stack to contain PC/Func/File/Line corresponding to code that the goroutine had on its stack. I should not see PC of 0x0.
CC @mknyszek @golang/runtime