From 0c8d9896cbe21e83cfbc0b2c68e35aa3b565e71d Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Thu, 24 Jun 2021 13:44:30 -0700 Subject: [PATCH] Fast path for empty buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we don't have a leftover partial write in the buffer, we can skip the buffer completely and write directly to the logger. This improves performance when log statements aren't split across too many writes. ``` name old time/op new time/op delta Writer/single-4 422ns ±21% 383ns ± 2% -9.26% (p=0.000 n=10+9) Writer/splits-4 433ns ± 4% 435ns ± 1% ~ (p=0.236 n=9+8) name old alloc/op new alloc/op delta Writer/single-4 16.0B ± 0% 16.0B ± 0% ~ (all equal) Writer/splits-4 16.0B ± 0% 16.0B ± 0% ~ (all equal) name old allocs/op new allocs/op delta Writer/single-4 2.00 ± 0% 2.00 ± 0% ~ (all equal) Writer/splits-4 2.00 ± 0% 2.00 ± 0% ~ (all equal) ``` --- zapio/writer.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/zapio/writer.go b/zapio/writer.go index 8c367d7f2..29699c86d 100644 --- a/zapio/writer.go +++ b/zapio/writer.go @@ -72,6 +72,14 @@ func (w *Writer) writeLine(line []byte) (remaining []byte) { // Split on the newline, buffer and flush the left. line, remaining = line[:idx], line[idx+1:] + + // Fast path: if we don't have a partial message from a previous write + // in the buffer, skip the buffer and log directly. + if w.buff.Len() == 0 { + w.log(line) + return + } + w.buff.Write(line) // Log empty messages in the middle of the stream so that we don't lose @@ -100,9 +108,13 @@ func (w *Writer) Sync() error { // if the bool is set. func (w *Writer) flush(allowEmpty bool) { if allowEmpty || w.buff.Len() > 0 { - if ce := w.Log.Check(w.Level, w.buff.String()); ce != nil { - ce.Write() - } + w.log(w.buff.Bytes()) } w.buff.Reset() } + +func (w *Writer) log(b []byte) { + if ce := w.Log.Check(w.Level, string(b)); ce != nil { + ce.Write() + } +}