From 91344febc1f555247b483dfb830c8868aa0be52b Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Mon, 22 Sep 2014 11:58:15 -0700 Subject: 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 --- src/fmt/fmt_test.go | 17 +++++++++++++++++ src/fmt/format.go | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'src/fmt') 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] -- cgit v1.2.1