From: Martin Möhrmann Date: Sat, 11 Mar 2017 07:48:56 +0000 (+0100) Subject: strconv: fix performance regression in integer formatting on 32bit platforms X-Git-Tag: go1.9beta1~1199 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b71ed4edc6a5663caac434f9c2bea47dbc37db15;p=gostls13.git strconv: fix performance regression in integer formatting on 32bit platforms Some of the changes in CL golang.org/cl/38071/ assumed that / and % could always be combined to use only one DIV instruction. However, this is not the case for 64bit operands on a 32bit platform which use seperate runtime functions to calculate division and modulo. This CL restores the original optimizations that help on 32bit platforms with negligible impact on 64bit platforms. 386: name old time/op new time/op delta FormatInt-2 6.06µs ± 0% 6.02µs ± 0% -0.70% (p=0.000 n=20+20) AppendInt-2 4.98µs ± 0% 4.98µs ± 0% ~ (p=0.747 n=18+18) FormatUint-2 1.93µs ± 0% 1.85µs ± 0% -4.19% (p=0.000 n=20+20) AppendUint-2 1.71µs ± 0% 1.64µs ± 0% -3.68% (p=0.000 n=20+20) amd64: name old time/op new time/op delta FormatInt-2 2.41µs ± 0% 2.41µs ± 0% -0.09% (p=0.010 n=18+18) AppendInt-2 1.77µs ± 0% 1.77µs ± 0% +0.08% (p=0.000 n=18+18) FormatUint-2 653ns ± 1% 653ns ± 0% ~ (p=0.178 n=20+20) AppendUint-2 514ns ± 0% 513ns ± 0% -0.13% (p=0.000 n=20+17) Change-Id: I574a18e54fb41b25fbe51ce696e7a8765abc79a6 Reviewed-on: https://go-review.googlesource.com/38051 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- diff --git a/src/strconv/itoa.go b/src/strconv/itoa.go index 0cbbf06594..d0b4258d76 100644 --- a/src/strconv/itoa.go +++ b/src/strconv/itoa.go @@ -80,11 +80,11 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s if host32bit { // convert the lower digits using 32bit operations for u >= 1e9 { - // the compiler recognizes q = a/b; r = a%b - // and produces only one DIV instruction; - // no need to be clever here + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. q := u / 1e9 - us := uint(u % 1e9) // u % 1e9 fits into a uint + us := uint(u - q*1e9) // u % 1e9 fits into a uint for j := 9; j > 0; j-- { i-- a[i] = byte(us%10 + '0') @@ -117,19 +117,22 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s } // u < base i-- - a[i] = digits[u] - + a[i] = digits[uint(u)] } else { // general case b := uint64(base) for u >= b { i-- - a[i] = digits[u%b] - u /= b + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q } // u < base i-- - a[i] = digits[u] + a[i] = digits[uint(u)] } // add sign, if any