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

View File

@ -731,6 +731,11 @@ func (t opType) String() string {
return ""
}
func copyOpcode(code *opcode) *opcode {
codeMap := map[uintptr]*opcode{}
return code.copy(codeMap)
}
type opcodeHeader struct {
op opType
typ *rtype
@ -739,6 +744,16 @@ type opcodeHeader struct {
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 {
*opcodeHeader
}
@ -780,6 +795,220 @@ func (c *opcode) beforeLastCode() *opcode {
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 {
codes := []string{}
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 {
*opcodeHeader
idx uintptr
@ -861,6 +1108,28 @@ func (c *sliceElemCode) set(header *reflect.SliceHeader) {
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 {
*opcodeHeader
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 {
*opcodeHeader
idx uintptr
@ -886,6 +1174,27 @@ type arrayElemCode struct {
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 {
*opcodeHeader
key []byte
@ -894,6 +1203,27 @@ type structFieldCode struct {
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 {
*opcodeHeader
key *mapKeyCode
@ -901,6 +1231,25 @@ type mapHeaderCode struct {
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 {
*opcodeHeader
idx int
@ -909,6 +1258,27 @@ type mapKeyCode struct {
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) {
c.idx = 0
c.len = len
@ -920,6 +1290,24 @@ type mapValueCode struct {
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) {
c.iter = iter
}