diff options
author | Martin Möhrmann <martisch@uos.de> | 2016-08-26 15:00:46 +0200 |
---|---|---|
committer | Martin Möhrmann <martisch@uos.de> | 2016-08-30 18:17:20 +0000 |
commit | 0dae9dfb08a30983cce1114742c974077bdf5e18 (patch) | |
tree | b625e6f0852c8285c528aa8499f18777c593c856 /src/runtime/string_test.go | |
parent | 0d7a2241cb684236f2728bb08514e7f256ac4a43 (diff) | |
download | go-0dae9dfb08a30983cce1114742c974077bdf5e18.tar.gz go-0dae9dfb08a30983cce1114742c974077bdf5e18.zip |
cmd/compile: improve string iteration performance
Generate a for loop for ranging over strings that only needs to call
the runtime function charntorune for non ASCII characters.
This provides faster iteration over ASCII characters and slightly
faster iteration for other characters.
The runtime function charntorune is changed to take an index from where
to start decoding and returns the index after the last byte belonging
to the decoded rune.
All call sites of charntorune in the runtime are replaced by a for loop
that will be transformed by the compiler instead of calling the charntorune
function directly.
go binary size decreases by 80 bytes.
godoc binary size increases by around 4 kilobytes.
runtime:
name old time/op new time/op delta
RuneIterate/range/ASCII-4 43.7ns ± 3% 10.3ns ± 4% -76.33% (p=0.000 n=44+45)
RuneIterate/range/Japanese-4 72.5ns ± 2% 62.8ns ± 2% -13.41% (p=0.000 n=49+50)
RuneIterate/range1/ASCII-4 43.5ns ± 2% 10.4ns ± 3% -76.18% (p=0.000 n=50+50)
RuneIterate/range1/Japanese-4 72.5ns ± 2% 62.9ns ± 2% -13.26% (p=0.000 n=50+49)
RuneIterate/range2/ASCII-4 43.5ns ± 3% 10.3ns ± 2% -76.22% (p=0.000 n=48+47)
RuneIterate/range2/Japanese-4 72.4ns ± 2% 62.7ns ± 2% -13.47% (p=0.000 n=50+50)
strings:
name old time/op new time/op delta
IndexRune-4 64.7ns ± 5% 22.4ns ± 3% -65.43% (p=0.000 n=25+21)
MapNoChanges-4 269ns ± 2% 157ns ± 2% -41.46% (p=0.000 n=23+24)
Fields-4 23.0ms ± 2% 19.7ms ± 2% -14.35% (p=0.000 n=25+25)
FieldsFunc-4 23.1ms ± 2% 19.6ms ± 2% -14.94% (p=0.000 n=25+24)
name old speed new speed delta
Fields-4 45.6MB/s ± 2% 53.2MB/s ± 2% +16.87% (p=0.000 n=24+25)
FieldsFunc-4 45.5MB/s ± 2% 53.5MB/s ± 2% +17.57% (p=0.000 n=25+24)
Updates #13162
Change-Id: I79ffaf828d82bf9887592f08e5cad883e9f39701
Reviewed-on: https://go-review.googlesource.com/27853
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Martin Möhrmann <martisch@uos.de>
Diffstat (limited to 'src/runtime/string_test.go')
-rw-r--r-- | src/runtime/string_test.go | 52 |
1 files changed, 33 insertions, 19 deletions
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go index 0f1d82a481..b1757f0721 100644 --- a/src/runtime/string_test.go +++ b/src/runtime/string_test.go @@ -82,28 +82,42 @@ func BenchmarkCompareStringBig(b *testing.B) { b.SetBytes(int64(len(s1))) } -func BenchmarkRuneIterate(b *testing.B) { - bytes := make([]byte, 100) - for i := range bytes { - bytes[i] = byte('A') - } - s := string(bytes) - for i := 0; i < b.N; i++ { - for range s { - } - } +var stringdata = []struct{ name, data string }{ + {"ASCII", "01234567890"}, + {"Japanese", "日本語日本語日本語"}, } -func BenchmarkRuneIterate2(b *testing.B) { - bytes := make([]byte, 100) - for i := range bytes { - bytes[i] = byte('A') - } - s := string(bytes) - for i := 0; i < b.N; i++ { - for range s { +func BenchmarkRuneIterate(b *testing.B) { + b.Run("range", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for range sd.data { + } + } + }) } - } + }) + b.Run("range1", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _ = range sd.data { + } + } + }) + } + }) + b.Run("range2", func(b *testing.B) { + for _, sd := range stringdata { + b.Run(sd.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, _ = range sd.data { + } + } + }) + } + }) } func BenchmarkArrayEqual(b *testing.B) { |