Merge pull request #213 from jxskiss/compact_type_cache

Add type addrShift to enable bigger encoder/decoder cache
This commit is contained in:
Masaaki Goshima 2021-05-11 04:15:37 +09:00 committed by GitHub
commit 102554cbcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 51 additions and 12 deletions

View File

@ -16,6 +16,7 @@ var (
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
baseTypeAddr uintptr
maxTypeAddr uintptr
typeAddrShift uintptr
)
//go:linkname typelinks reflect.typelinks
@ -35,8 +36,10 @@ func setupCodec() error {
section := sections[0]
offset := offsets[0]
var (
min uintptr = uintptr(^uint(0))
max uintptr = 0
min uintptr = uintptr(^uint(0))
max uintptr = 0
isAligned64 = true
isAligned32 = true
)
for i := 0; i < len(offset); i++ {
typ := (*rtype)(rtypeOff(section, offset[i]))
@ -56,15 +59,25 @@ func setupCodec() error {
max = addr
}
}
// check every address is aligned from the base address
isAligned64 = isAligned64 && (addr-min)&63 == 0
isAligned32 = isAligned32 && (addr-min)&31 == 0
}
addrRange := max - min
if addrRange == 0 {
return fmt.Errorf("failed to get address range of types")
}
if addrRange > maxAcceptableTypeAddrRange {
if isAligned64 {
typeAddrShift = 6
} else if isAligned32 {
typeAddrShift = 5
}
cacheSize := addrRange >> typeAddrShift
if cacheSize > maxAcceptableTypeAddrRange {
return fmt.Errorf("too big address range %d", addrRange)
}
cachedDecoder = make([]decoder, addrRange)
cachedDecoder = make([]decoder, cacheSize)
baseTypeAddr = min
maxTypeAddr = max
return nil

13
codec_go16_test.go Normal file
View File

@ -0,0 +1,13 @@
// +build go1.16
package json
import (
"testing"
)
func TestTypeAddressAligned32(t *testing.T) {
if typeAddrShift != 5 {
t.Fatalf("unexpected type address shift %d, want 5", typeAddrShift)
}
}

View File

@ -10,7 +10,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
}
index := typeptr - baseTypeAddr
index := (typeptr - baseTypeAddr) >> typeAddrShift
if dec := cachedDecoder[index]; dec != nil {
return dec, nil
}

View File

@ -15,7 +15,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
}
index := typeptr - baseTypeAddr
index := (typeptr - baseTypeAddr) >> typeAddrShift
decMu.RLock()
if dec := cachedDecoder[index]; dec != nil {
decMu.RUnlock()

View File

@ -27,7 +27,7 @@ func init() {
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange)
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift)
}
func loadOpcodeMap() map[uintptr]*OpcodeSet {

View File

@ -12,7 +12,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetCodeSetSlowPath(typeptr)
}
index := typeptr - typeAddr.BaseTypeAddr
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
return codeSet, nil
}

View File

@ -15,7 +15,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetCodeSetSlowPath(typeptr)
}
index := typeptr - typeAddr.BaseTypeAddr
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
setsMu.RLock()
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
setsMu.RUnlock()

View File

@ -19,6 +19,7 @@ type TypeAddr struct {
BaseTypeAddr uintptr
MaxTypeAddr uintptr
AddrRange uintptr
AddrShift uintptr
}
var (
@ -49,8 +50,10 @@ func AnalyzeTypeAddr() *TypeAddr {
section := sections[0]
offset := offsets[0]
var (
min uintptr = uintptr(^uint(0))
max uintptr = 0
min uintptr = uintptr(^uint(0))
max uintptr = 0
isAligned64 = true
isAligned32 = true
)
for i := 0; i < len(offset); i++ {
typ := (*Type)(rtypeOff(section, offset[i]))
@ -70,18 +73,28 @@ func AnalyzeTypeAddr() *TypeAddr {
max = addr
}
}
isAligned64 = isAligned64 && (addr-min)&63 == 0
isAligned32 = isAligned32 && (addr-min)&31 == 0
}
addrRange := max - min
if addrRange == 0 {
return nil
}
if addrRange > maxAcceptableTypeAddrRange {
var addrShift uintptr
if isAligned64 {
addrShift = 6
} else if isAligned32 {
addrShift = 5
}
cacheSize := addrRange >> addrShift
if cacheSize > maxAcceptableTypeAddrRange {
return nil
}
typeAddr = &TypeAddr{
BaseTypeAddr: min,
MaxTypeAddr: max,
AddrRange: addrRange,
AddrShift: addrShift,
}
return typeAddr
}