Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type addrShift to enable bigger encoder/decoder cache #213

Merged
merged 1 commit into from May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 17 additions & 4 deletions codec.go
Expand Up @@ -16,6 +16,7 @@ var (
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
baseTypeAddr uintptr
maxTypeAddr uintptr
typeAddrShift uintptr
)

//go:linkname typelinks reflect.typelinks
Expand All @@ -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]))
Expand All @@ -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
Expand Down
13 changes: 13 additions & 0 deletions codec_go16_test.go
@@ -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)
}
}
2 changes: 1 addition & 1 deletion decode_compile_norace.go
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion decode_compile_race.go
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler.go
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler_norace.go
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler_race.go
Expand Up @@ -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()
Expand Down
19 changes: 16 additions & 3 deletions internal/runtime/type.go
Expand Up @@ -19,6 +19,7 @@ type TypeAddr struct {
BaseTypeAddr uintptr
MaxTypeAddr uintptr
AddrRange uintptr
AddrShift uintptr
}

var (
Expand Down Expand Up @@ -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]))
Expand All @@ -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
}