[go] strconv: optimize Atoi for common case

100 views
Skip to first unread message

Aliaksandr Valialkin (Gerrit)

unread,
Jun 2, 2017, 12:55:16 PM6/2/17
to Ian Lance Taylor, golang-co...@googlegroups.com

Aliaksandr Valialkin has uploaded this change for review.

View Change

strconv: optimize Atoi for common case

strconv.Atoi is mostly used for parsing non-negative integers.
Opimize it for this case.

Benchmark results:

GOARCH=amd64

name old time/op new time/op delta
Atoi/1-4 16.7ns ± 1% 6.1ns ± 3% -63.35% (p=0.008 n=5+5)
Atoi/12-4 18.2ns ± 0% 6.3ns ± 0% -65.13% (p=0.000 n=4+5)
Atoi/123-4 19.3ns ± 1% 6.9ns ± 1% -64.22% (p=0.008 n=5+5)
Atoi/1234-4 20.3ns ± 1% 7.6ns ± 1% -62.68% (p=0.008 n=5+5)
Atoi/12345-4 21.2ns ± 0% 8.5ns ± 1% -59.85% (p=0.008 n=5+5)
Atoi/123456-4 22.3ns ± 0% 9.1ns ± 1% -59.11% (p=0.008 n=5+5)
Atoi/1234567-4 23.8ns ± 0% 9.5ns ± 0% -59.96% (p=0.016 n=4+5)
Atoi/12345678-4 24.9ns ± 1% 10.2ns ± 1% -59.15% (p=0.008 n=5+5)
Atoi/123456789-4 26.4ns ± 3% 10.9ns ± 1% -58.68% (p=0.008 n=5+5)
Atoi/1234567890-4 27.5ns ± 1% 11.8ns ± 1% -57.23% (p=0.008 n=5+5)
AtoiNeg/1-4 15.3ns ± 1% 15.9ns ± 3% +4.18% (p=0.008 n=5+5)
AtoiNeg/12-4 16.6ns ± 1% 17.3ns ± 1% +3.85% (p=0.008 n=5+5)
AtoiNeg/123-4 17.9ns ± 0% 18.6ns ± 1% +3.79% (p=0.008 n=5+5)
AtoiNeg/1234-4 19.2ns ± 1% 19.7ns ± 3% +2.50% (p=0.008 n=5+5)
AtoiNeg/12345-4 20.6ns ± 0% 20.8ns ± 0% +1.17% (p=0.016 n=5+4)
AtoiNeg/123456-4 21.7ns ± 1% 22.1ns ± 1% +1.85% (p=0.008 n=5+5)
AtoiNeg/1234567-4 23.1ns ± 1% 23.6ns ± 3% +2.17% (p=0.024 n=5+5)
AtoiNeg/12345678-4 24.4ns ± 1% 24.8ns ± 2% ~ (p=0.087 n=5+5)
AtoiNeg/123456789-4 25.8ns ± 1% 26.4ns ± 1% +2.25% (p=0.008 n=5+5)
AtoiNeg/1234567890-4 26.9ns ± 1% 27.4ns ± 0% +1.71% (p=0.016 n=5+4)

GOARCH=386

name old time/op new time/op delta
Atoi/1-4 51.7ns ± 1% 6.3ns ± 1% -87.72% (p=0.008 n=5+5)
Atoi/12-4 77.9ns ± 5% 9.3ns ± 4% -88.02% (p=0.008 n=5+5)
Atoi/123-4 102ns ± 2% 12ns ± 3% -88.28% (p=0.008 n=5+5)
Atoi/1234-4 122ns ± 2% 15ns ± 3% -87.92% (p=0.008 n=5+5)
Atoi/12345-4 149ns ± 1% 18ns ± 1% -88.20% (p=0.008 n=5+5)
Atoi/123456-4 173ns ± 5% 20ns ± 5% -88.24% (p=0.008 n=5+5)
Atoi/1234567-4 192ns ± 5% 23ns ± 1% -88.23% (p=0.008 n=5+5)
Atoi/12345678-4 221ns ± 6% 26ns ± 2% -88.39% (p=0.008 n=5+5)
Atoi/123456789-4 241ns ± 1% 28ns ± 1% -88.33% (p=0.016 n=4+5)
Atoi/1234567890-4 265ns ± 4% 263ns ± 1% ~ (p=0.794 n=5+5)
AtoiNeg/1-4 52.1ns ± 4% 52.6ns ± 1% ~ (p=0.190 n=5+4)
AtoiNeg/12-4 74.7ns ± 1% 77.9ns ± 6% ~ (p=0.254 n=5+5)
AtoiNeg/123-4 100ns ± 2% 101ns ± 4% ~ (p=0.389 n=5+5)
AtoiNeg/1234-4 123ns ± 6% 122ns ± 1% ~ (p=0.873 n=5+4)
AtoiNeg/12345-4 142ns ± 1% 145ns ± 0% +2.11% (p=0.016 n=5+4)
AtoiNeg/123456-4 165ns ± 1% 175ns ± 7% +6.30% (p=0.008 n=5+5)
AtoiNeg/1234567-4 193ns ± 6% 190ns ± 1% ~ (p=0.738 n=5+5)
AtoiNeg/12345678-4 215ns ± 4% 235ns ±25% ~ (p=0.071 n=5+5)
AtoiNeg/123456789-4 235ns ± 2% 249ns ± 7% ~ (p=0.095 n=5+5)
AtoiNeg/1234567890-4 258ns ± 1% 261ns ± 3% ~ (p=0.698 n=4+5)

Fixes #20557

Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
---
M src/strconv/atoi.go
M src/strconv/atoi_test.go
2 files changed, 79 insertions(+), 22 deletions(-)

diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index 66df149..6279738 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -199,10 +199,25 @@

// Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
func Atoi(s string) (int, error) {
- const fnAtoi = "Atoi"
+ if len(s) > 0 && s[0] != '-' && s[0] != '+' &&
+ (intSize == 32 && len(s) < 10 || intSize == 64 && len(s) < 19) {
+ // Fast path for positive integers
+ var n int
+ for i := 0; i < len(s); i++ {
+ ch := s[i]
+ v := ch - '0'
+ if v > 9 {
+ return 0, &NumError{"Atoi", s, ErrSyntax}
+ }
+ n = n*10 + int(v)
+ }
+ return n, nil
+ }
+
+ // slow path
i64, err := ParseInt(s, 10, 0)
if nerr, ok := err.(*NumError); ok {
- nerr.Func = fnAtoi
+ nerr.Func = "Atoi"
}
return int(i64), err
}
diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go
index d608505..0992c92 100644
--- a/src/strconv/atoi_test.go
+++ b/src/strconv/atoi_test.go
@@ -6,6 +6,7 @@

import (
"errors"
+ "fmt"
"reflect"
. "strconv"
"testing"
@@ -286,7 +287,7 @@
test := &atoui32tests[i]
out, err := ParseUint(test.in, 10, 0)
if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseUint(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -295,7 +296,7 @@
test := &atoui64tests[i]
out, err := ParseUint(test.in, 10, 0)
if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoui(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseUint(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -309,7 +310,7 @@
test := &atoi32tests[i]
out, err := ParseInt(test.in, 10, 0)
if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -318,13 +319,46 @@
test := &atoi64tests[i]
out, err := ParseInt(test.in, 10, 0)
if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
}
}

+func TestAtoi(t *testing.T) {
+ switch IntSize {
+ case 32:
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, err := Atoi(test.in)
+ var errAtoi error
+ if test.err != nil {
+ numErr := test.err.(*NumError)
+ errAtoi = &NumError{"Atoi", numErr.Num, numErr.Err}
+ }
+ if test.out != int32(out) || !reflect.DeepEqual(errAtoi, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, errAtoi)
+ }
+ }
+ case 64:
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, err := Atoi(test.in)
+ var errAtoi error
+ if test.err != nil {
+ numErr := test.err.(*NumError)
+ errAtoi = &NumError{"Atoi", numErr.Num, numErr.Err}
+ }
+ if test.out != int64(out) || !reflect.DeepEqual(errAtoi, err) {
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
+ test.in, out, err, test.out, errAtoi)
+ }
+ }
+ }
+}
+
func TestNumError(t *testing.T) {
for _, test := range numErrorTests {
err := &NumError{
@@ -339,25 +373,33 @@
}

func BenchmarkAtoi(b *testing.B) {
- for i := 0; i < b.N; i++ {
- ParseInt("12345678", 10, 0)
+ n := 1
+ sink := 0
+ for i := 0; i < 10; i++ {
+ s := fmt.Sprintf("%d", n)
+ b.Run(s, func(b *testing.B) {
+ for j := 0; j < b.N; j++ {
+ out, _ := Atoi(s)
+ sink += out
+ }
+ BenchSink += sink
+ })
+ n = n*10 + (i+2)%10
}
}

func BenchmarkAtoiNeg(b *testing.B) {
- for i := 0; i < b.N; i++ {
- ParseInt("-12345678", 10, 0)
- }
-}
-
-func BenchmarkAtoi64(b *testing.B) {
- for i := 0; i < b.N; i++ {
- ParseInt("12345678901234", 10, 64)
- }
-}
-
-func BenchmarkAtoi64Neg(b *testing.B) {
- for i := 0; i < b.N; i++ {
- ParseInt("-12345678901234", 10, 64)
+ n := 1
+ sink := 0
+ for i := 0; i < 10; i++ {
+ s := fmt.Sprintf("%d", -n)
+ b.Run(s[1:], func(b *testing.B) {
+ for j := 0; j < b.N; j++ {
+ out, _ := Atoi(s)
+ sink += out
+ }
+ BenchSink += sink
+ })
+ n = n*10 + (i+2)%10
}
}

To view, visit change 44692. To unsubscribe, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
Gerrit-Change-Number: 44692
Gerrit-PatchSet: 1
Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>

Ian Lance Taylor (Gerrit)

unread,
Jun 2, 2017, 1:42:41 PM6/2/17
to Aliaksandr Valialkin, golang-co...@googlegroups.com

Ian Lance Taylor posted comments on this change.

View Change

Patch set 1:

R=go1.10

    To view, visit change 44692. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
    Gerrit-Change-Number: 44692
    Gerrit-PatchSet: 1
    Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
    Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Comment-Date: Fri, 02 Jun 2017 17:42:37 +0000
    Gerrit-HasComments: No
    Gerrit-HasLabels: No

    Keith Randall (Gerrit)

    unread,
    Jun 2, 2017, 2:22:37 PM6/2/17
    to Aliaksandr Valialkin, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

    Keith Randall posted comments on this change.

    View Change

    Patch set 1:Code-Review +2

    Wait until 1.10 opens to submit.
    R=go1.10

    (2 comments)

    To view, visit change 44692. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
    Gerrit-Change-Number: 44692
    Gerrit-PatchSet: 1
    Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
    Gerrit-Reviewer: Keith Randall <k...@golang.org>
    Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
    Gerrit-Comment-Date: Fri, 02 Jun 2017 18:22:35 +0000
    Gerrit-HasComments: Yes
    Gerrit-HasLabels: Yes

    Martin Möhrmann (Gerrit)

    unread,
    Jun 3, 2017, 2:02:14 AM6/3/17
    to Aliaksandr Valialkin, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

    Martin Möhrmann posted comments on this change.

    View Change

    Patch set 1:

    (5 comments)

    • File src/strconv/atoi.go:

      • Patch Set #1, Line 202: s[0] != '+'

        since we creating branches here anyway could we do something like (not tested):
        var neg bool
        if len(s) > 0 && (intSize == 32 && len(s) < 10 || intSize == 64 && len(s) < 19)
        switch s[0] {
        case '-':
        neg = true
        case '+':
        s = s[1:]
        default
        }
        ....
        if neg {
        n = -n
        }
        }

        if the switch is not performant we can try if else.

        to capture negative cases in the fast path?

      • Patch Set #1, Line 203: (intSize == 32 && len(s) < 10

        i think we can fold the length checks for lower and upper bound into one comparison:
        (intSize == 32 && uint(len(s)-1) < 9 || intSize == 64 && uint(len(s)-1) < 18)

        and add a comment that this is (intSize == 32 && 0 < len(s) && len(s) < 10 || ...)
        Josh put an optimization for it in the compiler not sure if it is covered in this case.
        If so we should use the spelled out variant in the code.

      • Patch Set #1, Line 206: for i := 0; i < len(s); i++ {

        not tested if it is overall slower code but this range doesnt make a string copy and reads more compact:
        for ch := range []byte(s) {
        ch = ch - '0'
        ...
    • File src/strconv/atoi_test.go:

      • Patch Set #1, Line 385: BenchSink += sink

        we could remove sink and always add directly do BenchSink += out above

      • Patch Set #1, Line 391: BenchmarkAtoiNeg

        Can we do subbenchmarks Atoi/Pos/ Atoi/Neg? This way there is also no confusion with the Atoi bechmark having changed.

    To view, visit change 44692. To unsubscribe, visit settings.

    Gerrit-Project: go
    Gerrit-Branch: master
    Gerrit-MessageType: comment
    Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
    Gerrit-Change-Number: 44692
    Gerrit-PatchSet: 1
    Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
    Gerrit-Reviewer: Keith Randall <k...@golang.org>
    Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
    Gerrit-CC: Martin Möhrmann <moeh...@google.com>
    Gerrit-Comment-Date: Sat, 03 Jun 2017 06:02:09 +0000
    Gerrit-HasComments: Yes
    Gerrit-HasLabels: No

    Martin Möhrmann (Gerrit)

    unread,
    Jun 3, 2017, 4:06:28 AM6/3/17
    to Aliaksandr Valialkin, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

    Martin Möhrmann posted comments on this change.

    View Change

    Patch set 1:

    tested the below is maybe 0.3ns slower for me on positive numbers vs current CL but brings the fast path speedup also to negative numbers.

    // fast path
    if intSize == 32 && uint(len(s)-1) < 9 || intSize == 64 && uint(len(s)-1) < 18 {
    s0 := s
    if s[0] == '+' || s[0] == '-' {
    s = s[1:]
    if len(s) < 1 {
    return 0, &NumError{"Atoi", s0, ErrSyntax}
    }
    }
    		var n int
    for _, ch := range []byte(s) {
    ch -= '0'
    if ch > 9 {
    return 0, &NumError{"Atoi", s0, ErrSyntax}
    }
    n = n*10 + int(ch)
    }
    		if s0[0] == '-' {
    n = -n
    }
    		return n, nil
    }

      To view, visit change 44692. To unsubscribe, visit settings.

      Gerrit-Project: go
      Gerrit-Branch: master
      Gerrit-MessageType: comment
      Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
      Gerrit-Change-Number: 44692
      Gerrit-PatchSet: 1
      Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
      Gerrit-Reviewer: Keith Randall <k...@golang.org>
      Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
      Gerrit-CC: Martin Möhrmann <moeh...@google.com>
      Gerrit-CC: Robert Griesemer <g...@golang.org>
      Gerrit-Comment-Date: Sat, 03 Jun 2017 08:06:23 +0000
      Gerrit-HasComments: No
      Gerrit-HasLabels: No

      Martin Möhrmann (Gerrit)

      unread,
      Jun 3, 2017, 4:35:38 AM6/3/17
      to Aliaksandr Valialkin, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

      Martin Möhrmann posted comments on this change.

      View Change

      Patch set 1:

      One last note while having just run the benchmarks:
      I dont think having benchmarks for many different lengths of numbers adds much here. One benchmark for Atoi/Pos with a long number and that same number with '-' for Atoi/Neg would be sufficient for performance testing. I think adding more benchmarks than that just makes pkg wide benchmarking longer with little gain.

        To view, visit change 44692. To unsubscribe, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 1
        Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Keith Randall <k...@golang.org>
        Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
        Gerrit-CC: Martin Möhrmann <moeh...@google.com>
        Gerrit-CC: Robert Griesemer <g...@golang.org>
        Gerrit-Comment-Date: Sat, 03 Jun 2017 08:35:33 +0000
        Gerrit-HasComments: No
        Gerrit-HasLabels: No

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 23, 2017, 11:11:25 AM8/23/17
        to Keith Randall, Martin Möhrmann, Ian Lance Taylor, Robert Griesemer, golang-co...@googlegroups.com

        Aliaksandr Valialkin uploaded patch set #2 to this change.

        View Change

        strconv: optimize Atoi for common case

        Benchmark results on GOOS=linux:


        GOARCH=amd64

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   19.3ns ± 1%   8.4ns ± 1%  -56.28%  (p=0.000 n=10+10)
        Atoi/Pos/29bit-4 25.8ns ± 1% 12.5ns ± 3% -51.47% (p=0.000 n=9+10)
        Atoi/Pos/31bit-4 27.3ns ± 2% 13.1ns ± 1% -52.05% (p=0.000 n=10+10)
        Atoi/Pos/56bit-4 36.0ns ± 1% 18.1ns ± 0% -49.79% (p=0.000 n=10+9)
        Atoi/Pos/63bit-4 41.4ns ± 9% 39.0ns ± 1% -5.85% (p=0.000 n=10+10)
        Atoi/Neg/7bit-4 17.8ns ± 2% 7.5ns ± 1% -57.79% (p=0.000 n=10+10)
        Atoi/Neg/29bit-4 25.7ns ± 2% 13.0ns ± 1% -49.28% (p=0.000 n=10+10)
        Atoi/Neg/31bit-4 27.2ns ± 1% 13.9ns ± 0% -48.84% (p=0.000 n=10+7)
        Atoi/Neg/56bit-4 36.0ns ± 1% 19.3ns ± 0% -46.55% (p=0.000 n=10+8)
        Atoi/Neg/63bit-4 38.6ns ± 0% 38.8ns ± 1% ~ (p=0.267 n=10+10)


        GOARCH=386

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   87.2ns ± 1%   7.5ns ± 1%  -91.37%  (p=0.000 n=9+9)
        Atoi/Pos/29bit-4 208ns ± 0% 13ns ± 1% -93.71% (p=0.000 n=10+10)
        Atoi/Pos/31bit-4 229ns ± 2% 228ns ± 0% -0.57% (p=0.048 n=10+8)
        Atoi/Neg/7bit-4 86.4ns ± 1% 7.9ns ± 1% -90.86% (p=0.000 n=9+9)
        Atoi/Neg/29bit-4 207ns ± 0% 207ns ± 1% ~ (p=0.173 n=10+9)
        Atoi/Neg/31bit-4 227ns ± 0% 228ns ± 1% +0.64% (p=0.000 n=6+9)


        Fixes #20557

        Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        ---
        M src/strconv/atoi.go
        M src/strconv/atoi_test.go
        2 files changed, 92 insertions(+), 18 deletions(-)

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: newpatchset
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 2

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 23, 2017, 11:14:38 AM8/23/17
        to Keith Randall, Martin Möhrmann, Ian Lance Taylor, Robert Griesemer, golang-co...@googlegroups.com

        Aliaksandr Valialkin uploaded patch set #4 to this change.

        View Change

        strconv: optimize Atoi for common case

        Benchmark results on GOOS=linux:


        GOARCH=amd64

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   19.3ns ± 1%   8.4ns ± 1%  -56.28%  (p=0.000 n=10+10)
        Atoi/Pos/29bit-4 25.8ns ± 1% 12.5ns ± 3% -51.47% (p=0.000 n=9+10)
        Atoi/Pos/31bit-4 27.3ns ± 2% 13.1ns ± 1% -52.05% (p=0.000 n=10+10)
        Atoi/Pos/56bit-4 36.0ns ± 1% 18.1ns ± 0% -49.79% (p=0.000 n=10+9)
        Atoi/Pos/63bit-4 41.4ns ± 9% 39.0ns ± 1% -5.85% (p=0.000 n=10+10)
        Atoi/Neg/7bit-4 17.8ns ± 2% 7.5ns ± 1% -57.79% (p=0.000 n=10+10)
        Atoi/Neg/29bit-4 25.7ns ± 2% 13.0ns ± 1% -49.28% (p=0.000 n=10+10)
        Atoi/Neg/31bit-4 27.2ns ± 1% 13.9ns ± 0% -48.84% (p=0.000 n=10+7)
        Atoi/Neg/56bit-4 36.0ns ± 1% 19.3ns ± 0% -46.55% (p=0.000 n=10+8)
        Atoi/Neg/63bit-4 38.6ns ± 0% 38.8ns ± 1% ~ (p=0.267 n=10+10)

        GOARCH=386

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   87.2ns ± 1%   7.5ns ± 1%  -91.37%  (p=0.000 n=9+9)
        Atoi/Pos/29bit-4 208ns ± 0% 13ns ± 1% -93.71% (p=0.000 n=10+10)
        Atoi/Pos/31bit-4 229ns ± 2% 228ns ± 0% -0.57% (p=0.048 n=10+8)
        Atoi/Neg/7bit-4 86.4ns ± 1% 7.9ns ± 1% -90.86% (p=0.000 n=9+9)
        Atoi/Neg/29bit-4 207ns ± 0% 207ns ± 1% ~ (p=0.173 n=10+9)
        Atoi/Neg/31bit-4 227ns ± 0% 228ns ± 1% +0.64% (p=0.000 n=6+9)

        Fixes #20557

        Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        ---
        M src/strconv/atoi.go
        M src/strconv/atoi_test.go
        2 files changed, 88 insertions(+), 18 deletions(-)

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: newpatchset
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 4

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 23, 2017, 11:16:24 AM8/23/17
        to Robert Griesemer, Martin Möhrmann, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

        Updated the CL according to comments

        View Change

        7 comments:

          • I would put the sink := 0 here, no point in capturing that variable with a closure.

            Done

          • Patch Set #1, Line 385: , baseErrStub},

          • we could remove sink and always add directly do BenchSink += out above

          • Done

          • Patch Set #1, Line 391: TestParseIntBitS

            Can we do subbenchmarks Atoi/Pos/ Atoi/Neg? This way there is also no confusion with the Atoi bechma […]

            Done

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 4
        Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Keith Randall <k...@golang.org>
        Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
        Gerrit-CC: Martin Möhrmann <moeh...@google.com>
        Gerrit-CC: Robert Griesemer <g...@golang.org>
        Gerrit-Comment-Date: Wed, 23 Aug 2017 15:16:20 +0000
        Gerrit-HasComments: Yes
        Gerrit-HasLabels: No

        Martin Möhrmann (Gerrit)

        unread,
        Aug 23, 2017, 12:19:23 PM8/23/17
        to Aliaksandr Valialkin, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

        Do we have seperate Atoi tests?
        If not should be good time to add them and use the test tables for ParseInt if we can reuse them (even if we might need to filter some entries).

        View Change

        2 comments:

        • File src/strconv/atoi.go:

          • Patch Set #4, Line 202: func Atoi(s string) (int, error) {

            i think we should keep const fnAtoi = "Atoi" for consistency with other functions and replace "Atoi" in the NumErrors.

            It should not impact performance.

          • Patch Set #4, Line 203: uint(len(s)-1) < 9

            i think that the compiler is now smart enough to transform:

            l := len(s)
            (0 < s && s < 10)

            to the optimized code we use here.

            We can check with objdump if thats the case.

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 4
        Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Keith Randall <k...@golang.org>
        Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
        Gerrit-CC: Martin Möhrmann <moeh...@google.com>
        Gerrit-CC: Robert Griesemer <g...@golang.org>
        Gerrit-Comment-Date: Wed, 23 Aug 2017 16:19:18 +0000
        Gerrit-HasComments: Yes
        Gerrit-HasLabels: No

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 24, 2017, 6:40:27 AM8/24/17
        to Keith Randall, Martin Möhrmann, Ian Lance Taylor, Robert Griesemer, golang-co...@googlegroups.com

        Aliaksandr Valialkin uploaded patch set #5 to this change.

        View Change

        strconv: optimize Atoi for common case

        Benchmark results on GOOS=linux:


        GOARCH=amd64

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   19.3ns ± 1%   8.4ns ± 1%  -56.28%  (p=0.000 n=10+10)
        Atoi/Pos/29bit-4 25.8ns ± 1% 12.5ns ± 3% -51.47% (p=0.000 n=9+10)
        Atoi/Pos/31bit-4 27.3ns ± 2% 13.1ns ± 1% -52.05% (p=0.000 n=10+10)
        Atoi/Pos/56bit-4 36.0ns ± 1% 18.1ns ± 0% -49.79% (p=0.000 n=10+9)
        Atoi/Pos/63bit-4 41.4ns ± 9% 39.0ns ± 1% -5.85% (p=0.000 n=10+10)
        Atoi/Neg/7bit-4 17.8ns ± 2% 7.5ns ± 1% -57.79% (p=0.000 n=10+10)
        Atoi/Neg/29bit-4 25.7ns ± 2% 13.0ns ± 1% -49.28% (p=0.000 n=10+10)
        Atoi/Neg/31bit-4 27.2ns ± 1% 13.9ns ± 0% -48.84% (p=0.000 n=10+7)
        Atoi/Neg/56bit-4 36.0ns ± 1% 19.3ns ± 0% -46.55% (p=0.000 n=10+8)
        Atoi/Neg/63bit-4 38.6ns ± 0% 38.8ns ± 1% ~ (p=0.267 n=10+10)

        GOARCH=386

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   87.2ns ± 1%   7.5ns ± 1%  -91.37%  (p=0.000 n=9+9)
        Atoi/Pos/29bit-4 208ns ± 0% 13ns ± 1% -93.71% (p=0.000 n=10+10)
        Atoi/Pos/31bit-4 229ns ± 2% 228ns ± 0% -0.57% (p=0.048 n=10+8)
        Atoi/Neg/7bit-4 86.4ns ± 1% 7.9ns ± 1% -90.86% (p=0.000 n=9+9)
        Atoi/Neg/29bit-4 207ns ± 0% 207ns ± 1% ~ (p=0.173 n=10+9)
        Atoi/Neg/31bit-4 227ns ± 0% 228ns ± 1% +0.64% (p=0.000 n=6+9)

        Fixes #20557

        Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        ---
        M src/strconv/atoi.go
        M src/strconv/atoi_test.go
        2 files changed, 119 insertions(+), 16 deletions(-)

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: newpatchset
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 5

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 24, 2017, 7:07:30 AM8/24/17
        to Keith Randall, Martin Möhrmann, Ian Lance Taylor, Robert Griesemer, golang-co...@googlegroups.com

        Aliaksandr Valialkin uploaded patch set #6 to this change.

        View Change

        strconv: optimize Atoi for common case

        Benchmark results on GOOS=linux:


        GOARCH=amd64

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   19.3ns ± 1%   8.4ns ± 1%  -56.28%  (p=0.000 n=10+10)
        Atoi/Pos/29bit-4 25.8ns ± 1% 12.5ns ± 3% -51.47% (p=0.000 n=9+10)
        Atoi/Pos/31bit-4 27.3ns ± 2% 13.1ns ± 1% -52.05% (p=0.000 n=10+10)
        Atoi/Pos/56bit-4 36.0ns ± 1% 18.1ns ± 0% -49.79% (p=0.000 n=10+9)
        Atoi/Pos/63bit-4 41.4ns ± 9% 39.0ns ± 1% -5.85% (p=0.000 n=10+10)
        Atoi/Neg/7bit-4 17.8ns ± 2% 7.5ns ± 1% -57.79% (p=0.000 n=10+10)
        Atoi/Neg/29bit-4 25.7ns ± 2% 13.0ns ± 1% -49.28% (p=0.000 n=10+10)
        Atoi/Neg/31bit-4 27.2ns ± 1% 13.9ns ± 0% -48.84% (p=0.000 n=10+7)
        Atoi/Neg/56bit-4 36.0ns ± 1% 19.3ns ± 0% -46.55% (p=0.000 n=10+8)
        Atoi/Neg/63bit-4 38.6ns ± 0% 38.8ns ± 1% ~ (p=0.267 n=10+10)

        GOARCH=386

        name old time/op new time/op delta
        Atoi/Pos/7bit-4   87.2ns ± 1%   7.5ns ± 1%  -91.37%  (p=0.000 n=9+9)
        Atoi/Pos/29bit-4 208ns ± 0% 13ns ± 1% -93.71% (p=0.000 n=10+10)
        Atoi/Pos/31bit-4 229ns ± 2% 228ns ± 0% -0.57% (p=0.048 n=10+8)
        Atoi/Neg/7bit-4 86.4ns ± 1% 7.9ns ± 1% -90.86% (p=0.000 n=9+9)
        Atoi/Neg/29bit-4 207ns ± 0% 207ns ± 1% ~ (p=0.173 n=10+9)
        Atoi/Neg/31bit-4 227ns ± 0% 228ns ± 1% +0.64% (p=0.000 n=6+9)

        Fixes #20557

        Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        ---
        M src/strconv/atoi.go
        M src/strconv/atoi_test.go
        2 files changed, 121 insertions(+), 16 deletions(-)

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: newpatchset
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 6

        Aliaksandr Valialkin (Gerrit)

        unread,
        Aug 24, 2017, 7:09:17 AM8/24/17
        to Robert Griesemer, Martin Möhrmann, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

        Patch Set 4:

        (2 comments)

        Do we have seperate Atoi tests?
        If not should be good time to add them and use the test tables for ParseInt if we can reuse them (even if we might need to filter some entries).

        Added missing Atoi tests

        View Change

        2 comments:

          • i think we should keep const fnAtoi = "Atoi" for consistency with other functions and replace "Atoi" […]

            Done

          • i think that the compiler is now smart enough to transform: […]

            Yes, the code is identical except register naming.

        To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-Project: go
        Gerrit-Branch: master
        Gerrit-MessageType: comment
        Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
        Gerrit-Change-Number: 44692
        Gerrit-PatchSet: 6
        Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
        Gerrit-Reviewer: Keith Randall <k...@golang.org>
        Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
        Gerrit-CC: Martin Möhrmann <moeh...@google.com>
        Gerrit-CC: Robert Griesemer <g...@golang.org>
        Gerrit-Comment-Date: Thu, 24 Aug 2017 11:09:13 +0000
        Gerrit-HasComments: Yes
        Gerrit-HasLabels: No

        Martin Möhrmann (Gerrit)

        unread,
        Aug 24, 2017, 7:14:19 AM8/24/17
        to Aliaksandr Valialkin, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

        thanks!

        Can we reconfirm the benchmarks if not done so already?
        +Trybots but then looks good to me.

        Patch set 6:Run-TryBot +1Code-Review +1

        View Change

          To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-Project: go
          Gerrit-Branch: master
          Gerrit-MessageType: comment
          Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
          Gerrit-Change-Number: 44692
          Gerrit-PatchSet: 6
          Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
          Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
          Gerrit-Reviewer: Keith Randall <k...@golang.org>
          Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
          Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
          Gerrit-CC: Robert Griesemer <g...@golang.org>
          Gerrit-Comment-Date: Thu, 24 Aug 2017 11:14:14 +0000
          Gerrit-HasComments: No
          Gerrit-HasLabels: Yes

          Gobot Gobot (Gerrit)

          unread,
          Aug 24, 2017, 7:15:51 AM8/24/17
          to Aliaksandr Valialkin, Martin Möhrmann, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

          TryBots beginning. Status page: https://farmer.golang.org/try?commit=af343cfe

          View Change

            To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-Project: go
            Gerrit-Branch: master
            Gerrit-MessageType: comment
            Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
            Gerrit-Change-Number: 44692
            Gerrit-PatchSet: 6
            Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
            Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
            Gerrit-Reviewer: Keith Randall <k...@golang.org>
            Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
            Gerrit-CC: Gobot Gobot <go...@golang.org>
            Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
            Gerrit-CC: Robert Griesemer <g...@golang.org>
            Gerrit-Comment-Date: Thu, 24 Aug 2017 11:15:48 +0000
            Gerrit-HasComments: No
            Gerrit-HasLabels: No

            Gobot Gobot (Gerrit)

            unread,
            Aug 24, 2017, 7:26:26 AM8/24/17
            to Aliaksandr Valialkin, Martin Möhrmann, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

            TryBots are happy.

            Patch set 6:TryBot-Result +1

            View Change

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 6
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-CC: Robert Griesemer <g...@golang.org>
              Gerrit-Comment-Date: Thu, 24 Aug 2017 11:26:21 +0000
              Gerrit-HasComments: No
              Gerrit-HasLabels: Yes

              Robert Griesemer (Gerrit)

              unread,
              Aug 24, 2017, 8:32:47 AM8/24/17
              to Aliaksandr Valialkin, Gobot Gobot, Martin Möhrmann, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              View Change

              8 comments:

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 6
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-CC: Robert Griesemer <g...@golang.org>
              Gerrit-Comment-Date: Thu, 24 Aug 2017 12:32:41 +0000
              Gerrit-HasComments: Yes
              Gerrit-HasLabels: No

              Aliaksandr Valialkin (Gerrit)

              unread,
              Aug 25, 2017, 5:53:27 AM8/25/17
              to Keith Randall, Martin Möhrmann, Gobot Gobot, Ian Lance Taylor, Robert Griesemer, golang-co...@googlegroups.com

              Aliaksandr Valialkin uploaded patch set #7 to this change.

              View Change

              strconv: optimize Atoi for common case

              Benchmark results on GOOS=linux:


              GOARCH=amd64

              name old time/op new time/op delta
              Atoi/Pos/7bit-4   20.1ns ± 2%   8.6ns ± 1%  -57.34%  (p=0.000 n=10+10)
              Atoi/Pos/26bit-4 25.8ns ± 7% 11.9ns ± 0% -53.91% (p=0.000 n=10+8)
              Atoi/Pos/31bit-4 27.3ns ± 2% 13.2ns ± 1% -51.56% (p=0.000 n=10+10)
              Atoi/Pos/56bit-4 37.2ns ± 5% 18.2ns ± 1% -51.26% (p=0.000 n=10+10)
              Atoi/Pos/63bit-4 38.7ns ± 1% 38.6ns ± 1% ~ (p=0.297 n=9+10)
              Atoi/Neg/7bit-4 17.6ns ± 1% 7.2ns ± 0% -59.22% (p=0.000 n=10+10)
              Atoi/Neg/26bit-4 24.4ns ± 1% 12.4ns ± 1% -49.28% (p=0.000 n=10+10)
              Atoi/Neg/31bit-4 26.9ns ± 0% 14.0ns ± 1% -47.88% (p=0.000 n=7+10)
              Atoi/Neg/56bit-4 36.2ns ± 1% 19.5ns ± 0% -46.24% (p=0.000 n=10+9)
              Atoi/Neg/63bit-4 38.9ns ± 1% 38.8ns ± 1% ~ (p=0.385 n=9+10)


              GOARCH=386

              name old time/op new time/op delta
              Atoi/Pos/7bit-4   89.6ns ± 1%   8.2ns ± 1%  -90.84%  (p=0.000 n=9+10)
              Atoi/Pos/26bit-4 187ns ± 2% 12ns ± 1% -93.71% (p=0.000 n=10+9)
              Atoi/Pos/31bit-4 225ns ± 1% 225ns ± 1% ~ (p=0.995 n=10+10)
              Atoi/Neg/7bit-4 86.2ns ± 1% 8.5ns ± 1% -90.14% (p=0.000 n=10+10)
              Atoi/Neg/26bit-4 183ns ± 1% 13ns ± 1% -92.77% (p=0.000 n=9+10)
              Atoi/Neg/31bit-4 223ns ± 0% 223ns ± 0% ~ (p=0.247 n=8+9)


              Fixes #20557

              Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              ---
              M src/strconv/atoi.go
              M src/strconv/atoi_test.go
              2 files changed, 117 insertions(+), 16 deletions(-)

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: newpatchset
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 7

              Aliaksandr Valialkin (Gerrit)

              unread,
              Aug 25, 2017, 5:53:38 AM8/25/17
              to Gobot Gobot, Martin Möhrmann, Robert Griesemer, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              Patch Set 6:

              (8 comments)

              Updated the CL according to comments

              View Change

              8 comments:

                • s0 is used for constructing NumError below on lines 213 and 221, so the proposed change will make these lines uglier.

                • for _, test := range parseInt32Tests { ... […]

                  I just copy-pasted TestParseInt, which uses the same for loop.

                  It would be better to make the proposed change for all the tests in this file in the follow-up CL for the sake of consistency.

                • See the reply above

                • if test.out != int64(out) ... […]

                  int(test.out) cannot truncate since it has type int32 - see parseInt32Test struct definition above.

                • Ack

                • Ack

                • define a type TestCase struct {... […]

                  Done

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 6
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-CC: Robert Griesemer <g...@golang.org>
              Gerrit-Comment-Date: Fri, 25 Aug 2017 09:53:30 +0000
              Gerrit-HasComments: Yes
              Gerrit-HasLabels: No

              Robert Griesemer (Gerrit)

              unread,
              Aug 25, 2017, 6:17:21 AM8/25/17
              to Aliaksandr Valialkin, Robert Griesemer, Gobot Gobot, Martin Möhrmann, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              Patch set 7:Code-Review +2

              View Change

              4 comments:

                • int(test.out) cannot truncate since it has type int32 - see parseInt32Test struct definition above.

                • ACK (I looked at the wrong struct for Int64)

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 7
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-Comment-Date: Fri, 25 Aug 2017 10:17:15 +0000
              Gerrit-HasComments: Yes
              Gerrit-HasLabels: Yes

              Robert Griesemer (Gerrit)

              unread,
              Aug 25, 2017, 6:17:46 AM8/25/17
              to Aliaksandr Valialkin, Robert Griesemer, golang-...@googlegroups.com, Gobot Gobot, Martin Möhrmann, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              Robert Griesemer merged this change.

              View Change

              Approvals: Keith Randall: Looks good to me, approved Robert Griesemer: Looks good to me, approved
              strconv: optimize Atoi for common case

              Benchmark results on GOOS=linux:


              GOARCH=amd64

              name old time/op new time/op delta
              Atoi/Pos/7bit-4   20.1ns ± 2%   8.6ns ± 1%  -57.34%  (p=0.000 n=10+10)
              Atoi/Pos/26bit-4 25.8ns ± 7% 11.9ns ± 0% -53.91% (p=0.000 n=10+8)
              Atoi/Pos/31bit-4 27.3ns ± 2% 13.2ns ± 1% -51.56% (p=0.000 n=10+10)
              Atoi/Pos/56bit-4 37.2ns ± 5% 18.2ns ± 1% -51.26% (p=0.000 n=10+10)
              Atoi/Pos/63bit-4 38.7ns ± 1% 38.6ns ± 1% ~ (p=0.297 n=9+10)
              Atoi/Neg/7bit-4 17.6ns ± 1% 7.2ns ± 0% -59.22% (p=0.000 n=10+10)
              Atoi/Neg/26bit-4 24.4ns ± 1% 12.4ns ± 1% -49.28% (p=0.000 n=10+10)
              Atoi/Neg/31bit-4 26.9ns ± 0% 14.0ns ± 1% -47.88% (p=0.000 n=7+10)
              Atoi/Neg/56bit-4 36.2ns ± 1% 19.5ns ± 0% -46.24% (p=0.000 n=10+9)
              Atoi/Neg/63bit-4 38.9ns ± 1% 38.8ns ± 1% ~ (p=0.385 n=9+10)

              GOARCH=386

              name old time/op new time/op delta
              Atoi/Pos/7bit-4   89.6ns ± 1%   8.2ns ± 1%  -90.84%  (p=0.000 n=9+10)
              Atoi/Pos/26bit-4 187ns ± 2% 12ns ± 1% -93.71% (p=0.000 n=10+9)
              Atoi/Pos/31bit-4 225ns ± 1% 225ns ± 1% ~ (p=0.995 n=10+10)
              Atoi/Neg/7bit-4 86.2ns ± 1% 8.5ns ± 1% -90.14% (p=0.000 n=10+10)
              Atoi/Neg/26bit-4 183ns ± 1% 13ns ± 1% -92.77% (p=0.000 n=9+10)
              Atoi/Neg/31bit-4 223ns ± 0% 223ns ± 0% ~ (p=0.247 n=8+9)

              Fixes #20557

              Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Reviewed-on: https://go-review.googlesource.com/44692
              Reviewed-by: Robert Griesemer <g...@golang.org>
              Reviewed-by: Keith Randall <k...@golang.org>

              ---
              M src/strconv/atoi.go
              M src/strconv/atoi_test.go
              2 files changed, 117 insertions(+), 16 deletions(-)

              diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
              index e1ac427..bebed04 100644
              --- a/src/strconv/atoi.go
              +++ b/src/strconv/atoi.go
              @@ -201,6 +201,34 @@

              // Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
              func Atoi(s string) (int, error) {
               	const fnAtoi = "Atoi"
              +
              +	sLen := len(s)
              + if intSize == 32 && (0 < sLen && sLen < 10) ||
              + intSize == 64 && (0 < sLen && sLen < 19) {
              + // Fast path for small integers that fit int type.
              + s0 := s
              + if s[0] == '-' || s[0] == '+' {

              + s = s[1:]
              +			if len(s) < 1 {
              + return 0, &NumError{fnAtoi, s0, ErrSyntax}
              + }
              + }
              +
              + n := 0
              + for _, ch := range []byte(s) {
              + ch -= '0'
              + if ch > 9 {
              + return 0, &NumError{fnAtoi, s0, ErrSyntax}
              + }
              + n = n*10 + int(ch)
              + }
              + if s0[0] == '-' {
              + n = -n

              + }
              + return n, nil
              + }
              +
              +	// Slow path for invalid or big integers.

              i64, err := ParseInt(s, 10, 0)
              if nerr, ok := err.(*NumError); ok {
               		nerr.Func = fnAtoi
              diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go
              index 94844c7..e2f505a 100644

              --- a/src/strconv/atoi_test.go
              +++ b/src/strconv/atoi_test.go
              @@ -6,6 +6,7 @@

              import (
              "errors"
              + "fmt"
              "reflect"
              . "strconv"
              "testing"
              @@ -354,6 +355,37 @@

              }
              }

              +func TestAtoi(t *testing.T) {
              + switch IntSize {
              + case 32:
              +		for i := range parseInt32Tests {
              + test := &parseInt32Tests[i]

              + out, err := Atoi(test.in)
              +			var testErr error

              + if test.err != nil {
              +				testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err}
              + }
              + if int(test.out) != out || !reflect.DeepEqual(testErr, err) {

              + t.Errorf("Atoi(%q) = %v, %v want %v, %v",
              +					test.in, out, err, test.out, testErr)

              + }
              + }
              + case 64:
              +		for i := range parseInt64Tests {
              + test := &parseInt64Tests[i]

              + out, err := Atoi(test.in)
              +			var testErr error

              + if test.err != nil {
              +				testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err}
              + }
              + if test.out != int64(out) || !reflect.DeepEqual(testErr, err) {

              + t.Errorf("Atoi(%q) = %v, %v want %v, %v",
              +					test.in, out, err, test.out, testErr)

              + }
              + }
              + }
              +}
              +
               func bitSizeErrStub(name string, bitSize int) error {
              return BitSizeError(name, "0", bitSize)
              }
              @@ -448,26 +480,67 @@
              }
              }

              +func BenchmarkParseInt(b *testing.B) {
              + b.Run("Pos", func(b *testing.B) {
              + benchmarkParseInt(b, 1)
              + })
              + b.Run("Neg", func(b *testing.B) {
              + benchmarkParseInt(b, -1)
              + })
              +}
              +
              +type benchCase struct {
              + name string
              + num int64
              +}
              +
              +func benchmarkParseInt(b *testing.B, neg int) {
              + cases := []benchCase{
              + {"7bit", 1<<7 - 1},
              + {"26bit", 1<<26 - 1},
              + {"31bit", 1<<31 - 1},
              + {"56bit", 1<<56 - 1},
              + {"63bit", 1<<63 - 1},
              + }
              + for _, cs := range cases {
              + b.Run(cs.name, func(b *testing.B) {
              + s := fmt.Sprintf("%d", cs.num*int64(neg))
              + for i := 0; i < b.N; i++ {
              + out, _ := ParseInt(s, 10, 64)
              + BenchSink += int(out)
              + }
              + })
              + }
              +}
              +

              func BenchmarkAtoi(b *testing.B) {
              - for i := 0; i < b.N; i++ {
              - ParseInt("12345678", 10, 0)
              -	}
              + b.Run("Pos", func(b *testing.B) {
              + benchmarkAtoi(b, 1)
              + })
              + b.Run("Neg", func(b *testing.B) {
              + benchmarkAtoi(b, -1)
              + })
              }

              -func BenchmarkAtoiNeg(b *testing.B) {

              - for i := 0; i < b.N; i++ {
              - ParseInt("-12345678", 10, 0)
              +func benchmarkAtoi(b *testing.B, neg int) {
              + cases := []benchCase{
              + {"7bit", 1<<7 - 1},
              + {"26bit", 1<<26 - 1},
              + {"31bit", 1<<31 - 1},

              }
              -}
              -
              -func BenchmarkAtoi64(b *testing.B) {
              - for i := 0; i < b.N; i++ {
              - ParseInt("12345678901234", 10, 64)
              +	if IntSize == 64 {
              + cases = append(cases, []benchCase{
              + {"56bit", 1<<56 - 1},
              + {"63bit", 1<<63 - 1},
              + }...)

              }
              -}
              -
              -func BenchmarkAtoi64Neg(b *testing.B) {
              - for i := 0; i < b.N; i++ {
              - ParseInt("-12345678901234", 10, 64)
              +	for _, cs := range cases {
              + b.Run(cs.name, func(b *testing.B) {
              + s := fmt.Sprintf("%d", cs.num*int64(neg))
              + for i := 0; i < b.N; i++ {

              + out, _ := Atoi(s)
              +				BenchSink += out
              + }
              + })
              }
              }

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: merged
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 8

              Martin Möhrmann (Gerrit)

              unread,
              Aug 25, 2017, 8:52:43 AM8/25/17
              to Aliaksandr Valialkin, Robert Griesemer, Gobot Gobot, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              View Change

              1 comment:

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 8
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-Comment-Date: Fri, 25 Aug 2017 12:52:36 +0000
              Gerrit-HasComments: Yes
              Gerrit-HasLabels: No

              Aliaksandr Valialkin (Gerrit)

              unread,
              Aug 25, 2017, 10:14:56 AM8/25/17
              to Robert Griesemer, Gobot Gobot, Martin Möhrmann, Keith Randall, Ian Lance Taylor, golang-co...@googlegroups.com

              View Change

              1 comment:

                • I made a not yet ready cleanup CL for the tests in strconv where i also changed that. […]

                  OK, waiting for your cleanup CL then.

              To view, visit change 44692. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-Project: go
              Gerrit-Branch: master
              Gerrit-MessageType: comment
              Gerrit-Change-Id: Ib6245d88cffd4b037419e2bf8e4a71b86c6d773f
              Gerrit-Change-Number: 44692
              Gerrit-PatchSet: 8
              Gerrit-Owner: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Aliaksandr Valialkin <val...@gmail.com>
              Gerrit-Reviewer: Gobot Gobot <go...@golang.org>
              Gerrit-Reviewer: Keith Randall <k...@golang.org>
              Gerrit-Reviewer: Martin Möhrmann <moeh...@google.com>
              Gerrit-Reviewer: Robert Griesemer <g...@golang.org>
              Gerrit-CC: Ian Lance Taylor <ia...@golang.org>
              Gerrit-Comment-Date: Fri, 25 Aug 2017 14:14:51 +0000
              Gerrit-HasComments: Yes
              Gerrit-HasLabels: No
              Reply all
              Reply to author
              Forward
              0 new messages