diff options
author | Rob Pike <r@golang.org> | 2014-09-22 11:58:15 -0700 |
---|---|---|
committer | Rob Pike <r@golang.org> | 2014-09-22 11:58:15 -0700 |
commit | 91344febc1f555247b483dfb830c8868aa0be52b (patch) | |
tree | 99bb52d291f3084ae889cf056762a6e251aae3dd /src | |
parent | edc8f73c2071f951fa1fb57a892e9baeb3707426 (diff) | |
download | go-91344febc1f555247b483dfb830c8868aa0be52b.tar.gz |
fmt: make printing of ints 25-35% faster
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 issue 3463
LGTM=josharian, rsc
R=golang-codereviews, josharian, rsc
CC=golang-codereviews
https://codereview.appspot.com/144250043
Diffstat (limited to 'src')
-rw-r--r-- | src/fmt/fmt_test.go | 17 | ||||
-rw-r--r-- | src/fmt/format.go | 34 |
2 files changed, 47 insertions, 4 deletions
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index a212c9f70..cca0a495f 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -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. diff --git a/src/fmt/format.go b/src/fmt/format.go index 8aeffd7b2..255167c8f 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -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] |