mirror of
https://github.com/golang/go
synced 2024-09-30 13:18:34 -06:00
strconv: replace small int string table with constant string
This reduces memory use yet still provides the significant performance gain seen when using a fast path for small integers. Improvement of this CL comparing to code without fast path: name old time/op new time/op delta FormatIntSmall-8 35.6ns ± 1% 4.5ns ± 1% -87.30% (p=0.008 n=5+5) AppendIntSmall-8 17.4ns ± 1% 9.4ns ± 3% -45.70% (p=0.008 n=5+5) For comparison, here's the improvement before this CL to code without fast path (1% better for FormatIntSmall): name old time/op new time/op delta FormatIntSmall-8 35.6ns ± 1% 4.0ns ± 3% -88.64% (p=0.008 n=5+5) AppendIntSmall-8 17.4ns ± 1% 8.2ns ± 1% -52.80% (p=0.008 n=5+5) Thus, the code in this CL performs slower for small integers using fast path then the prior version, but this is relative to an already very fast version: name old time/op new time/op delta FormatIntSmall-8 4.05ns ± 3% 4.52ns ± 1% +11.81% (p=0.008 n=5+5) AppendIntSmall-8 8.21ns ± 1% 9.45ns ± 3% +15.05% (p=0.008 n=5+5) Measured on 2.3 GHz Intel Core i7 running macOS Sierra 10.12.3. Overall, it's still ~88% faster than without fast path for small integers, so probably worth it as it removes 100 global string slices in favor of a single string. Credits: This is based on the original (but cleaned up) version of the code by Aliaksandr Valialkin (https://go-review.googlesource.com/c/37963/). Change-Id: Icda78679c8c14666d46257894e9fa3d7f35e58b8 Reviewed-on: https://go-review.googlesource.com/38319 Reviewed-by: Martin Möhrmann <moehrmann@google.com>
This commit is contained in:
parent
b744a11a96
commit
aea44109cf
@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
package strconv
|
package strconv
|
||||||
|
|
||||||
|
const fastSmalls = true // enable fast path for small integers
|
||||||
|
|
||||||
// FormatUint returns the string representation of i in the given base,
|
// FormatUint returns the string representation of i in the given base,
|
||||||
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
|
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
|
||||||
// for digit values >= 10.
|
// for digit values >= 10.
|
||||||
func FormatUint(i uint64, base int) string {
|
func FormatUint(i uint64, base int) string {
|
||||||
if i < uint64(len(smallints)) && base == 10 {
|
if fastSmalls && i < nSmalls && base == 10 {
|
||||||
return smallints[i]
|
return small(int(i))
|
||||||
}
|
}
|
||||||
_, s := formatBits(nil, i, base, false, false)
|
_, s := formatBits(nil, i, base, false, false)
|
||||||
return s
|
return s
|
||||||
@ -19,8 +21,8 @@ func FormatUint(i uint64, base int) string {
|
|||||||
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
|
// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z'
|
||||||
// for digit values >= 10.
|
// for digit values >= 10.
|
||||||
func FormatInt(i int64, base int) string {
|
func FormatInt(i int64, base int) string {
|
||||||
if 0 <= i && i < int64(len(smallints)) && base == 10 {
|
if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
|
||||||
return smallints[i]
|
return small(int(i))
|
||||||
}
|
}
|
||||||
_, s := formatBits(nil, uint64(i), base, i < 0, false)
|
_, s := formatBits(nil, uint64(i), base, i < 0, false)
|
||||||
return s
|
return s
|
||||||
@ -34,8 +36,8 @@ func Itoa(i int) string {
|
|||||||
// AppendInt appends the string form of the integer i,
|
// AppendInt appends the string form of the integer i,
|
||||||
// as generated by FormatInt, to dst and returns the extended buffer.
|
// as generated by FormatInt, to dst and returns the extended buffer.
|
||||||
func AppendInt(dst []byte, i int64, base int) []byte {
|
func AppendInt(dst []byte, i int64, base int) []byte {
|
||||||
if 0 <= i && i < int64(len(smallints)) && base == 10 {
|
if fastSmalls && 0 <= i && i < nSmalls && base == 10 {
|
||||||
return append(dst, smallints[i]...)
|
return append(dst, small(int(i))...)
|
||||||
}
|
}
|
||||||
dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
|
dst, _ = formatBits(dst, uint64(i), base, i < 0, true)
|
||||||
return dst
|
return dst
|
||||||
@ -44,30 +46,39 @@ func AppendInt(dst []byte, i int64, base int) []byte {
|
|||||||
// AppendUint appends the string form of the unsigned integer i,
|
// AppendUint appends the string form of the unsigned integer i,
|
||||||
// as generated by FormatUint, to dst and returns the extended buffer.
|
// as generated by FormatUint, to dst and returns the extended buffer.
|
||||||
func AppendUint(dst []byte, i uint64, base int) []byte {
|
func AppendUint(dst []byte, i uint64, base int) []byte {
|
||||||
if i < uint64(len(smallints)) && base == 10 {
|
if fastSmalls && i < nSmalls && base == 10 {
|
||||||
return append(dst, smallints[i]...)
|
return append(dst, small(int(i))...)
|
||||||
}
|
}
|
||||||
dst, _ = formatBits(dst, i, base, false, true)
|
dst, _ = formatBits(dst, i, base, false, true)
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// small returns the string for an i with 0 <= i < nSmalls.
|
||||||
|
func small(i int) string {
|
||||||
|
off := 0
|
||||||
|
if i < 10 {
|
||||||
|
off = 1
|
||||||
|
}
|
||||||
|
return smallsString[i*2+off : i*2+2]
|
||||||
|
}
|
||||||
|
|
||||||
|
const nSmalls = 100
|
||||||
|
|
||||||
|
const smallsString = "00010203040506070809" +
|
||||||
|
"10111213141516171819" +
|
||||||
|
"20212223242526272829" +
|
||||||
|
"30313233343536373839" +
|
||||||
|
"40414243444546474849" +
|
||||||
|
"50515253545556575859" +
|
||||||
|
"60616263646566676869" +
|
||||||
|
"70717273747576777879" +
|
||||||
|
"80818283848586878889" +
|
||||||
|
"90919293949596979899"
|
||||||
|
|
||||||
const host32bit = ^uint(0)>>32 == 0
|
const host32bit = ^uint(0)>>32 == 0
|
||||||
|
|
||||||
const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
|
const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
var smallints = [...]string{
|
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
|
||||||
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
|
|
||||||
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
|
|
||||||
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
|
|
||||||
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
|
|
||||||
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
|
|
||||||
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
|
|
||||||
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
|
|
||||||
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
|
|
||||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
|
|
||||||
}
|
|
||||||
|
|
||||||
var shifts = [len(digits) + 1]uint{
|
var shifts = [len(digits) + 1]uint{
|
||||||
1 << 1: 1,
|
1 << 1: 1,
|
||||||
1 << 2: 2,
|
1 << 2: 2,
|
||||||
|
Loading…
Reference in New Issue
Block a user