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:
Egon Elbre
2023-10-23 19:51:10 +03:00
committed by Chris Waldon
parent d078bf0ed7
commit 49296bd0ca
6 changed files with 34 additions and 34 deletions
+17 -17
View File
@@ -14,7 +14,7 @@ import (
type Ops struct {
// version is incremented at each Reset.
version int
version uint32
// data contains the serialized operations.
data []byte
// refs hold external references for operations.
@@ -32,7 +32,7 @@ type Ops struct {
stringRefs []string
// nextStateID is the id allocated for the next
// StateOp.
nextStateID int
nextStateID uint32
// multipOp indicates a multi-op such as clip.Path is being added.
multipOp bool
@@ -91,23 +91,23 @@ const (
)
type StackID struct {
id int
prev int
id uint32
prev uint32
}
// StateOp represents a saved operation snapshot to be restored
// later.
type StateOp struct {
id int
macroID int
id uint32
macroID uint32
ops *Ops
}
// stack tracks the integer identities of stack operations to ensure correct
// pairing of their push and pop methods.
type stack struct {
currentID int
nextID int
currentID uint32
nextID uint32
}
type StackKind uint8
@@ -266,11 +266,11 @@ func AddCall(o *Ops, callOps *Ops, pc PC, end PC) {
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
}
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 {
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 {
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 {
@@ -460,17 +460,17 @@ var opProps = [0x100]opProp{
TypeActionInput: {Size: TypeActionInputLen, NumRefs: 0},
}
func (t OpType) props() (size, numRefs int) {
func (t OpType) props() (size, numRefs uint32) {
v := opProps[t]
return int(v.Size), int(v.NumRefs)
return uint32(v.Size), uint32(v.NumRefs)
}
func (t OpType) Size() int {
return int(opProps[t].Size)
func (t OpType) Size() uint32 {
return uint32(opProps[t].Size)
}
func (t OpType) NumRefs() int {
return int(opProps[t].NumRefs)
func (t OpType) NumRefs() uint32 {
return uint32(opProps[t].NumRefs)
}
func (t OpType) String() string {