Skip to content

Commit 78b5321

Browse files
committed
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 #3463 LGTM=josharian, rsc R=golang-codereviews, josharian, rsc CC=golang-codereviews https://golang.org/cl/144250043
1 parent db56d4d commit 78b5321

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

src/fmt/fmt_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,23 @@ func BenchmarkManyArgs(b *testing.B) {
854854
})
855855
}
856856

857+
func BenchmarkFprintInt(b *testing.B) {
858+
var buf bytes.Buffer
859+
for i := 0; i < b.N; i++ {
860+
buf.Reset()
861+
Fprint(&buf, 123456)
862+
}
863+
}
864+
865+
func BenchmarkFprintIntNoAlloc(b *testing.B) {
866+
var x interface{} = 123456
867+
var buf bytes.Buffer
868+
for i := 0; i < b.N; i++ {
869+
buf.Reset()
870+
Fprint(&buf, x)
871+
}
872+
}
873+
857874
var mallocBuf bytes.Buffer
858875
var mallocPointer *int // A pointer so we know the interface value won't allocate.
859876

src/fmt/format.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,36 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
199199
// block but it's not worth the duplication, so ua has 64 bits.
200200
i := len(buf)
201201
ua := uint64(a)
202-
for ua >= base {
203-
i--
204-
buf[i] = digits[ua%base]
205-
ua /= base
202+
// use constants for the division and modulo for more efficient code.
203+
// switch cases ordered by popularity.
204+
switch base {
205+
case 10:
206+
for ua >= 10 {
207+
i--
208+
next := ua / 10
209+
buf[i] = byte('0' + ua - next*10)
210+
ua = next
211+
}
212+
case 16:
213+
for ua >= 16 {
214+
i--
215+
buf[i] = digits[ua&0xF]
216+
ua >>= 4
217+
}
218+
case 8:
219+
for ua >= 8 {
220+
i--
221+
buf[i] = byte('0' + ua&7)
222+
ua >>= 3
223+
}
224+
case 2:
225+
for ua >= 2 {
226+
i--
227+
buf[i] = byte('0' + ua&1)
228+
ua >>= 1
229+
}
230+
default:
231+
panic("fmt: unknown base; can't happen")
206232
}
207233
i--
208234
buf[i] = digits[ua]

0 commit comments

Comments
 (0)