forked from joejulian/gio
internal/ops: use uint32 for pc, version, macroID
4GB of render data should be sufficient for anyone.
By replacing an int with uint32, it allows for a smaller memory
footprint and faster caching. Example impact on rendering static
labels.
│ before.txt │ after.txt │
│ sec/op │ sec/op vs base │
LabelStatic/1000runes-RTL-arabic-32 98.08µ ± 3% 88.17µ ± 1% -10.10% (p=0.002 n=6)
LabelStatic/1000runes-RTL-complex-32 103.9µ ± 2% 101.9µ ± 1% -1.84% (p=0.009 n=6)
LabelStatic/1000runes-RTL-emoji-32 113.3µ ± 2% 100.7µ ± 3% -11.11% (p=0.002 n=6)
LabelStatic/1000runes-RTL-latin-32 100.01µ ± 1% 92.31µ ± 1% -7.69% (p=0.002 n=6)
LabelStatic/1000runes-LTR-arabic-32 97.90µ ± 2% 87.92µ ± 2% -10.19% (p=0.002 n=6)
LabelStatic/1000runes-LTR-complex-32 102.63µ ± 2% 99.81µ ± 1% -2.75% (p=0.002 n=6)
LabelStatic/1000runes-LTR-emoji-32 106.56µ ± 2% 98.47µ ± 1% -7.59% (p=0.002 n=6)
LabelStatic/1000runes-LTR-latin-32 97.51µ ± 1% 92.60µ ± 3% -5.03% (p=0.002 n=6)
geomean 102.4µ 95.09µ -7.10%
Signed-off-by: Egon Elbre <egonelbre@gmail.com>
This commit is contained in:
+17
-17
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type Ops struct {
|
type Ops struct {
|
||||||
// version is incremented at each Reset.
|
// version is incremented at each Reset.
|
||||||
version int
|
version uint32
|
||||||
// data contains the serialized operations.
|
// data contains the serialized operations.
|
||||||
data []byte
|
data []byte
|
||||||
// refs hold external references for operations.
|
// refs hold external references for operations.
|
||||||
@@ -32,7 +32,7 @@ type Ops struct {
|
|||||||
stringRefs []string
|
stringRefs []string
|
||||||
// nextStateID is the id allocated for the next
|
// nextStateID is the id allocated for the next
|
||||||
// StateOp.
|
// StateOp.
|
||||||
nextStateID int
|
nextStateID uint32
|
||||||
// multipOp indicates a multi-op such as clip.Path is being added.
|
// multipOp indicates a multi-op such as clip.Path is being added.
|
||||||
multipOp bool
|
multipOp bool
|
||||||
|
|
||||||
@@ -91,23 +91,23 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type StackID struct {
|
type StackID struct {
|
||||||
id int
|
id uint32
|
||||||
prev int
|
prev uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateOp represents a saved operation snapshot to be restored
|
// StateOp represents a saved operation snapshot to be restored
|
||||||
// later.
|
// later.
|
||||||
type StateOp struct {
|
type StateOp struct {
|
||||||
id int
|
id uint32
|
||||||
macroID int
|
macroID uint32
|
||||||
ops *Ops
|
ops *Ops
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack tracks the integer identities of stack operations to ensure correct
|
// stack tracks the integer identities of stack operations to ensure correct
|
||||||
// pairing of their push and pop methods.
|
// pairing of their push and pop methods.
|
||||||
type stack struct {
|
type stack struct {
|
||||||
currentID int
|
currentID uint32
|
||||||
nextID int
|
nextID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type StackKind uint8
|
type StackKind uint8
|
||||||
@@ -266,11 +266,11 @@ func AddCall(o *Ops, callOps *Ops, pc PC, end PC) {
|
|||||||
bo.PutUint32(data[13:], uint32(end.refs))
|
bo.PutUint32(data[13:], uint32(end.refs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func PushOp(o *Ops, kind StackKind) (StackID, int) {
|
func PushOp(o *Ops, kind StackKind) (StackID, uint32) {
|
||||||
return o.stacks[kind].push(), o.macroStack.currentID
|
return o.stacks[kind].push(), o.macroStack.currentID
|
||||||
}
|
}
|
||||||
|
|
||||||
func PopOp(o *Ops, kind StackKind, sid StackID, macroID int) {
|
func PopOp(o *Ops, kind StackKind, sid StackID, macroID uint32) {
|
||||||
if o.macroStack.currentID != macroID {
|
if o.macroStack.currentID != macroID {
|
||||||
panic("stack push and pop must not cross macro boundary")
|
panic("stack push and pop must not cross macro boundary")
|
||||||
}
|
}
|
||||||
@@ -310,7 +310,7 @@ func Write3(o *Ops, n int, ref1, ref2, ref3 interface{}) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PCFor(o *Ops) PC {
|
func PCFor(o *Ops) PC {
|
||||||
return PC{data: len(o.data), refs: len(o.refs)}
|
return PC{data: uint32(len(o.data)), refs: uint32(len(o.refs))}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stack) push() StackID {
|
func (s *stack) push() StackID {
|
||||||
@@ -460,17 +460,17 @@ var opProps = [0x100]opProp{
|
|||||||
TypeActionInput: {Size: TypeActionInputLen, NumRefs: 0},
|
TypeActionInput: {Size: TypeActionInputLen, NumRefs: 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t OpType) props() (size, numRefs int) {
|
func (t OpType) props() (size, numRefs uint32) {
|
||||||
v := opProps[t]
|
v := opProps[t]
|
||||||
return int(v.Size), int(v.NumRefs)
|
return uint32(v.Size), uint32(v.NumRefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t OpType) Size() int {
|
func (t OpType) Size() uint32 {
|
||||||
return int(opProps[t].Size)
|
return uint32(opProps[t].Size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t OpType) NumRefs() int {
|
func (t OpType) NumRefs() uint32 {
|
||||||
return int(opProps[t].NumRefs)
|
return uint32(opProps[t].NumRefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t OpType) String() string {
|
func (t OpType) String() string {
|
||||||
|
|||||||
+13
-13
@@ -26,8 +26,8 @@ type EncodedOp struct {
|
|||||||
// Key is a unique key for a given op.
|
// Key is a unique key for a given op.
|
||||||
type Key struct {
|
type Key struct {
|
||||||
ops *Ops
|
ops *Ops
|
||||||
pc int
|
pc uint32
|
||||||
version int
|
version uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow of op.MacroOp.
|
// Shadow of op.MacroOp.
|
||||||
@@ -39,8 +39,8 @@ type macroOp struct {
|
|||||||
|
|
||||||
// PC is an instruction counter for an operation list.
|
// PC is an instruction counter for an operation list.
|
||||||
type PC struct {
|
type PC struct {
|
||||||
data int
|
data uint32
|
||||||
refs int
|
refs uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
type macro struct {
|
type macro struct {
|
||||||
@@ -128,7 +128,7 @@ func (r *Reader) Decode() (EncodedOp, bool) {
|
|||||||
if nrefs != 1 {
|
if nrefs != 1 {
|
||||||
panic("internal error: unexpected number of macro refs")
|
panic("internal error: unexpected number of macro refs")
|
||||||
}
|
}
|
||||||
deferData := Write1(&r.deferOps, n, refs[0])
|
deferData := Write1(&r.deferOps, int(n), refs[0])
|
||||||
copy(deferData, data)
|
copy(deferData, data)
|
||||||
r.pc.data += n
|
r.pc.data += n
|
||||||
r.pc.refs += nrefs
|
r.pc.refs += nrefs
|
||||||
@@ -154,8 +154,8 @@ func (r *Reader) Decode() (EncodedOp, bool) {
|
|||||||
r.pc = op.endpc
|
r.pc = op.endpc
|
||||||
} else {
|
} else {
|
||||||
// Treat an incomplete macro as containing all remaining ops.
|
// Treat an incomplete macro as containing all remaining ops.
|
||||||
r.pc.data = len(r.ops.data)
|
r.pc.data = uint32(len(r.ops.data))
|
||||||
r.pc.refs = len(r.ops.refs)
|
r.pc.refs = uint32(len(r.ops.refs))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -171,8 +171,8 @@ func (op *opMacroDef) decode(data []byte) {
|
|||||||
}
|
}
|
||||||
bo := binary.LittleEndian
|
bo := binary.LittleEndian
|
||||||
data = data[:TypeMacroLen]
|
data = data[:TypeMacroLen]
|
||||||
op.endpc.data = int(int32(bo.Uint32(data[1:])))
|
op.endpc.data = bo.Uint32(data[1:])
|
||||||
op.endpc.refs = int(int32(bo.Uint32(data[5:])))
|
op.endpc.refs = bo.Uint32(data[5:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *macroOp) decode(data []byte, refs []interface{}) {
|
func (m *macroOp) decode(data []byte, refs []interface{}) {
|
||||||
@@ -183,8 +183,8 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
|
|||||||
data = data[:TypeCallLen]
|
data = data[:TypeCallLen]
|
||||||
|
|
||||||
m.ops = refs[0].(*Ops)
|
m.ops = refs[0].(*Ops)
|
||||||
m.start.data = int(int32(bo.Uint32(data[1:])))
|
m.start.data = bo.Uint32(data[1:])
|
||||||
m.start.refs = int(int32(bo.Uint32(data[5:])))
|
m.start.refs = bo.Uint32(data[5:])
|
||||||
m.end.data = int(int32(bo.Uint32(data[9:])))
|
m.end.data = bo.Uint32(data[9:])
|
||||||
m.end.refs = int(int32(bo.Uint32(data[13:])))
|
m.end.refs = bo.Uint32(data[13:])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ type PassOp struct {
|
|||||||
type PassStack struct {
|
type PassStack struct {
|
||||||
ops *ops.Ops
|
ops *ops.Ops
|
||||||
id ops.StackID
|
id ops.StackID
|
||||||
macroID int
|
macroID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputOp declares an input handler ready for pointer
|
// InputOp declares an input handler ready for pointer
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ type Op struct {
|
|||||||
type Stack struct {
|
type Stack struct {
|
||||||
ops *ops.Ops
|
ops *ops.Ops
|
||||||
id ops.StackID
|
id ops.StackID
|
||||||
macroID int
|
macroID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
var pathSeed maphash.Seed
|
var pathSeed maphash.Seed
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ type TransformOp struct {
|
|||||||
// TransformStack represents a TransformOp pushed on the transformation stack.
|
// TransformStack represents a TransformOp pushed on the transformation stack.
|
||||||
type TransformStack struct {
|
type TransformStack struct {
|
||||||
id ops.StackID
|
id ops.StackID
|
||||||
macroID int
|
macroID uint32
|
||||||
ops *ops.Ops
|
ops *ops.Ops
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ type PaintOp struct {
|
|||||||
// until Pop is called.
|
// until Pop is called.
|
||||||
type OpacityStack struct {
|
type OpacityStack struct {
|
||||||
id ops.StackID
|
id ops.StackID
|
||||||
macroID int
|
macroID uint32
|
||||||
ops *ops.Ops
|
ops *ops.Ops
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user