From: Julien Cretel Date: Tue, 13 May 2025 11:11:13 +0000 (+0000) Subject: bytes, strings: speed up Split{,After}Seq X-Git-Tag: go1.25rc1~276 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=14fc54fc5735163abf7694b4efa2b7998c6696e2;p=gostls13.git bytes, strings: speed up Split{,After}Seq CL 669735 brought a welcome performance boost to splitSeq; however, it rendered explodeSeq ineligible for inlining and failed to update that function's doc comment. This CL inlines the call to explodeSeq in splitSeq, thereby unlocking a further speedup in the case of an empty separator, and removes function explodeSeq altogether. Some benchmarks results: goos: darwin goarch: amd64 pkg: strings cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ old │ new │ │ sec/op │ sec/op vs base │ SplitSeqEmptySeparator-8 5.136m ± 6% 3.180m ± 6% -38.09% (p=0.000 n=20) SplitSeqSingleByteSeparator-8 995.9µ ± 1% 988.4µ ± 0% -0.75% (p=0.000 n=20) SplitSeqMultiByteSeparator-8 593.1µ ± 2% 591.7µ ± 1% ~ (p=0.253 n=20) SplitAfterSeqEmptySeparator-8 5.554m ± 3% 3.432m ± 2% -38.20% (p=0.000 n=20) SplitAfterSeqSingleByteSeparator-8 997.4µ ± 0% 1000.0µ ± 8% ~ (p=0.121 n=20) SplitAfterSeqMultiByteSeparator-8 591.7µ ± 1% 588.9µ ± 0% -0.48% (p=0.004 n=20) geomean 1.466m 1.247m -14.97% │ old │ new │ │ B/op │ B/op vs base │ SplitSeqEmptySeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ SplitSeqSingleByteSeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ SplitSeqMultiByteSeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ SplitAfterSeqEmptySeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ SplitAfterSeqSingleByteSeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ SplitAfterSeqMultiByteSeparator-8 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=20) ¹ geomean ² +0.00% ² ¹ all samples are equal ² summaries must be >0 to compute geomean Change-Id: I5767b68dc1a4fbcb2ac20683830a49ee3eb1bee1 GitHub-Last-Rev: 344934071f3220a1afea3def306dadfee720d311 GitHub-Pull-Request: golang/go#73685 Reviewed-on: https://go-review.googlesource.com/c/go/+/672175 Reviewed-by: qiu laidongfeng2 <2645477756@qq.com> Reviewed-by: Robert Griesemer Auto-Submit: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- diff --git a/src/bytes/iter.go b/src/bytes/iter.go index e3af4d2f13..b2abb2c9ba 100644 --- a/src/bytes/iter.go +++ b/src/bytes/iter.go @@ -31,23 +31,18 @@ func Lines(s []byte) iter.Seq[[]byte] { } } -// explodeSeq returns an iterator over the runes in s. -func explodeSeq(s []byte, yield func([]byte) bool) { - for len(s) > 0 { - _, size := utf8.DecodeRune(s) - if !yield(s[:size:size]) { - return - } - s = s[size:] - } -} - // splitSeq is SplitSeq or SplitAfterSeq, configured by how many // bytes of sep to include in the results (none or all). func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] { return func(yield func([]byte) bool) { if len(sep) == 0 { - explodeSeq(s, yield) + for len(s) > 0 { + _, size := utf8.DecodeRune(s) + if !yield(s[:size:size]) { + return + } + s = s[size:] + } return } for { diff --git a/src/strings/iter.go b/src/strings/iter.go index a42e78ee09..69fe031739 100644 --- a/src/strings/iter.go +++ b/src/strings/iter.go @@ -31,23 +31,18 @@ func Lines(s string) iter.Seq[string] { } } -// explodeSeq returns an iterator over the runes in s. -func explodeSeq(s string, yield func(string) bool) { - for len(s) > 0 { - _, size := utf8.DecodeRuneInString(s) - if !yield(s[:size]) { - return - } - s = s[size:] - } -} - // splitSeq is SplitSeq or SplitAfterSeq, configured by how many // bytes of sep to include in the results (none or all). func splitSeq(s, sep string, sepSave int) iter.Seq[string] { return func(yield func(string) bool) { if len(sep) == 0 { - explodeSeq(s, yield) + for len(s) > 0 { + _, size := utf8.DecodeRuneInString(s) + if !yield(s[:size]) { + return + } + s = s[size:] + } return } for {