[go] bufio: add fast path to WriteString for strings that fit in the buffer

5 views
Skip to first unread message

Gerrit Bot (Gerrit)

unread,
Aug 2, 2026, 8:19:31 PM (7 days ago) Aug 2
to goph...@pubsubhelper.golang.org, David Teather, golang-co...@googlegroups.com

Gerrit Bot has uploaded the change for review

Commit message

bufio: add fast path to WriteString for strings that fit in the buffer

WriteString sets up its io.StringWriter fallback before checking
whether the string simply fits in the remaining buffer space, which
is the common case. The setup is not free: the interface value is
zeroed and state is spilled on every call, including the calls that
never use the fallback, making WriteString measurably slower than
Write for an identical payload that fits.

Handle the fits-in-buffer case first. The fallback loop then only
runs when the string does not fit, so its condition is known true on
entry: test it at the bottom of the loop instead so it is not
evaluated twice. The fallback path gets slightly faster as well.

goos: darwin
goarch: arm64
pkg: bufio
cpu: Apple M2 Pro
│ old │ new │
│ sec/op │ sec/op vs base │
WriterCopyOptimal-10 51.54n ± 0% 51.67n ± 0% ~ (p=0.233 n=25)
WriterCopyUnoptimal-10 52.42n ± 1% 52.42n ± 1% ~ (p=0.528 n=25)
WriterCopyNoReadFrom-10 2.329µ ± 1% 2.325µ ± 1% ~ (p=0.690 n=25)
WriterEmpty-10 483.1n ± 1% 480.6n ± 1% ~ (p=0.567 n=25)
WriterFlush-10 5.262n ± 0% 5.025n ± 1% -4.50% (p=0.000 n=25)
WriteString/fit-10 4.873n ± 1% 3.783n ± 0% -22.37% (p=0.000 n=25)
WriteString/overflow-10 5.993n ± 0% 5.697n ± 0% -4.94% (p=0.000 n=25)
geomean 46.46n 44.17n -4.94%

B/op and allocs/op are unchanged.

Fixes #80692
Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
GitHub-Last-Rev: a645f774f6d1eb5c55a9dd6fc47b8807a11dfe02
GitHub-Pull-Request: golang/go#80693

Change diff

diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go
index f9b762b..5f0f9bb 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -745,11 +745,22 @@
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteString(s string) (int, error) {
+ if b.err == nil && len(s) <= b.Available() {
+ // Fast path: the whole string fits in the buffer.
+ n := copy(b.buf[b.n:], s)
+ b.n += n
+ return n, nil
+ }
+
+ if b.err != nil {
+ return 0, b.err
+ }
+
var sw io.StringWriter
tryStringWriter := true

nn := 0
- for len(s) > b.Available() && b.err == nil {
+ for {
var n int
if b.Buffered() == 0 && sw == nil && tryStringWriter {
// Check at most once whether b.wr is a StringWriter.
@@ -767,6 +778,9 @@
}
nn += n
s = s[n:]
+ if len(s) <= b.Available() || b.err != nil {
+ break
+ }
}
if b.err != nil {
return nn, b.err
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 742e195..4fb3d9e 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -1997,3 +1997,20 @@
bw.Flush()
}
}
+
+func BenchmarkWriteString(b *testing.B) {
+ fit := strings.Repeat("x", 50)
+ overflow := strings.Repeat("x", 8<<10)
+ for _, tc := range []struct{ name, s string }{
+ {"fit", fit},
+ {"overflow", overflow},
+ } {
+ b.Run(tc.name, func(b *testing.B) {
+ b.ReportAllocs()
+ bw := NewWriter(io.Discard)
+ for i := 0; i < b.N; i++ {
+ bw.WriteString(tc.s)
+ }
+ })
+ }
+}

Change information

Files:
  • M src/bufio/bufio.go
  • M src/bufio/bufio_test.go
Change size: S
Delta: 2 files changed, 32 insertions(+), 1 deletion(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
Gerrit-Change-Number: 809320
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-CC: David Teather <contact.da...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

David Teather (Gerrit)

unread,
Aug 2, 2026, 8:37:40 PM (7 days ago) Aug 2
to Gerrit Bot, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
Attention needed from Brad Fitzpatrick, Ian Lance Taylor and Robert Griesemer

David Teather added 1 comment

File src/bufio/bufio.go
Line 781, Patchset 1 (Latest): if len(s) <= b.Available() || b.err != nil {
David Teather . resolved

pushed the conditional down here bc re-evaluating at the top had a benchmark regression of ~5%

Open in Gerrit

Related details

Attention is currently required from:
  • Brad Fitzpatrick
  • Ian Lance Taylor
  • Robert Griesemer
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
Gerrit-Change-Number: 809320
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
Gerrit-CC: David Teather <contact.da...@gmail.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Attention: Robert Griesemer <g...@golang.org>
Gerrit-Comment-Date: Mon, 03 Aug 2026 00:37:35 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
unsatisfied_requirement
satisfied_requirement
open
diffy

Ian Lance Taylor (Gerrit)

unread,
Aug 3, 2026, 1:41:49 AM (7 days ago) Aug 3
to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
Attention needed from Brad Fitzpatrick and Robert Griesemer

Ian Lance Taylor added 1 comment

Patchset-level comments
File-level comment, Patchset 1 (Latest):
Ian Lance Taylor . resolved

This change makes the function longer and harder to understand, to avoid compiler issues. I think it would be better to tweak the compiler.

Open in Gerrit

Related details

Attention is currently required from:
  • Brad Fitzpatrick
  • Robert Griesemer
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
Gerrit-Change-Number: 809320
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
Gerrit-CC: David Teather <contact.da...@gmail.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Attention: Robert Griesemer <g...@golang.org>
Gerrit-Comment-Date: Mon, 03 Aug 2026 05:41:44 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
unsatisfied_requirement
satisfied_requirement
open
diffy

Jorropo (Gerrit)

unread,
Aug 3, 2026, 2:21:02 AM (7 days ago) Aug 3
to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
Attention needed from Brad Fitzpatrick and Robert Griesemer

Jorropo voted and added 4 comments

Votes added by Jorropo

Code-Review+2
Commit-Queue+1

4 comments

Patchset-level comments
Jorropo . resolved

Thanks

File src/bufio/bufio.go
Line 754, Patchset 1 (Latest):
if b.err != nil {
return 0, b.err
}
Jorropo . unresolved

Shouldn't that come first ?

If the buffer has a pending error it's a bit weird to accept a write.

File src/bufio/bufio_test.go
Line 2001, Patchset 1 (Latest):func BenchmarkWriteString(b *testing.B) {

fit := strings.Repeat("x", 50)
overflow := strings.Repeat("x", 8<<10)
for _, tc := range []struct{ name, s string }{
{"fit", fit},
{"overflow", overflow},
Jorropo . unresolved
```suggestion
func BenchmarkWriteString(b *testing.B) {

for _, tc := range []struct{ name, s string }{
		{"small", strings.Repeat("x", 50)},
{"huge", strings.Repeat("x", 8<<10)},
```
Given you don't create a new buffer on each iteration, the small string doesn't always fit.

I think it's clearer to name it small and huge.

Line 2011, Patchset 1 (Latest): for i := 0; i < b.N; i++ {
Jorropo . unresolved
```suggestion
for range b.N {
```
Open in Gerrit

Related details

Attention is currently required from:
  • Brad Fitzpatrick
  • Robert Griesemer
Submit Requirements:
  • requirement satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
Gerrit-Change-Number: 809320
Gerrit-PatchSet: 1
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
Gerrit-CC: David Teather <contact.da...@gmail.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Attention: Robert Griesemer <g...@golang.org>
Gerrit-Comment-Date: Mon, 03 Aug 2026 06:20:55 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Gerrit Bot (Gerrit)

unread,
Aug 3, 2026, 10:20:07 PM (6 days ago) Aug 3
to David Teather, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Brad Fitzpatrick, Ian Lance Taylor, Jorropo and Robert Griesemer

Gerrit Bot uploaded new patchset

Gerrit Bot uploaded patch set #2 to this change.
Following approvals got outdated and were removed:
Open in Gerrit

Related details

Attention is currently required from:
  • Brad Fitzpatrick
  • Ian Lance Taylor
  • Jorropo
  • Robert Griesemer
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
Gerrit-Change-Number: 809320
Gerrit-PatchSet: 2
Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
Gerrit-CC: David Teather <contact.da...@gmail.com>
Gerrit-CC: Gopher Robot <go...@golang.org>
Gerrit-Attention: Jorropo <jorro...@gmail.com>
Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
unsatisfied_requirement
open
diffy

David Teather (Gerrit)

unread,
Aug 3, 2026, 10:25:14 PM (6 days ago) Aug 3
to Gerrit Bot, goph...@pubsubhelper.golang.org, golang...@luci-project-accounts.iam.gserviceaccount.com, Jorropo, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
Attention needed from Brad Fitzpatrick, Ian Lance Taylor, Jorropo and Robert Griesemer

David Teather added 4 comments

Patchset-level comments
File-level comment, Patchset 2 (Latest):
David Teather . resolved

Updated. Thanks for the review!

File src/bufio/bufio.go

if b.err != nil {
return 0, b.err
}
Jorropo . resolved

Shouldn't that come first ?

If the buffer has a pending error it's a bit weird to accept a write.

David Teather

good call swapped to `b.err` comparison first

File src/bufio/bufio_test.go
Line 2001, Patchset 1:func BenchmarkWriteString(b *testing.B) {

fit := strings.Repeat("x", 50)
overflow := strings.Repeat("x", 8<<10)
for _, tc := range []struct{ name, s string }{
{"fit", fit},
{"overflow", overflow},
Jorropo . resolved
```suggestion
func BenchmarkWriteString(b *testing.B) {
for _, tc := range []struct{ name, s string }{
{"small", strings.Repeat("x", 50)},
{"huge", strings.Repeat("x", 8<<10)},
```
Given you don't create a new buffer on each iteration, the small string doesn't always fit.

I think it's clearer to name it small and huge.

David Teather

updated to small/huge

Line 2011, Patchset 1: for i := 0; i < b.N; i++ {
Jorropo . resolved
```suggestion
for range b.N {
```
David Teather

swapped to `b.Loop()` looks like that's current best practice https://go.dev/blog/testing-b-loop

Open in Gerrit

Related details

Attention is currently required from:
  • Brad Fitzpatrick
  • Ian Lance Taylor
  • Jorropo
  • Robert Griesemer
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Comment-Date: Tue, 04 Aug 2026 02:25:09 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Jorropo <jorro...@gmail.com>
    unsatisfied_requirement
    satisfied_requirement
    open
    diffy

    Sean Liao (Gerrit)

    unread,
    Aug 8, 2026, 6:25:16 PM (2 days ago) Aug 8
    to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, golang...@luci-project-accounts.iam.gserviceaccount.com, Jorropo, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
    Attention needed from Brad Fitzpatrick, Ian Lance Taylor, Jorropo and Robert Griesemer

    Sean Liao voted

    Auto-Submit+1
    Code-Review+2
    Commit-Queue+1
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Brad Fitzpatrick
    • Ian Lance Taylor
    • Jorropo
    • Robert Griesemer
    Submit Requirements:
    • requirement satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-Reviewer: Sean Liao <se...@liao.dev>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Comment-Date: Sat, 08 Aug 2026 22:25:08 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Alan Donovan (Gerrit)

    unread,
    Aug 9, 2026, 6:06:02 AM (24 hours ago) Aug 9
    to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, golang...@luci-project-accounts.iam.gserviceaccount.com, Jorropo, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
    Attention needed from Brad Fitzpatrick, Ian Lance Taylor, Jorropo and Robert Griesemer

    Alan Donovan added 3 comments

    Patchset-level comments
    Alan Donovan . resolved

    Thanks for contributing this optimization.

    File src/bufio/bufio.go
    Line 753, Patchset 2 (Latest): // Fast path: the whole string fits in the buffer.

    n := copy(b.buf[b.n:], s)
    b.n += n
    return n, nil
    Alan Donovan . unresolved

    Once we've applied the change at L783, can we also factor this common tail with L788-... using something like this form?

    ```

    func (b *Writer) WriteString(s string) (int, error) {
    	if b.err != nil {
    return 0, b.err
    }
    	nn := 0
    if len(s) > b.Available() {
    if b.Buffered() == 0 {
    if sw, ok := b.wr.(io.StringWriter); ok {
    // Large write, empty buffer, and the underlying writer supports
    // WriteString: forward the write to the underlying StringWriter.
    // This avoids an extra copy.
    var n int
    n, b.err = sw.WriteString(s)
    return n, b.err
    }
    }
    		// Buffer and flush each complete chunk.
    for {

    n := copy(b.buf[b.n:], s)
    			b.n += n
    b.Flush() // ignore error

    if len(s) <= b.Available() || b.err != nil {
    				break

    }
    nn += n
    s = s[n:]
    }
    		if b.err != nil {
    return nn, b.err
    }
    }
    	// The whole string (or final chunk) fits in the buffer.

    n := copy(b.buf[b.n:], s)
    	b.n += n
    nn += n
    return nn, nil
    }
    ```
    Line 763, Patchset 2 (Latest): for {
    Alan Donovan . unresolved

    Now that we have the precondition `len(s) > b.Available()`, we know the loop will execute at least once, so we can simplify by doing the one-time check for StringWriter eagerly, which may improve the non-fast case too.

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Brad Fitzpatrick
    • Ian Lance Taylor
    • Jorropo
    • Robert Griesemer
    Submit Requirements:
    • requirement satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-Reviewer: Sean Liao <se...@liao.dev>
    Gerrit-CC: Alan Donovan <adon...@google.com>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Comment-Date: Sun, 09 Aug 2026 10:05:56 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Gerrit Bot (Gerrit)

    unread,
    Aug 9, 2026, 6:44:02 PM (11 hours ago) Aug 9
    to David Teather, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
    Attention needed from Brad Fitzpatrick, Ian Lance Taylor, Jorropo, Robert Griesemer and Sean Liao

    Gerrit Bot uploaded new patchset

    Gerrit Bot uploaded patch set #3 to this change.
    Following approvals got outdated and were removed:
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Brad Fitzpatrick
    • Ian Lance Taylor
    • Jorropo
    • Robert Griesemer
    • Sean Liao
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: newpatchset
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 3
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-Reviewer: Sean Liao <se...@liao.dev>
    Gerrit-CC: Alan Donovan <adon...@google.com>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Sean Liao <se...@liao.dev>
    unsatisfied_requirement
    open
    diffy

    David Teather (Gerrit)

    unread,
    Aug 9, 2026, 6:56:08 PM (11 hours ago) Aug 9
    to Gerrit Bot, goph...@pubsubhelper.golang.org, Alan Donovan, golang...@luci-project-accounts.iam.gserviceaccount.com, Jorropo, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
    Attention needed from Alan Donovan, Brad Fitzpatrick, Ian Lance Taylor, Jorropo, Robert Griesemer and Sean Liao

    David Teather added 3 comments

    Patchset-level comments
    File-level comment, Patchset 2:
    David Teather . resolved

    Thanks for the review! Updated it and tried to refactor closer to the structure you provided but it had some perf regressions, but took some shapes from that which made it faster

    File src/bufio/bufio.go
    Line 753, Patchset 2: // Fast path: the whole string fits in the buffer.
    David Teather

    Happy to make the change, but held off for now as it costs the fast path.

    This is what I benched, the suggested shape on top of the current logic

    ```go

    func (b *Writer) WriteString(s string) (int, error) {
    if b.err != nil {
    return 0, b.err
    }
    	nn := 0
    if len(s) > b.Available() {
    		sw, ok := b.wr.(io.StringWriter)
    		if ok && b.Buffered() == 0 {

    // Large write, empty buffer, and the underlying writer supports
    // WriteString: forward the write to the underlying StringWriter.
    // This avoids an extra copy.
    var n int
    n, b.err = sw.WriteString(s)
    			if n == len(s) || b.err != nil {
    return n, b.err
    }
    nn = n
    s = s[n:]
    }
    		// Buffer and flush each complete chunk.
    for {
    var n int
    if b.Buffered() == 0 && ok {
    n, b.err = sw.WriteString(s)
    } else {

    n = copy(b.buf[b.n:], s)
    b.n += n
    b.Flush()
    }
    			nn += n
    s = s[n:]
    if len(s) <= b.Available() || b.err != nil {
    break
    }
    }
    if b.err != nil {
    return nn, b.err
    }
    }
    	n := copy(b.buf[b.n:], s)

    b.n += n
    nn += n
    return nn, nil
    }
    ```

    `go test -run='^$' -bench=WriteString bufio`, n=30, that against the patchset:

    ```
    │ CL │ refactor │
    │ sec/op │ sec/op vs base │
    WriteString/small-10 3.696n ± 1% 5.129n ± 2% +38.75% (p=0.000 n=30)
    WriteString/huge-10 3.914n ± 1% 3.607n ± 0% -7.83% (p=0.000 n=30)
    geomean 3.803n 4.301n +13.09%
    ```

    It's mixed, but the absolute deltas are +1.43ns and -0.31ns. I'm not entirely sure why the effect is that large, I assume it's layout. Maybe the fast path stops being a straight-line return off the prologue.


    Two things from your sketch I did take, and one I didn't.

    I took the early return for the empty-buffer case. It needs the `n == len(s) || b.err != nil` guard. I tried it without, and hit cases where a short-writing StringWriter made WriteString return (n, nil) with n < len(s), dropping the rest of the string and breaking the doc's "if the count is less than len(s), it also returns an error". Write absorbs that by looping. Guarded as above it matches master exactly, and it's worth ~ -28% on `huge`.

    I kept the StringWriter test inside the loop. Checking only on entry means a Writer with buffered data never reaches sw.WriteString at all: 242 -> 96 calls on the underlying writer across my matrix, and writing 4 bytes then 8 KiB regressed 81%. Write tests b.Buffered() == 0 inside its loop for the same reason.

    Let me know what you think, or if I'm missing something on the refactor that might be hurting performance. Thanks!

    Line 763, Patchset 2: for {
    Alan Donovan . resolved

    Now that we have the precondition `len(s) > b.Available()`, we know the loop will execute at least once, so we can simplify by doing the one-time check for StringWriter eagerly, which may improve the non-fast case too.

    David Teather

    Done. Hoisted the check above the loop. I also confirmed your guess about the non-fast case WriteString/huge got faster by ~5% more

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Alan Donovan
    • Brad Fitzpatrick
    • Ian Lance Taylor
    • Jorropo
    • Robert Griesemer
    • Sean Liao
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 2
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-Reviewer: Sean Liao <se...@liao.dev>
    Gerrit-CC: Alan Donovan <adon...@google.com>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Sean Liao <se...@liao.dev>
    Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Attention: Alan Donovan <adon...@google.com>
    Gerrit-Comment-Date: Sun, 09 Aug 2026 22:56:03 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    Comment-In-Reply-To: Alan Donovan <adon...@google.com>
    unsatisfied_requirement
    open
    diffy

    Emmanuel Odeke (Gerrit)

    unread,
    1:02 AM (5 hours ago) 1:02 AM
    to David Teather, Gerrit Bot, goph...@pubsubhelper.golang.org, Alan Donovan, golang...@luci-project-accounts.iam.gserviceaccount.com, Jorropo, Brad Fitzpatrick, Ian Lance Taylor, Robert Griesemer, Gopher Robot, golang-co...@googlegroups.com
    Attention needed from Alan Donovan, Brad Fitzpatrick, Ian Lance Taylor, Jorropo, Robert Griesemer and Sean Liao

    Emmanuel Odeke voted Commit-Queue+1

    Commit-Queue+1
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Alan Donovan
    • Brad Fitzpatrick
    • Ian Lance Taylor
    • Jorropo
    • Robert Griesemer
    • Sean Liao
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement is not satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-Change-Id: Iae8f1612b4aaf741ed26e20074729557085a0bdc
    Gerrit-Change-Number: 809320
    Gerrit-PatchSet: 3
    Gerrit-Owner: Gerrit Bot <letsus...@gmail.com>
    Gerrit-Reviewer: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Reviewer: Emmanuel Odeke <emma...@orijtech.com>
    Gerrit-Reviewer: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Reviewer: Jorropo <jorro...@gmail.com>
    Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
    Gerrit-Reviewer: Sean Liao <se...@liao.dev>
    Gerrit-CC: Alan Donovan <adon...@google.com>
    Gerrit-CC: David Teather <contact.da...@gmail.com>
    Gerrit-CC: Gopher Robot <go...@golang.org>
    Gerrit-Attention: Jorropo <jorro...@gmail.com>
    Gerrit-Attention: Sean Liao <se...@liao.dev>
    Gerrit-Attention: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Attention: Brad Fitzpatrick <brad...@golang.org>
    Gerrit-Attention: Robert Griesemer <g...@golang.org>
    Gerrit-Attention: Alan Donovan <adon...@google.com>
    Gerrit-Comment-Date: Mon, 10 Aug 2026 05:02:17 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    unsatisfied_requirement
    open
    diffy
    Reply all
    Reply to author
    Forward
    0 new messages