Skip to content

Commit cd2f6ac

Browse files
committed
zap.Any add benchmarks (#1311)
This is a prefactor for #1301, #1302, #1304, #1305, #1307, #1308 and #1310. We're writing various approaches to reduce the stack size and it's painful to keep copy-pasting the tests between PRs. This was suggested in @prashantv in #1307. The tests are mostly based on tests in #1303, but made "more generic", as #1307 we might want to test across more than just a single type. It does make the tests a bit harder to setup. Some of the setup is inconvenient (we duplicate the value in both `typed` and `any` version of the tests) but hopefully okay to understand. A fully non-duplicated alternative would likely require something like #1310 itself. For #1307 in particular a test against interface type would likely be needed, so adding it here too. The tests compare two code paths, with the same arguments, one using a strongly typed method and second using `zap.Any`. We have: - a simple "create field" case for a baseline - a "create and log" case for a realistic case (we typically log the fields) - a "create and log in a goroutine" case for the pathological case we're trying to solve for. - a "create and long in goroutine in a pre-warmed system" that does the above, but before tries to affect the starting goroutine stack size to provide an realistic example. Without this, for any tests with 2+ goroutines, the cost of `zap.Any` is not visible, as we always end up expanding the stack even in the strongly typed methods. The test results are: ``` goos: darwin goarch: arm64 pkg: go.uber.org/zap BenchmarkAny/string-typ-no-logger 166879518 6.988 ns/op 0 B/op 0 allocs/op BenchmarkAny/string-typ-no-logger-12 167398297 6.973 ns/op 0 B/op 0 allocs/op BenchmarkAny/string-any-no-logger 87669631 13.97 ns/op 0 B/op 0 allocs/op BenchmarkAny/string-any-no-logger-12 86760837 14.11 ns/op 0 B/op 0 allocs/op BenchmarkAny/string-typ-logger 3059485 395.5 ns/op 64 B/op 1 allocs/op BenchmarkAny/string-typ-logger-12 3141176 379.7 ns/op 64 B/op 1 allocs/op BenchmarkAny/string-any-logger 2995699 401.3 ns/op 64 B/op 1 allocs/op BenchmarkAny/string-any-logger-12 3071046 391.1 ns/op 64 B/op 1 allocs/op BenchmarkAny/string-typ-logger-go 784323 1351 ns/op 146 B/op 2 allocs/op BenchmarkAny/string-typ-logger-go-12 2000835 613.9 ns/op 96 B/op 2 allocs/op BenchmarkAny/string-any-logger-go 477486 2479 ns/op 117 B/op 2 allocs/op BenchmarkAny/string-any-logger-go-12 1830955 680.0 ns/op 112 B/op 2 allocs/op BenchmarkAny/string-typ-logger-go-stack 841566 1328 ns/op 96 B/op 2 allocs/op BenchmarkAny/string-typ-logger-go-stack-12 2625226 479.6 ns/op 96 B/op 2 allocs/op BenchmarkAny/string-any-logger-go-stack 486084 2493 ns/op 112 B/op 2 allocs/op BenchmarkAny/string-any-logger-go-stack-12 2658640 667.9 ns/op 112 B/op 2 allocs/op BenchmarkAny/stringer-typ-no-logger 147314238 8.034 ns/op 0 B/op 0 allocs/op BenchmarkAny/stringer-typ-no-logger-12 157857937 7.436 ns/op 0 B/op 0 allocs/op BenchmarkAny/stringer-any-no-logger 58872349 20.19 ns/op 0 B/op 0 allocs/op BenchmarkAny/stringer-any-no-logger-12 60532305 20.27 ns/op 0 B/op 0 allocs/op BenchmarkAny/stringer-typ-logger 3094204 411.7 ns/op 64 B/op 1 allocs/op BenchmarkAny/stringer-typ-logger-12 3163489 383.7 ns/op 64 B/op 1 allocs/op BenchmarkAny/stringer-any-logger 2981940 427.2 ns/op 64 B/op 1 allocs/op BenchmarkAny/stringer-any-logger-12 2777792 394.0 ns/op 64 B/op 1 allocs/op BenchmarkAny/stringer-typ-logger-go 911761 1335 ns/op 96 B/op 2 allocs/op BenchmarkAny/stringer-typ-logger-go-12 2006440 605.2 ns/op 96 B/op 2 allocs/op BenchmarkAny/stringer-any-logger-go 467934 2518 ns/op 112 B/op 2 allocs/op BenchmarkAny/stringer-any-logger-go-12 1786076 683.1 ns/op 112 B/op 2 allocs/op BenchmarkAny/stringer-typ-logger-go-stack 855794 1316 ns/op 96 B/op 2 allocs/op BenchmarkAny/stringer-typ-logger-go-stack-12 2598783 434.5 ns/op 96 B/op 2 allocs/op BenchmarkAny/stringer-any-logger-go-stack 473282 2474 ns/op 112 B/op 2 allocs/op BenchmarkAny/stringer-any-logger-go-stack-12 2020183 651.9 ns/op 112 B/op 2 allocs/op PASS ok go.uber.org/zap 53.516s ```
1 parent 17e02a5 commit cd2f6ac

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

logger_bench_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ package zap
2222

2323
import (
2424
"errors"
25+
"runtime"
26+
"sync"
2527
"testing"
2628
"time"
2729

@@ -238,3 +240,79 @@ func Benchmark100Fields(b *testing.B) {
238240
logger.With(first...).Info("Child loggers with lots of context.", second...)
239241
}
240242
}
243+
244+
func BenchmarkAny(b *testing.B) {
245+
key := "some-long-string-longer-than-16"
246+
247+
tests := []struct {
248+
name string
249+
typed func() Field
250+
anyArg any
251+
}{
252+
{
253+
name: "string",
254+
typed: func() Field { return String(key, "yet-another-long-string") },
255+
anyArg: "yet-another-long-string",
256+
},
257+
{
258+
name: "stringer",
259+
typed: func() Field { return Stringer(key, InfoLevel) },
260+
anyArg: InfoLevel,
261+
},
262+
}
263+
264+
for _, tt := range tests {
265+
b.Run(tt.name, func(b *testing.B) {
266+
b.Run("field-only", func(b *testing.B) {
267+
b.Run("typed", func(b *testing.B) {
268+
withBenchedLogger(b, func(log *Logger) {
269+
f := tt.typed()
270+
runtime.KeepAlive(f)
271+
})
272+
})
273+
b.Run("any", func(b *testing.B) {
274+
withBenchedLogger(b, func(log *Logger) {
275+
f := Any(key, tt.anyArg)
276+
runtime.KeepAlive(f)
277+
})
278+
})
279+
})
280+
b.Run("log", func(b *testing.B) {
281+
b.Run("typed", func(b *testing.B) {
282+
withBenchedLogger(b, func(log *Logger) {
283+
log.Info("", tt.typed())
284+
})
285+
})
286+
b.Run("any", func(b *testing.B) {
287+
withBenchedLogger(b, func(log *Logger) {
288+
log.Info("", Any(key, tt.anyArg))
289+
})
290+
})
291+
})
292+
b.Run("log-go", func(b *testing.B) {
293+
b.Run("typed", func(b *testing.B) {
294+
withBenchedLogger(b, func(log *Logger) {
295+
var wg sync.WaitGroup
296+
wg.Add(1)
297+
go func() {
298+
log.Info("", tt.typed())
299+
wg.Done()
300+
}()
301+
wg.Wait()
302+
})
303+
})
304+
b.Run("any", func(b *testing.B) {
305+
withBenchedLogger(b, func(log *Logger) {
306+
var wg sync.WaitGroup
307+
wg.Add(1)
308+
go func() {
309+
log.Info("", Any(key, tt.anyArg))
310+
wg.Done()
311+
}()
312+
wg.Wait()
313+
})
314+
})
315+
})
316+
})
317+
}
318+
}

0 commit comments

Comments
 (0)