Commit 5f209aba authored by David Crawshaw's avatar David Crawshaw

encoding/json: copy-on-write cacheTypeFields

Swtich from a sync.RWMutex to atomic.Value for cacheTypeFields.

On GOARCH=386, this recovers most of the remaining performance
difference from the 1.6 release. Compared with tip on linux/386:

	name            old time/op    new time/op    delta
	CodeDecoder-40    92.8ms ± 1%    87.7ms ± 1%  -5.50%  (p=0.000 n=10+10)

	name            old speed      new speed      delta
	CodeDecoder-40  20.9MB/s ± 1%  22.1MB/s ± 1%  +5.83%  (p=0.000 n=10+10)

With more time and care, I believe more of the JSON decoder's work
could be shifted so it is done before decoding, and independent of
the number of bytes processed. Maybe someone could explore that for
Go 1.8.

For #16117.

Change-Id: I049655b2e5b76384a0d5f4b90e3ec7cc8d8c4340
Reviewed-on: https://go-review.googlesource.com/24472
Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: 's avatarDmitry Vyukov <dvyukov@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 33fa855e
......@@ -22,6 +22,7 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"unicode"
"unicode/utf8"
)
......@@ -1231,15 +1232,14 @@ func dominantField(fields []field) (field, bool) {
}
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
value atomic.Value // map[reflect.Type][]field
mu sync.Mutex // used only by writers
}
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
func cachedTypeFields(t reflect.Type) []field {
fieldCache.RLock()
f := fieldCache.m[t]
fieldCache.RUnlock()
m, _ := fieldCache.value.Load().(map[reflect.Type][]field)
f := m[t]
if f != nil {
return f
}
......@@ -1251,11 +1251,14 @@ func cachedTypeFields(t reflect.Type) []field {
f = []field{}
}
fieldCache.Lock()
if fieldCache.m == nil {
fieldCache.m = map[reflect.Type][]field{}
fieldCache.mu.Lock()
m, _ = fieldCache.value.Load().(map[reflect.Type][]field)
newM := make(map[reflect.Type][]field, len(m)+1)
for k, v := range m {
newM[k] = v
}
fieldCache.m[t] = f
fieldCache.Unlock()
newM[t] = f
fieldCache.value.Store(newM)
fieldCache.mu.Unlock()
return f
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment