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 cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
baseTypeAddr uintptr baseTypeAddr uintptr
maxTypeAddr uintptr maxTypeAddr uintptr
typeAddrShift uintptr
) )
//go:linkname typelinks reflect.typelinks //go:linkname typelinks reflect.typelinks
@ -37,6 +38,8 @@ func setupCodec() error {
var ( var (
min uintptr = uintptr(^uint(0)) min uintptr = uintptr(^uint(0))
max uintptr = 0 max uintptr = 0
isAligned64 = true
isAligned32 = true
) )
for i := 0; i < len(offset); i++ { for i := 0; i < len(offset); i++ {
typ := (*rtype)(rtypeOff(section, offset[i])) typ := (*rtype)(rtypeOff(section, offset[i]))
@ -56,15 +59,25 @@ func setupCodec() error {
max = addr 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 addrRange := max - min
if addrRange == 0 { if addrRange == 0 {
return fmt.Errorf("failed to get address range of types") 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) return fmt.Errorf("too big address range %d", addrRange)
} }
cachedDecoder = make([]decoder, addrRange) cachedDecoder = make([]decoder, cacheSize)
baseTypeAddr = min baseTypeAddr = min
maxTypeAddr = max maxTypeAddr = max
return nil 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) return decodeCompileToGetDecoderSlowPath(typeptr, typ)
} }
index := typeptr - baseTypeAddr index := (typeptr - baseTypeAddr) >> typeAddrShift
if dec := cachedDecoder[index]; dec != nil { if dec := cachedDecoder[index]; dec != nil {
return dec, nil return dec, nil
} }

View File

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

View File

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

View File

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

View File

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

View File

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