]> Cypherpunks repositories - gostls13.git/commitdiff
fmt: make printing of ints 25-35% faster
authorRob Pike <r@golang.org>
Mon, 22 Sep 2014 18:58:15 +0000 (11:58 -0700)
committerRob Pike <r@golang.org>
Mon, 22 Sep 2014 18:58:15 +0000 (11:58 -0700)
Inspired by a remark by Leonard Holz, use constants for division

BenchmarkSprintfEmpty           130           132           +1.54%
BenchmarkSprintfString          438           437           -0.23%
BenchmarkSprintfInt             417           414           -0.72%
BenchmarkSprintfIntInt          663           691           +4.22%
BenchmarkSprintfPrefixedInt     791           774           -2.15%
BenchmarkSprintfFloat           701           686           -2.14%
BenchmarkManyArgs               2584          2469          -4.45%
BenchmarkFprintInt              488           357           -26.84%
BenchmarkFprintIntNoAlloc       402           265           -34.08%
BenchmarkScanInts               1244346       1267574       +1.87%
BenchmarkScanRecursiveInt       1748741       1724138       -1.41%

Update #3463

LGTM=josharian, rsc
R=golang-codereviews, josharian, rsc
CC=golang-codereviews
https://golang.org/cl/144250043

src/fmt/fmt_test.go
src/fmt/format.go

index a212c9f7026a8169bc5a6f14b18409e4b6b219fd..cca0a495ffe47d817bba07210a192b0076883e2d 100644 (file)
@@ -854,6 +854,23 @@ func BenchmarkManyArgs(b *testing.B) {
        })
 }
 
+func BenchmarkFprintInt(b *testing.B) {
+       var buf bytes.Buffer
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               Fprint(&buf, 123456)
+       }
+}
+
+func BenchmarkFprintIntNoAlloc(b *testing.B) {
+       var x interface{} = 123456
+       var buf bytes.Buffer
+       for i := 0; i < b.N; i++ {
+               buf.Reset()
+               Fprint(&buf, x)
+       }
+}
+
 var mallocBuf bytes.Buffer
 var mallocPointer *int // A pointer so we know the interface value won't allocate.
 
index 8aeffd7b2b7d7b21774c41b4325035cded96a85d..255167c8f519c1aed11339386e01fa6bdc4efb31 100644 (file)
@@ -199,10 +199,36 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
        // block but it's not worth the duplication, so ua has 64 bits.
        i := len(buf)
        ua := uint64(a)
-       for ua >= base {
-               i--
-               buf[i] = digits[ua%base]
-               ua /= base
+       // use constants for the division and modulo for more efficient code.
+       // switch cases ordered by popularity.
+       switch base {
+       case 10:
+               for ua >= 10 {
+                       i--
+                       next := ua / 10
+                       buf[i] = byte('0' + ua - next*10)
+                       ua = next
+               }
+       case 16:
+               for ua >= 16 {
+                       i--
+                       buf[i] = digits[ua&0xF]
+                       ua >>= 4
+               }
+       case 8:
+               for ua >= 8 {
+                       i--
+                       buf[i] = byte('0' + ua&7)
+                       ua >>= 3
+               }
+       case 2:
+               for ua >= 2 {
+                       i--
+                       buf[i] = byte('0' + ua&1)
+                       ua >>= 1
+               }
+       default:
+               panic("fmt: unknown base; can't happen")
        }
        i--
        buf[i] = digits[ua]