fmt: speed up 10-20%
The check for Stringer etc. can only fire if the test is not a builtin, so avoid
the expensive check if we know there's no chance.
Also put in a fast path for pad, which saves a more modest amount.
benchmark old ns/op new ns/op delta
BenchmarkSprintfEmpty 148 152 +2.70%
BenchmarkSprintfString 585 497 -15.04%
BenchmarkSprintfInt 441 396 -10.20%
BenchmarkSprintfIntInt 718 603 -16.02%
BenchmarkSprintfPrefixedInt 676 621 -8.14%
BenchmarkSprintfFloat 1003 953 -4.99%
BenchmarkManyArgs 2945 2312 -21.49%
BenchmarkScanInts 1704152 1734441 +1.78%
BenchmarkScanRecursiveInt 1837397 1828920 -0.46%
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/6245068
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index de03429..a7632de 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -527,6 +527,14 @@
}
}
+func BenchmarkManyArgs(b *testing.B) {
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+ }
+}
+
var mallocBuf bytes.Buffer
var mallocTest = []struct {
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index caf900d..3c9cd0d 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -110,11 +110,11 @@
// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
// clear flags afterwards.
func (f *fmt) pad(b []byte) {
- var padding []byte
- var left, right int
- if f.widPresent && f.wid != 0 {
- padding, left, right = f.computePadding(len(b))
+ if !f.widPresent || f.wid == 0 {
+ f.buf.Write(b)
+ return
}
+ padding, left, right := f.computePadding(len(b))
if left > 0 {
f.writePadding(left, padding)
}
@@ -127,11 +127,11 @@
// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
// clear flags afterwards.
func (f *fmt) padString(s string) {
- var padding []byte
- var left, right int
- if f.widPresent && f.wid != 0 {
- padding, left, right = f.computePadding(utf8.RuneCountInString(s))
+ if !f.widPresent || f.wid == 0 {
+ f.buf.WriteString(s)
+ return
}
+ padding, left, right := f.computePadding(utf8.RuneCountInString(s))
if left > 0 {
f.writePadding(left, padding)
}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 1343824..c730b18 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -734,10 +734,6 @@
return false
}
- if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
- return wasString
- }
-
// Some types can be done without reflection.
switch f := field.(type) {
case bool:
@@ -779,6 +775,10 @@
p.fmtBytes(f, verb, goSyntax, depth)
wasString = verb == 's'
default:
+ // If the type is not simple, it might have methods.
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
+ return wasString
+ }
// Need to use reflection
return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
}