aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
authorDaniel Martí <mvdan@mvdan.cc>2019-04-05 23:06:49 +0200
committerDaniel Martí <mvdan@mvdan.cc>2019-04-13 13:14:55 +0000
commitab2f83c387fcc00efbdcc0a5c249af26c84ff425 (patch)
treecaf7b2db1bac258864516cdb1f32c16be7603a78 /src/encoding
parentee64b35531a841ab4dbe41c17390214f9dea654f (diff)
downloadgo-ab2f83c387fcc00efbdcc0a5c249af26c84ff425.tar.xz
encoding/json: remove a bounds check in readValue
readValue is a hot function, clocking in at ~13% flat CPU use in CodeDecoder. In particular, looping over the bytes is slow. That's partially because the code contains a bounds check at the start of the loop. The source of the problem is that scanp is a signed integer, and comes from a field, so the compiler doesn't know that it's non-negative. Help it with a simple and comparatively cheap hint. While at it, use scanp as the index variable directly, removing the need for a duplicate index variable which is later added back into scanp. name old time/op new time/op delta CodeDecoder-8 11.3ms ± 1% 11.2ms ± 1% -0.98% (p=0.000 n=9+9) name old speed new speed delta CodeDecoder-8 172MB/s ± 1% 174MB/s ± 1% +0.99% (p=0.000 n=9+9) Updates #28923. Change-Id: I138f83babdf316fc97697cc18f595c3403c1ddb7 Reviewed-on: https://go-review.googlesource.com/c/go/+/170939 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/encoding')
-rw-r--r--src/encoding/json/stream.go12
1 files changed, 7 insertions, 5 deletions
diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go
index 7d5137fbc7..e29127499b 100644
--- a/src/encoding/json/stream.go
+++ b/src/encoding/json/stream.go
@@ -92,20 +92,23 @@ func (dec *Decoder) readValue() (int, error) {
scanp := dec.scanp
var err error
Input:
- for {
+ // help the compiler see that scanp is never negative, so it can remove
+ // some bounds checks below.
+ for scanp >= 0 {
+
// Look in the buffer for a new value.
- for i, c := range dec.buf[scanp:] {
+ for ; scanp < len(dec.buf); scanp++ {
+ c := dec.buf[scanp]
dec.scan.bytes++
switch dec.scan.step(&dec.scan, c) {
case scanEnd:
- scanp += i
break Input
case scanEndObject, scanEndArray:
// scanEnd is delayed one byte.
// We might block trying to get that byte from src,
// so instead invent a space byte.
if stateEndValue(&dec.scan, ' ') == scanEnd {
- scanp += i + 1
+ scanp++
break Input
}
case scanError:
@@ -113,7 +116,6 @@ Input:
return 0, dec.scan.err
}
}
- scanp = len(dec.buf)
// Did the last read have an error?
// Delayed until now to allow buffer scan.