Merge pull request #68 from goccy/feature/add-benchmark

Optimize access to opcodeMap
This commit is contained in:
Masaaki Goshima 2020-12-15 14:55:13 +09:00 committed by GitHub
commit 0e0bf702c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 18 additions and 15 deletions

View File

@ -9,6 +9,7 @@ import (
"reflect" "reflect"
"strconv" "strconv"
"sync" "sync"
"sync/atomic"
"unsafe" "unsafe"
) )
@ -33,31 +34,32 @@ const (
bufSize = 1024 bufSize = 1024
) )
type opcodeMap struct {
sync.Map
}
type opcodeSet struct { type opcodeSet struct {
codeIndent *opcode codeIndent *opcode
code *opcode code *opcode
ctx sync.Pool ctx sync.Pool
} }
func (m *opcodeMap) get(k uintptr) *opcodeSet { func loadOpcodeMap() map[uintptr]*opcodeSet {
if v, ok := m.Load(k); ok { p := atomic.LoadPointer(&cachedOpcode)
return v.(*opcodeSet) return *(*map[uintptr]*opcodeSet)(unsafe.Pointer(&p))
}
return nil
} }
func (m *opcodeMap) set(k uintptr, op *opcodeSet) { func storeOpcodeSet(typ uintptr, set *opcodeSet, m map[uintptr]*opcodeSet) {
m.Store(k, op) newOpcodeMap := make(map[uintptr]*opcodeSet, len(m)+1)
newOpcodeMap[typ] = set
for k, v := range m {
newOpcodeMap[k] = v
}
atomic.StorePointer(&cachedOpcode, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap)))
} }
var ( var (
encPool sync.Pool encPool sync.Pool
codePool sync.Pool codePool sync.Pool
cachedOpcode opcodeMap cachedOpcode unsafe.Pointer // map[uintptr]*opcodeSet
marshalJSONType reflect.Type marshalJSONType reflect.Type
marshalTextType reflect.Type marshalTextType reflect.Type
) )
@ -72,7 +74,6 @@ func init() {
} }
}, },
} }
cachedOpcode = opcodeMap{}
marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem() marshalJSONType = reflect.TypeOf((*Marshaler)(nil)).Elem()
marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
} }
@ -175,7 +176,8 @@ func (e *Encoder) encode(v interface{}) error {
typ := header.typ typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ)) typeptr := uintptr(unsafe.Pointer(typ))
if codeSet := cachedOpcode.get(typeptr); codeSet != nil { opcodeMap := loadOpcodeMap()
if codeSet, exists := opcodeMap[typeptr]; exists {
var code *opcode var code *opcode
if e.enabledIndent { if e.enabledIndent {
code = codeSet.codeIndent code = codeSet.codeIndent
@ -224,7 +226,8 @@ func (e *Encoder) encode(v interface{}) error {
}, },
}, },
} }
cachedOpcode.set(typeptr, codeSet)
storeOpcodeSet(typeptr, codeSet, opcodeMap)
p := uintptr(header.ptr) p := uintptr(header.ptr)
ctx := codeSet.ctx.Get().(*encodeRuntimeContext) ctx := codeSet.ctx.Get().(*encodeRuntimeContext)
ctx.init(p) ctx.init(p)