From b9bb609c1dc42b5e1dbfbc3d8846e14786a8f504 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sun, 9 Aug 2020 17:48:28 +0900 Subject: [PATCH] Fix parallel encoding --- encode.go | 30 +++- encode_opcode.go | 388 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 412 insertions(+), 6 deletions(-) diff --git a/encode.go b/encode.go index 6a8db7a..58c5b3e 100644 --- a/encode.go +++ b/encode.go @@ -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) } diff --git a/encode_opcode.go b/encode_opcode.go index aedbbd8..900bc16 100644 --- a/encode_opcode.go +++ b/encode_opcode.go @@ -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 }