Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize zap.Any to allocate less mamory on stack
We have identified an issue where zap.Any can cause performance degradation due to stack size. This is apparently cased by the compiler assigning 4.8kb (a zap.Field per arm of the switch statement) for zap.Any on stack. This can result in an unnecessary runtime.newstack+runtime.copystack. A github issue against Go language is pending. This can be particularly bad if `zap.Any` was to be used in a new goroutine, since the default goroutine sizes can be as low as 2kb (it can vary depending on average stack size - see golang/go#18138). This is an alternative to #1301, @cdvr and me were talking about this, and he inspired this idea with the closure. By using a function and a closure we're able to reduce the size and remove the degradation. At least on my laptop, this change result in a new performance gain, as all benchmarks show reduced time. 10 runs. ``` ❯ benchstat ~/before.txt ~/after-after.txt goos: darwin goarch: arm64 pkg: go.uber.org/zap │ /Users/pawel/before.txt │ /Users/pawel/after-after.txt │ │ sec/op │ sec/op vs base │ AnyInGoroutine/any-12 305.2n ± 3% 297.0n ± 0% ~ (p=0.085 n=10) AnyInGoroutine/int-12 288.0n ± 0% 270.1n ± 1% -6.25% (p=0.000 n=10) AnyInGoroutine/goroutine-12 218.3n ± 6% 209.5n ± 5% -4.05% (p=0.015 n=10) AnyInGoroutine/int-in-go-12 592.7n ± 2% 573.9n ± 2% -3.17% (p=0.000 n=10) AnyInGoroutine/any-in-go-12 666.5n ± 4% 552.3n ± 1% -17.13% (p=0.000 n=10) AnyInGoroutine/int-in-go-with-stack-12 474.4n ± 4% 459.4n ± 6% ~ (p=0.447 n=10+9) AnyInGoroutine/any-in-go-with-stack-12 617.6n ± 4% 468.8n ± 4% -24.09% (p=0.000 n=10) geomean 417.8n 380.1n -9.01% │ /Users/pawel/before.txt │ /Users/pawel/after-after.txt │ │ B/op │ B/op vs base │ AnyInGoroutine/any-12 64.00 ± 0% 64.00 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/int-12 64.00 ± 0% 64.00 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/goroutine-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/int-in-go-12 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=10) AnyInGoroutine/any-in-go-12 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=10) AnyInGoroutine/int-in-go-with-stack-12 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=10+9) ¹ AnyInGoroutine/any-in-go-with-stack-12 88.00 ± 0% 88.00 ± 0% ~ (p=1.000 n=10) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean │ /Users/pawel/before.txt │ /Users/pawel/after-after.txt │ │ allocs/op │ allocs/op vs base │ AnyInGoroutine/any-12 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/int-12 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/goroutine-12 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/int-in-go-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/any-in-go-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ AnyInGoroutine/int-in-go-with-stack-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10+9) ¹ AnyInGoroutine/any-in-go-with-stack-12 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean ```
- Loading branch information