]> Cypherpunks repositories - gostls13.git/commitdiff
all: remove unnecessary allocations from w.WriteString(fmt.Sprint*(...)) by fmt.Fprin...
authorEmmanuel T Odeke <emmanuel@orijtech.com>
Fri, 9 Sep 2022 16:59:21 +0000 (09:59 -0700)
committerEmmanuel Odeke <emmanuel@orijtech.com>
Wed, 14 Sep 2022 16:11:21 +0000 (16:11 +0000)
Noticed in a manual audit from a customer codebase that the pattern

    w.WriteString(fmt.Sprint*(args...))

was less efficient and in most cases we can just invoke:

    fmt.Fprint*(w, args...)

and from the simple benchmarks we can see quick wins in all dimensions:

$ benchstat before.txt after.txt
name            old time/op    new time/op    delta
DetailString-8    5.48µs ±23%    4.40µs ±11%  -19.79%  (p=0.000 n=20+17)

name            old alloc/op   new alloc/op   delta
DetailString-8    2.63kB ± 0%    2.11kB ± 0%  -19.76%  (p=0.000 n=20+20)

name            old allocs/op  new allocs/op  delta
DetailString-8      63.0 ± 0%      50.0 ± 0%  -20.63%  (p=0.000 n=20+20)

Change-Id: I47a2827cd34d6b92644900b1bd5f4c0a3287bdb1
Reviewed-on: https://go-review.googlesource.com/c/go/+/429861
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: hopehook <hopehook@golangcn.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
src/cmd/compile/internal/abt/avlint32.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/syntax/scanner_test.go
src/cmd/compile/internal/types/fmt.go
src/go/types/exprstring.go
src/internal/fmtsort/sort_test.go
src/runtime/trace/annotation_test.go
src/runtime/wincallback.go

index eed5fa5d38b7b4ffc7a70e66858b36639084c21a..e0998f5bacc83aad0c518112862cd52f7fc20452 100644 (file)
@@ -339,7 +339,7 @@ func (t *T) String() string {
                }
                b.WriteString(strconv.FormatInt(int64(k), 10))
                b.WriteString(":")
-               b.WriteString(fmt.Sprint(v))
+               fmt.Fprint(&b, v)
        }
        return b.String()
 }
index 21b8fbc8ec36e8b06b23000b9be1442bf6904005..88d43b9915f2598d498b0bbbaebb770dacc7e52b 100644 (file)
@@ -7271,7 +7271,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
                        }
                        buf.WriteString("</dt>")
                        buf.WriteString("<dd class=\"ssa-prog\">")
-                       buf.WriteString(fmt.Sprintf("%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString())))
+                       fmt.Fprintf(&buf, "%.5d <span class=\"l%v line-number\">(%s)</span> %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))
                        buf.WriteString("</dd>")
                }
                buf.WriteString("</dl>")
index 2deb3bbf8463446273cd4be9811f348abeaeee95..450ec1ff8a55f6138318e7dc84164bceaa4ca406 100644 (file)
@@ -88,10 +88,10 @@ func TestEmbeddedTokens(t *testing.T) {
        // make source
        var buf bytes.Buffer
        for i, s := range sampleTokens {
-               buf.WriteString("\t\t\t\t"[:i&3])                            // leading indentation
-               buf.WriteString(s.src)                                       // token
-               buf.WriteString("        "[:i&7])                            // trailing spaces
-               buf.WriteString(fmt.Sprintf("/*line foo:%d */ // bar\n", i)) // comments + newline (don't crash w/o directive handler)
+               buf.WriteString("\t\t\t\t"[:i&3])                 // leading indentation
+               buf.WriteString(s.src)                            // token
+               buf.WriteString("        "[:i&7])                 // trailing spaces
+               fmt.Fprintf(&buf, "/*line foo:%d */ // bar\n", i) // comments + newline (don't crash w/o directive handler)
        }
 
        // scan source
index c6e99d26c265d7668b1fa6603d5ff3fc2b66b91c..990f2e5f52e9afea95b2a49d15a0c2d129e72256 100644 (file)
@@ -577,7 +577,7 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                } else {
                        b.WriteString("tp")
                        // Print out the pointer value for now to disambiguate type params
-                       b.WriteString(fmt.Sprintf("%p", t))
+                       fmt.Fprintf(b, "%p", t)
                }
 
        case TUNION:
index e19d79d9c8d0df1c9118c15889f454f084623bec..3cdf30fba1a5148499862b77e6d7f288996db75c 100644 (file)
@@ -33,7 +33,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
 
        switch x := x.(type) {
        default:
-               buf.WriteString(fmt.Sprintf("(ast: %T)", x)) // nil, ast.BadExpr, ast.KeyValueExpr
+               fmt.Fprintf(buf, "(ast: %T)", x) // nil, ast.BadExpr, ast.KeyValueExpr
 
        case *ast.Ident:
                buf.WriteString(x.Name)
index 11befca6f1921f091d4ac6ede011f5a0f057143a..cddcf70159cbf5cdec2735ec906bdadd11d4593d 100644 (file)
@@ -147,7 +147,7 @@ func sprint(data any) string {
                }
                b.WriteString(sprintKey(key))
                b.WriteRune(':')
-               b.WriteString(fmt.Sprint(om.Value[i]))
+               fmt.Fprint(b, om.Value[i])
        }
        return b.String()
 }
index 31fccef206ce02868d42ddc28999c1f83f8c9cdc..69ea8f2d3b6e63854c624f8c43b3c11ba71e2a57 100644 (file)
@@ -147,7 +147,7 @@ func TestUserTaskRegion(t *testing.T) {
                pretty := func(data []testData) string {
                        var s strings.Builder
                        for _, d := range data {
-                               s.WriteString(fmt.Sprintf("\t%+v\n", d))
+                               fmt.Fprintf(&s, "\t%+v\n", d)
                        }
                        return s.String()
                }
index 442a98470837b84a7b0b5c1971ccce6d5eccaa3a..9ec2027f976f2298608f980df5e8360ccb4859a0 100644 (file)
@@ -62,7 +62,7 @@ func genasmArm() {
 TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
 `)
        for i := 0; i < maxCallback; i++ {
-               buf.WriteString(fmt.Sprintf("\tMOVW\t$%d, R12\n", i))
+               fmt.Fprintf(&buf, "\tMOVW\t$%d, R12\n", i)
                buf.WriteString("\tB\truntime·callbackasm1(SB)\n")
        }
 
@@ -90,7 +90,7 @@ func genasmArm64() {
 TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
 `)
        for i := 0; i < maxCallback; i++ {
-               buf.WriteString(fmt.Sprintf("\tMOVD\t$%d, R12\n", i))
+               fmt.Fprintf(&buf, "\tMOVD\t$%d, R12\n", i)
                buf.WriteString("\tB\truntime·callbackasm1(SB)\n")
        }
 
@@ -104,12 +104,12 @@ TEXT runtime·callbackasm(SB),NOSPLIT|NOFRAME,$0
 func gengo() {
        var buf bytes.Buffer
 
-       buf.WriteString(fmt.Sprintf(`// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
+       fmt.Fprintf(&buf, `// Code generated by wincallback.go using 'go generate'. DO NOT EDIT.
 
 package runtime
 
 const cb_max = %d // maximum number of windows callbacks allowed
-`, maxCallback))
+`, maxCallback)
        err := os.WriteFile("zcallback_windows.go", buf.Bytes(), 0666)
        if err != nil {
                fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)