In this trace, the GoCreate event that creates the goroutine to run println("hello") will have a stack trace for the new goroutine (really, the start PC) but will not have the stack trace in the scheduler/timer code that actually creates the goroutine.
The reason for this is simple: traceStack, the function that obtains a stack trace for the tracer, skips taking a stack if it's called from a system stack. This has been true as far back as I can find. The reason why it does this is because it uses the fact that it runs on a system stack as a signal that it should collect gp.mp.curg's stack instead. This is reasonable -- if a goroutine calls into the scheduler to yield, it'll be running on a system stack when we emit the trace event, but we crucially do not care about that location, but where the user code was when we yielded.
The fix here is, I think, straightforward: collect a trace from a system stack if and only if gp.mp.curg is nil. This should be sufficient to capture the time.AfterFunc case and cases like it.
Here is a simple program that reproduces the issue:
In this trace, the
GoCreate
event that creates the goroutine to runprintln("hello")
will have a stack trace for the new goroutine (really, the start PC) but will not have the stack trace in the scheduler/timer code that actually creates the goroutine.The reason for this is simple:
traceStack
, the function that obtains a stack trace for the tracer, skips taking a stack if it's called from a system stack. This has been true as far back as I can find. The reason why it does this is because it uses the fact that it runs on a system stack as a signal that it should collectgp.mp.curg
's stack instead. This is reasonable -- if a goroutine calls into the scheduler to yield, it'll be running on a system stack when we emit the trace event, but we crucially do not care about that location, but where the user code was when we yielded.The fix here is, I think, straightforward: collect a trace from a system stack if and only if
gp.mp.curg
is nil. This should be sufficient to capture thetime.AfterFunc
case and cases like it.