Fix parallel encoding

This commit is contained in:
Masaaki Goshima 2020-08-09 17:48:28 +09:00
parent c359cc258f
commit b9bb609c1d
2 changed files with 412 additions and 6 deletions

View File

@ -31,8 +31,8 @@ type opcodeMap struct {
} }
type opcodeSet struct { type opcodeSet struct {
codeIndent *opcode codeIndent sync.Pool
code *opcode code sync.Pool
} }
func (m *opcodeMap) get(k uintptr) *opcodeSet { func (m *opcodeMap) get(k uintptr) *opcodeSet {
@ -48,6 +48,7 @@ func (m *opcodeMap) set(k uintptr, op *opcodeSet) {
var ( var (
encPool sync.Pool encPool sync.Pool
codePool sync.Pool
cachedOpcode opcodeMap cachedOpcode opcodeMap
marshalJSONType reflect.Type marshalJSONType reflect.Type
marshalTextType reflect.Type marshalTextType reflect.Type
@ -147,15 +148,20 @@ func (e *Encoder) encode(v interface{}) error {
if codeSet := cachedOpcode.get(typeptr); codeSet != nil { if codeSet := cachedOpcode.get(typeptr); codeSet != nil {
var code *opcode var code *opcode
if e.enabledIndent { if e.enabledIndent {
code = codeSet.codeIndent code = codeSet.codeIndent.Get().(*opcode)
} else { } else {
code = codeSet.code code = codeSet.code.Get().(*opcode)
} }
p := uintptr(header.ptr) p := uintptr(header.ptr)
code.ptr = p code.ptr = p
if err := e.run(code); err != nil { if err := e.run(code); err != nil {
return err return err
} }
if e.enabledIndent {
codeSet.codeIndent.Put(code)
} else {
codeSet.code.Put(code)
}
return nil return nil
} }
@ -170,13 +176,25 @@ func (e *Encoder) encode(v interface{}) error {
if err != nil { if err != nil {
return err return err
} }
codeSet := &opcodeSet{codeIndent: codeIndent, code: code} codeSet := &opcodeSet{
codeIndent: sync.Pool{
New: func() interface{} {
return copyOpcode(codeIndent)
},
},
code: sync.Pool{
New: func() interface{} {
return copyOpcode(code)
},
},
}
cachedOpcode.set(typeptr, codeSet) cachedOpcode.set(typeptr, codeSet)
p := uintptr(header.ptr) p := uintptr(header.ptr)
code.ptr = p
if e.enabledIndent { if e.enabledIndent {
codeIndent.ptr = p
return e.run(codeIndent) return e.run(codeIndent)
} }
code.ptr = p
return e.run(code) return e.run(code)
} }

View File

@ -731,6 +731,11 @@ func (t opType) String() string {
return "" return ""
} }
func copyOpcode(code *opcode) *opcode {
codeMap := map[uintptr]*opcode{}
return code.copy(codeMap)
}
type opcodeHeader struct { type opcodeHeader struct {
op opType op opType
typ *rtype typ *rtype
@ -739,6 +744,16 @@ type opcodeHeader struct {
next *opcode next *opcode
} }
func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader {
return &opcodeHeader{
op: h.op,
typ: h.typ,
ptr: h.ptr,
indent: h.indent,
next: h.next.copy(codeMap),
}
}
type opcode struct { type opcode struct {
*opcodeHeader *opcodeHeader
} }
@ -780,6 +795,220 @@ func (c *opcode) beforeLastCode() *opcode {
return nil return nil
} }
func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
var code *opcode
switch c.op {
case opArrayHead, opArrayHeadIndent:
code = c.toArrayHeaderCode().copy(codeMap)
case opArrayElem, opArrayElemIndent:
code = c.toArrayElemCode().copy(codeMap)
case opSliceHead, opSliceHeadIndent:
code = c.toSliceHeaderCode().copy(codeMap)
case opSliceElem, opSliceElemIndent:
code = c.toSliceElemCode().copy(codeMap)
case opMapHead, opMapHeadLoad, opMapHeadIndent, opMapHeadLoadIndent:
code = c.toMapHeadCode().copy(codeMap)
case opMapKey, opMapKeyIndent:
code = c.toMapKeyCode().copy(codeMap)
case opMapValue, opMapValueIndent:
code = c.toMapValueCode().copy(codeMap)
case opStructFieldHead,
opStructFieldHeadInt,
opStructFieldHeadInt8,
opStructFieldHeadInt16,
opStructFieldHeadInt32,
opStructFieldHeadInt64,
opStructFieldHeadUint,
opStructFieldHeadUint8,
opStructFieldHeadUint16,
opStructFieldHeadUint32,
opStructFieldHeadUint64,
opStructFieldHeadFloat32,
opStructFieldHeadFloat64,
opStructFieldHeadString,
opStructFieldHeadBool,
opStructFieldHeadIndent,
opStructFieldHeadIntIndent,
opStructFieldHeadInt8Indent,
opStructFieldHeadInt16Indent,
opStructFieldHeadInt32Indent,
opStructFieldHeadInt64Indent,
opStructFieldHeadUintIndent,
opStructFieldHeadUint8Indent,
opStructFieldHeadUint16Indent,
opStructFieldHeadUint32Indent,
opStructFieldHeadUint64Indent,
opStructFieldHeadFloat32Indent,
opStructFieldHeadFloat64Indent,
opStructFieldHeadStringIndent,
opStructFieldHeadBoolIndent,
opStructFieldHeadOmitEmpty,
opStructFieldHeadIntOmitEmpty,
opStructFieldHeadInt8OmitEmpty,
opStructFieldHeadInt16OmitEmpty,
opStructFieldHeadInt32OmitEmpty,
opStructFieldHeadInt64OmitEmpty,
opStructFieldHeadUintOmitEmpty,
opStructFieldHeadUint8OmitEmpty,
opStructFieldHeadUint16OmitEmpty,
opStructFieldHeadUint32OmitEmpty,
opStructFieldHeadUint64OmitEmpty,
opStructFieldHeadFloat32OmitEmpty,
opStructFieldHeadFloat64OmitEmpty,
opStructFieldHeadStringOmitEmpty,
opStructFieldHeadBoolOmitEmpty,
opStructFieldHeadOmitEmptyIndent,
opStructFieldHeadIntOmitEmptyIndent,
opStructFieldHeadInt8OmitEmptyIndent,
opStructFieldHeadInt16OmitEmptyIndent,
opStructFieldHeadInt32OmitEmptyIndent,
opStructFieldHeadInt64OmitEmptyIndent,
opStructFieldHeadUintOmitEmptyIndent,
opStructFieldHeadUint8OmitEmptyIndent,
opStructFieldHeadUint16OmitEmptyIndent,
opStructFieldHeadUint32OmitEmptyIndent,
opStructFieldHeadUint64OmitEmptyIndent,
opStructFieldHeadFloat32OmitEmptyIndent,
opStructFieldHeadFloat64OmitEmptyIndent,
opStructFieldHeadStringOmitEmptyIndent,
opStructFieldHeadBoolOmitEmptyIndent,
opStructFieldPtrHead,
opStructFieldPtrHeadInt,
opStructFieldPtrHeadInt8,
opStructFieldPtrHeadInt16,
opStructFieldPtrHeadInt32,
opStructFieldPtrHeadInt64,
opStructFieldPtrHeadUint,
opStructFieldPtrHeadUint8,
opStructFieldPtrHeadUint16,
opStructFieldPtrHeadUint32,
opStructFieldPtrHeadUint64,
opStructFieldPtrHeadFloat32,
opStructFieldPtrHeadFloat64,
opStructFieldPtrHeadString,
opStructFieldPtrHeadBool,
opStructFieldPtrHeadIndent,
opStructFieldPtrHeadIntIndent,
opStructFieldPtrHeadInt8Indent,
opStructFieldPtrHeadInt16Indent,
opStructFieldPtrHeadInt32Indent,
opStructFieldPtrHeadInt64Indent,
opStructFieldPtrHeadUintIndent,
opStructFieldPtrHeadUint8Indent,
opStructFieldPtrHeadUint16Indent,
opStructFieldPtrHeadUint32Indent,
opStructFieldPtrHeadUint64Indent,
opStructFieldPtrHeadFloat32Indent,
opStructFieldPtrHeadFloat64Indent,
opStructFieldPtrHeadStringIndent,
opStructFieldPtrHeadBoolIndent,
opStructFieldPtrHeadOmitEmpty,
opStructFieldPtrHeadIntOmitEmpty,
opStructFieldPtrHeadInt8OmitEmpty,
opStructFieldPtrHeadInt16OmitEmpty,
opStructFieldPtrHeadInt32OmitEmpty,
opStructFieldPtrHeadInt64OmitEmpty,
opStructFieldPtrHeadUintOmitEmpty,
opStructFieldPtrHeadUint8OmitEmpty,
opStructFieldPtrHeadUint16OmitEmpty,
opStructFieldPtrHeadUint32OmitEmpty,
opStructFieldPtrHeadUint64OmitEmpty,
opStructFieldPtrHeadFloat32OmitEmpty,
opStructFieldPtrHeadFloat64OmitEmpty,
opStructFieldPtrHeadStringOmitEmpty,
opStructFieldPtrHeadBoolOmitEmpty,
opStructFieldPtrHeadOmitEmptyIndent,
opStructFieldPtrHeadIntOmitEmptyIndent,
opStructFieldPtrHeadInt8OmitEmptyIndent,
opStructFieldPtrHeadInt16OmitEmptyIndent,
opStructFieldPtrHeadInt32OmitEmptyIndent,
opStructFieldPtrHeadInt64OmitEmptyIndent,
opStructFieldPtrHeadUintOmitEmptyIndent,
opStructFieldPtrHeadUint8OmitEmptyIndent,
opStructFieldPtrHeadUint16OmitEmptyIndent,
opStructFieldPtrHeadUint32OmitEmptyIndent,
opStructFieldPtrHeadUint64OmitEmptyIndent,
opStructFieldPtrHeadFloat32OmitEmptyIndent,
opStructFieldPtrHeadFloat64OmitEmptyIndent,
opStructFieldPtrHeadStringOmitEmptyIndent,
opStructFieldPtrHeadBoolOmitEmptyIndent,
opStructField,
opStructFieldInt,
opStructFieldInt8,
opStructFieldInt16,
opStructFieldInt32,
opStructFieldInt64,
opStructFieldUint,
opStructFieldUint8,
opStructFieldUint16,
opStructFieldUint32,
opStructFieldUint64,
opStructFieldFloat32,
opStructFieldFloat64,
opStructFieldString,
opStructFieldBool,
opStructFieldIndent,
opStructFieldIntIndent,
opStructFieldInt8Indent,
opStructFieldInt16Indent,
opStructFieldInt32Indent,
opStructFieldInt64Indent,
opStructFieldUintIndent,
opStructFieldUint8Indent,
opStructFieldUint16Indent,
opStructFieldUint32Indent,
opStructFieldUint64Indent,
opStructFieldFloat32Indent,
opStructFieldFloat64Indent,
opStructFieldStringIndent,
opStructFieldBoolIndent,
opStructFieldOmitEmpty,
opStructFieldIntOmitEmpty,
opStructFieldInt8OmitEmpty,
opStructFieldInt16OmitEmpty,
opStructFieldInt32OmitEmpty,
opStructFieldInt64OmitEmpty,
opStructFieldUintOmitEmpty,
opStructFieldUint8OmitEmpty,
opStructFieldUint16OmitEmpty,
opStructFieldUint32OmitEmpty,
opStructFieldUint64OmitEmpty,
opStructFieldFloat32OmitEmpty,
opStructFieldFloat64OmitEmpty,
opStructFieldStringOmitEmpty,
opStructFieldBoolOmitEmpty,
opStructFieldOmitEmptyIndent,
opStructFieldIntOmitEmptyIndent,
opStructFieldInt8OmitEmptyIndent,
opStructFieldInt16OmitEmptyIndent,
opStructFieldInt32OmitEmptyIndent,
opStructFieldInt64OmitEmptyIndent,
opStructFieldUintOmitEmptyIndent,
opStructFieldUint8OmitEmptyIndent,
opStructFieldUint16OmitEmptyIndent,
opStructFieldUint32OmitEmptyIndent,
opStructFieldUint64OmitEmptyIndent,
opStructFieldFloat32OmitEmptyIndent,
opStructFieldFloat64OmitEmptyIndent,
opStructFieldStringOmitEmptyIndent,
opStructFieldBoolOmitEmptyIndent:
code = c.toStructFieldCode().copy(codeMap)
default:
code = &opcode{}
codeMap[addr] = code
code.opcodeHeader = c.opcodeHeader.copy(codeMap)
}
return code
}
func (c *opcode) dump() string { func (c *opcode) dump() string {
codes := []string{} codes := []string{}
for code := c; code.op != opEnd; { for code := c; code.op != opEnd; {
@ -846,6 +1075,24 @@ func newSliceHeaderCode(indent int) *sliceHeaderCode {
} }
} }
func (c *sliceHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
header := &sliceHeaderCode{}
code := (*opcode)(unsafe.Pointer(header))
codeMap[addr] = code
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
header.elem = (*sliceElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
header.end = c.end.copy(codeMap)
return code
}
type sliceElemCode struct { type sliceElemCode struct {
*opcodeHeader *opcodeHeader
idx uintptr idx uintptr
@ -861,6 +1108,28 @@ func (c *sliceElemCode) set(header *reflect.SliceHeader) {
c.data = header.Data c.data = header.Data
} }
func (c *sliceElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
elem := &sliceElemCode{
idx: c.idx,
len: c.len,
size: c.size,
data: c.data,
}
code := (*opcode)(unsafe.Pointer(elem))
codeMap[addr] = code
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
elem.end = c.end.copy(codeMap)
return code
}
type arrayHeaderCode struct { type arrayHeaderCode struct {
*opcodeHeader *opcodeHeader
len uintptr len uintptr
@ -878,6 +1147,25 @@ func newArrayHeaderCode(indent, alen int) *arrayHeaderCode {
} }
} }
func (c *arrayHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
header := &arrayHeaderCode{}
code := (*opcode)(unsafe.Pointer(header))
codeMap[addr] = code
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
header.len = c.len
header.elem = (*arrayElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
header.end = c.end.copy(codeMap)
return code
}
type arrayElemCode struct { type arrayElemCode struct {
*opcodeHeader *opcodeHeader
idx uintptr idx uintptr
@ -886,6 +1174,27 @@ type arrayElemCode struct {
end *opcode end *opcode
} }
func (c *arrayElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
elem := &arrayElemCode{
idx: c.idx,
len: c.len,
size: c.size,
}
code := (*opcode)(unsafe.Pointer(elem))
codeMap[addr] = code
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
elem.end = c.end.copy(codeMap)
return code
}
type structFieldCode struct { type structFieldCode struct {
*opcodeHeader *opcodeHeader
key []byte key []byte
@ -894,6 +1203,27 @@ type structFieldCode struct {
end *opcode end *opcode
} }
func (c *structFieldCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
field := &structFieldCode{
key: c.key,
offset: c.offset,
}
code := (*opcode)(unsafe.Pointer(field))
codeMap[addr] = code
field.opcodeHeader = c.opcodeHeader.copy(codeMap)
field.nextField = c.nextField.copy(codeMap)
field.end = c.end.copy(codeMap)
return code
}
type mapHeaderCode struct { type mapHeaderCode struct {
*opcodeHeader *opcodeHeader
key *mapKeyCode key *mapKeyCode
@ -901,6 +1231,25 @@ type mapHeaderCode struct {
end *opcode end *opcode
} }
func (c *mapHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
header := &mapHeaderCode{}
code := (*opcode)(unsafe.Pointer(header))
codeMap[addr] = code
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
header.key = (*mapKeyCode)(unsafe.Pointer(c.key.copy(codeMap)))
header.value = (*mapValueCode)(unsafe.Pointer(c.value.copy(codeMap)))
header.end = c.end.copy(codeMap)
return code
}
type mapKeyCode struct { type mapKeyCode struct {
*opcodeHeader *opcodeHeader
idx int idx int
@ -909,6 +1258,27 @@ type mapKeyCode struct {
end *opcode end *opcode
} }
func (c *mapKeyCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
key := &mapKeyCode{
idx: c.idx,
len: c.len,
iter: c.iter,
}
code := (*opcode)(unsafe.Pointer(key))
codeMap[addr] = code
key.opcodeHeader = c.opcodeHeader.copy(codeMap)
key.end = c.end.copy(codeMap)
return code
}
func (c *mapKeyCode) set(len int, iter unsafe.Pointer) { func (c *mapKeyCode) set(len int, iter unsafe.Pointer) {
c.idx = 0 c.idx = 0
c.len = len c.len = len
@ -920,6 +1290,24 @@ type mapValueCode struct {
iter unsafe.Pointer iter unsafe.Pointer
} }
func (c *mapValueCode) copy(codeMap map[uintptr]*opcode) *opcode {
if c == nil {
return nil
}
addr := uintptr(unsafe.Pointer(c))
if code, exists := codeMap[addr]; exists {
return code
}
value := &mapValueCode{
iter: c.iter,
}
code := (*opcode)(unsafe.Pointer(value))
codeMap[addr] = code
value.opcodeHeader = c.opcodeHeader.copy(codeMap)
return code
}
func (c *mapValueCode) set(iter unsafe.Pointer) { func (c *mapValueCode) set(iter unsafe.Pointer) {
c.iter = iter c.iter = iter
} }