Change information
Commit message:
runtime: skip printlock when output goes to a goroutine buffer
runtime.Stack prints its traceback through the print* machinery, which
takes printlock, which acquires the process-global debuglock. Stack
diverts its output into the calling goroutine's own writebuf, so the
lock protects nothing and concurrent callers serialize for no reason.
Return early from printlock and printunlock when gp.writebuf is non-nil
and the M is not dying. writebuf is non-nil only for runtime.Stack and a
few runtime tests, so ordinary print output still takes the lock. The
dying check is needed because gwrite ignores writebuf once the M is
dying and writes to stderr, which is shared.
Also move recordForPanic in gwrite below the writebuf check. It takes
printlock itself and mutates the global printBacklog, so two concurrent
Stack calls would otherwise race on it, invisibly to the race detector
since runtime packages are built NoInstrument. Stack output therefore no
longer reaches printBacklog. A traceback is larger than the 512-byte
buffer, so debug.Stack from recovery middleware was already overwriting
the print output leading up to a crash.
Traceback, panic and fatal error output are unchanged. Three benchmarks
and three tests are added, one of which fails if the recordForPanic move
is dropped.
goos: darwin
goarch: arm64
pkg: runtime
cpu: Apple M2 Pro
│ old │ new │
│ sec/op │ sec/op vs base │
Stack-10 1140.5n ± 1% 709.3n ± 1% -37.81% (p=0.000 n=20)
StackParallel-10 1689.5n ± 3% 110.1n ± 2% -93.48% (p=0.000 n=20)
StackAll-10 64.72µ ± 7% 54.71µ ± 1% -15.46% (p=0.000 n=20)
geomean 4.996µ 1.623µ -67.52%
StackParallel used to get slower as procs were added, 936n at one up to
1682n at eight. It now runs 631n down to 109n. B/op and allocs/op are
unchanged.
Fixes #56400
Change-Id: I21e20cdab5971d2c9f62dfd0a03909c9463e1de6
GitHub-Last-Rev: 576943ce779a2cf42a299879295878f4813b629a
GitHub-Pull-Request: golang/go#80807
Files:
- M src/runtime/export_test.go
- M src/runtime/print.go
- M src/runtime/print_test.go
Change size: M
Delta: 3 files changed, 143 insertions(+), 3 deletions(-)
Branch: refs/heads/master