diff options
| author | Daniel Martí <mvdan@mvdan.cc> | 2019-04-05 23:06:49 +0200 |
|---|---|---|
| committer | Daniel Martí <mvdan@mvdan.cc> | 2019-04-13 13:14:55 +0000 |
| commit | ab2f83c387fcc00efbdcc0a5c249af26c84ff425 (patch) | |
| tree | caf7b2db1bac258864516cdb1f32c16be7603a78 /src | |
| parent | ee64b35531a841ab4dbe41c17390214f9dea654f (diff) | |
| download | go-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')
| -rw-r--r-- | src/encoding/json/stream.go | 12 |
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. |
