I tried: strconv.Quote() strconv.AppendQuote() (weird that this is faster than Quote) fmt.Sprintf("%q") scanning for !IsPrint() + bytes.Buffer scanning for !IsPrint() + strings.Builder (sad that this is not faster than Buffer) scanning for !IsPrint() + string addition
``` $ go test -benchtime=5s -bench='XX' ./benchmark/ goos: linux goarch: amd64 pkg: github.com/go-logr/logr/benchmark cpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz BenchmarkXXQuote-6 23233543 258.5 ns/op BenchmarkXXAppendQuote-6 24370812 207.7 ns/op BenchmarkXXSprintf-6 18040070 335.2 ns/op BenchmarkXXScanBuffer-6 47154340 117.4 ns/op BenchmarkXXScanBuilder-6 42295635 141.9 ns/op BenchmarkXXScanAdd-6 43635146 137.5 ns/op PASS ok github.com/go-logr/logr/benchmark 35.926s ``` code: ``` //go:noinline func foo(s string) { _ = s } func prettyBuffer(s string) string { if needsEscape(s) { return strconv.Quote(s) } b := bytes.NewBuffer(make([]byte, 0, 1024)) b.WriteByte('"') b.WriteString(s) b.WriteByte('"') return b.String() } func prettyBuilder(s string) string { if needsEscape(s) { return strconv.Quote(s) } b := strings.Builder{} b.WriteByte('"') b.WriteString(s) b.WriteByte('"') return b.String() } func prettyAdd(s string) string { if needsEscape(s) { return strconv.Quote(s) } return `"` + s + `"` } // needsEscape determines whether the input string needs to be escaped or not, // without doing any allocations. func needsEscape(s string) bool { for _, r := range s { if !strconv.IsPrint(r) || r == '\\' || r == '"' { return true } } return false } func BenchmarkXXQuote(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := strconv.Quote(in) foo(out) } } func BenchmarkXXAppendQuote(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := strconv.AppendQuote(make([]byte, 0, 1024), in) foo(string(out)) } } func BenchmarkXXSprintf(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := fmt.Sprintf("%q", in) foo(out) } } func BenchmarkXXScanBuffer(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := prettyBuffer(in) foo(out) } } func BenchmarkXXScanBuilder(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := prettyBuilder(in) foo(out) } } func BenchmarkXXScanAdd(b *testing.B) { in := "a string with no specials" for i := 0; i < b.N; i++ { out := prettyAdd(in) foo(out) } } ``` On Thu, Oct 14, 2021 at 1:52 AM roger peppe <rogpe...@gmail.com> wrote: > On Thu, 14 Oct 2021 at 04:58, 'Tim Hockin' via golang-nuts < > golang-nuts@googlegroups.com> wrote: > >> Thanks for confirming. I wrote that function and erased a good bit of >> the overhead. >> >> bytes.Buffer for the no-escapes path and strconv.Quote otherwise. >> > > Could you not use strconv.AppendQuote and get the advantage without > needing the extra scan? > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAO_RewbrDW55pD74hO6eCTgUEGZh7-46_z7RC3FWonrpnypwHw%40mail.gmail.com.