golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/slog/benchmarks/benchmarks_test.go (about)

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package benchmarks
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"io"
    11  	"testing"
    12  
    13  	"golang.org/x/exp/slog"
    14  	"golang.org/x/exp/slog/internal"
    15  )
    16  
    17  func init() {
    18  	flag.BoolVar(&internal.IgnorePC, "nopc", false, "do not invoke runtime.Callers")
    19  }
    20  
    21  // We pass Attrs (or zap.Fields) inline because it affects allocations: building
    22  // up a list outside of the benchmarked code and passing it in with "..."
    23  // reduces measured allocations.
    24  
    25  func BenchmarkAttrs(b *testing.B) {
    26  	ctx := context.Background()
    27  	for _, handler := range []struct {
    28  		name string
    29  		h    slog.Handler
    30  	}{
    31  		{"disabled", disabledHandler{}},
    32  		{"async discard", newAsyncHandler()},
    33  		{"fastText discard", newFastTextHandler(io.Discard)},
    34  		{"Text discard", slog.NewTextHandler(io.Discard, nil)},
    35  		{"JSON discard", slog.NewJSONHandler(io.Discard, nil)},
    36  	} {
    37  		logger := slog.New(handler.h)
    38  		b.Run(handler.name, func(b *testing.B) {
    39  			for _, call := range []struct {
    40  				name string
    41  				f    func()
    42  			}{
    43  				{
    44  					// The number should match nAttrsInline in slog/record.go.
    45  					// This should exercise the code path where no allocations
    46  					// happen in Record or Attr. If there are allocations, they
    47  					// should only be from Duration.String and Time.String.
    48  					"5 args",
    49  					func() {
    50  						logger.LogAttrs(nil, slog.LevelInfo, TestMessage,
    51  							slog.String("string", TestString),
    52  							slog.Int("status", TestInt),
    53  							slog.Duration("duration", TestDuration),
    54  							slog.Time("time", TestTime),
    55  							slog.Any("error", TestError),
    56  						)
    57  					},
    58  				},
    59  				{
    60  					"5 args ctx",
    61  					func() {
    62  						logger.LogAttrs(ctx, slog.LevelInfo, TestMessage,
    63  							slog.String("string", TestString),
    64  							slog.Int("status", TestInt),
    65  							slog.Duration("duration", TestDuration),
    66  							slog.Time("time", TestTime),
    67  							slog.Any("error", TestError),
    68  						)
    69  					},
    70  				},
    71  				{
    72  					"10 args",
    73  					func() {
    74  						logger.LogAttrs(nil, slog.LevelInfo, TestMessage,
    75  							slog.String("string", TestString),
    76  							slog.Int("status", TestInt),
    77  							slog.Duration("duration", TestDuration),
    78  							slog.Time("time", TestTime),
    79  							slog.Any("error", TestError),
    80  							slog.String("string", TestString),
    81  							slog.Int("status", TestInt),
    82  							slog.Duration("duration", TestDuration),
    83  							slog.Time("time", TestTime),
    84  							slog.Any("error", TestError),
    85  						)
    86  					},
    87  				},
    88  				{
    89  					"40 args",
    90  					func() {
    91  						logger.LogAttrs(nil, slog.LevelInfo, TestMessage,
    92  							slog.String("string", TestString),
    93  							slog.Int("status", TestInt),
    94  							slog.Duration("duration", TestDuration),
    95  							slog.Time("time", TestTime),
    96  							slog.Any("error", TestError),
    97  							slog.String("string", TestString),
    98  							slog.Int("status", TestInt),
    99  							slog.Duration("duration", TestDuration),
   100  							slog.Time("time", TestTime),
   101  							slog.Any("error", TestError),
   102  							slog.String("string", TestString),
   103  							slog.Int("status", TestInt),
   104  							slog.Duration("duration", TestDuration),
   105  							slog.Time("time", TestTime),
   106  							slog.Any("error", TestError),
   107  							slog.String("string", TestString),
   108  							slog.Int("status", TestInt),
   109  							slog.Duration("duration", TestDuration),
   110  							slog.Time("time", TestTime),
   111  							slog.Any("error", TestError),
   112  							slog.String("string", TestString),
   113  							slog.Int("status", TestInt),
   114  							slog.Duration("duration", TestDuration),
   115  							slog.Time("time", TestTime),
   116  							slog.Any("error", TestError),
   117  							slog.String("string", TestString),
   118  							slog.Int("status", TestInt),
   119  							slog.Duration("duration", TestDuration),
   120  							slog.Time("time", TestTime),
   121  							slog.Any("error", TestError),
   122  							slog.String("string", TestString),
   123  							slog.Int("status", TestInt),
   124  							slog.Duration("duration", TestDuration),
   125  							slog.Time("time", TestTime),
   126  							slog.Any("error", TestError),
   127  							slog.String("string", TestString),
   128  							slog.Int("status", TestInt),
   129  							slog.Duration("duration", TestDuration),
   130  							slog.Time("time", TestTime),
   131  							slog.Any("error", TestError),
   132  						)
   133  					},
   134  				},
   135  			} {
   136  				b.Run(call.name, func(b *testing.B) {
   137  					b.ReportAllocs()
   138  					b.RunParallel(func(pb *testing.PB) {
   139  						for pb.Next() {
   140  							call.f()
   141  						}
   142  					})
   143  				})
   144  			}
   145  		})
   146  	}
   147  }