gounwind is a tiny Go library that acts as a drop-in replacement for runtime.Callers()
. It exists to show how simple and fast stack unwinding can theoretically be when using frame pointers.
Compared to runtime.Callers()
, gounwind is:
- ~50 faster
- ~25 lines of code vs thousands
- Totally unsafe for production use
- Unable to recognize inlined functions
- Only works on 64 bit platforms where frame pointers are enabled
The benchmark below shows the performance for unwinding a stack that has 16 frames. The numbers are from my macOS machine and Docker for Linux gives me very similar results.
goos: darwin
goarch: amd64
pkg: github.com/felixge/gounwind
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkUnwind
BenchmarkUnwind/runtime
BenchmarkUnwind/runtime-12 1281306 934.7 ns/op
BenchmarkUnwind/gounwind
BenchmarkUnwind/gounwind-12 65443237 17.69 ns/op
The The Go low-level calling convention on x86-64 article as well as this video were incredibly useful to me while trying to figure this out.
Go includes frame pointers by default since Go 1.7.
There is ongoing work to implement frame pointer unwinding for the Go core.