| package glog |
| |
| import ( |
| "flag" |
| "io/ioutil" |
| "runtime" |
| "sync" |
| "sync/atomic" |
| "testing" |
| "time" |
| ) |
| |
| // discarder is a flushSyncWriter that discards all data. |
| // Sync sleeps for 10ms to simulate a disk seek. |
| type discarder struct { |
| } |
| |
| func (d *discarder) Write(data []byte) (int, error) { |
| return len(data), nil |
| } |
| |
| func (d *discarder) Flush() error { |
| return nil |
| } |
| |
| func (d *discarder) Sync() error { |
| time.Sleep(10 * time.Millisecond) |
| return nil |
| } |
| |
| func (d *discarder) filenames() []string { |
| return nil |
| } |
| |
| // newDiscard sets the log writers to all new byte buffers and returns the old array. |
| func (s *fileSink) newDiscarders() severityWriters { |
| return s.swap(severityWriters{new(discarder), new(discarder), new(discarder), new(discarder)}) |
| } |
| |
| func discardStderr() func() { |
| se := sinks.stderr.w |
| sinks.stderr.w = ioutil.Discard |
| return func() { sinks.stderr.w = se } |
| } |
| |
| const message = "benchmark log message" |
| |
| func benchmarkLog(b *testing.B, log func(...any)) { |
| defer sinks.file.swap(sinks.file.newDiscarders()) |
| defer discardStderr()() |
| b.ResetTimer() |
| for i := 0; i < b.N; i++ { |
| log(message) |
| } |
| b.StopTimer() |
| } |
| |
| func benchmarkLogConcurrent(b *testing.B, log func(...any)) { |
| defer sinks.file.swap(sinks.file.newDiscarders()) |
| defer discardStderr()() |
| b.ResetTimer() |
| concurrency := runtime.GOMAXPROCS(0) |
| var wg sync.WaitGroup |
| wg.Add(concurrency) |
| for i := 0; i < concurrency; i++ { |
| go func() { |
| for i := 0; i < b.N; i++ { |
| log(message) |
| } |
| wg.Done() |
| }() |
| } |
| wg.Wait() |
| b.StopTimer() |
| } |
| |
| func BenchmarkInfo(b *testing.B) { |
| benchmarkLog(b, Info) |
| } |
| |
| func BenchmarkInfoConcurrent(b *testing.B) { |
| benchmarkLogConcurrent(b, Info) |
| } |
| |
| func BenchmarkWarning(b *testing.B) { |
| benchmarkLog(b, Warning) |
| } |
| |
| func BenchmarkWarningConcurrent(b *testing.B) { |
| benchmarkLogConcurrent(b, Warning) |
| } |
| |
| func BenchmarkError(b *testing.B) { |
| benchmarkLog(b, Error) |
| } |
| |
| func BenchmarkErrorConcurrent(b *testing.B) { |
| benchmarkLogConcurrent(b, Error) |
| } |
| |
| func mixer() func(...any) { |
| var i int64 |
| return func(args ...any) { |
| n := atomic.AddInt64(&i, 1) |
| switch { |
| case n%10000 == 0: |
| Error(args...) |
| case n%1000 == 0: |
| Warning(args...) |
| default: |
| Info(args...) |
| } |
| } |
| } |
| |
| func BenchmarkMix(b *testing.B) { |
| benchmarkLog(b, mixer()) |
| } |
| |
| func BenchmarkMixConcurrent(b *testing.B) { |
| benchmarkLogConcurrent(b, mixer()) |
| } |
| |
| func BenchmarkVLogDisabled(b *testing.B) { |
| benchmarkLog(b, vlog) |
| } |
| |
| func BenchmarkVLogDisabledConcurrent(b *testing.B) { |
| benchmarkLogConcurrent(b, vlog) |
| } |
| |
| func BenchmarkVLogModuleFlagSet(b *testing.B) { |
| defer withVmodule("nonexistant=5")() |
| benchmarkLog(b, vlog) |
| } |
| |
| func BenchmarkVLogModuleFlagSetConcurrent(b *testing.B) { |
| defer withVmodule("nonexistant=5")() |
| benchmarkLogConcurrent(b, vlog) |
| } |
| |
| func BenchmarkVLogEnabled(b *testing.B) { |
| defer withVmodule("glog_bench_test=5")() |
| if got := bool(V(3)); got != true { |
| b.Fatalf("V(3) == %v, want %v", got, true) |
| } |
| benchmarkLog(b, vlog) |
| } |
| |
| func BenchmarkVLogEnabledConcurrent(b *testing.B) { |
| defer withVmodule("glog_bench_test=5")() |
| benchmarkLogConcurrent(b, vlog) |
| } |
| |
| func vlog(args ...any) { |
| V(3).Info(args) |
| } |
| |
| func withVmodule(val string) func() { |
| if err := flag.Set("vmodule", val); err != nil { |
| panic(err) |
| } |
| return func() { flag.Set("vmodule", "") } |
| } |