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
+13 -13
View File
@@ -26,8 +26,8 @@ type EncodedOp struct {
// Key is a unique key for a given op.
type Key struct {
ops *Ops
pc int
version int
pc uint32
version uint32
}
// Shadow of op.MacroOp.
@@ -39,8 +39,8 @@ type macroOp struct {
// PC is an instruction counter for an operation list.
type PC struct {
data int
refs int
data uint32
refs uint32
}
type macro struct {
@@ -128,7 +128,7 @@ func (r *Reader) Decode() (EncodedOp, bool) {
if nrefs != 1 {
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)
r.pc.data += n
r.pc.refs += nrefs
@@ -154,8 +154,8 @@ func (r *Reader) Decode() (EncodedOp, bool) {
r.pc = op.endpc
} else {
// Treat an incomplete macro as containing all remaining ops.
r.pc.data = len(r.ops.data)
r.pc.refs = len(r.ops.refs)
r.pc.data = uint32(len(r.ops.data))
r.pc.refs = uint32(len(r.ops.refs))
}
continue
}
@@ -171,8 +171,8 @@ func (op *opMacroDef) decode(data []byte) {
}
bo := binary.LittleEndian
data = data[:TypeMacroLen]
op.endpc.data = int(int32(bo.Uint32(data[1:])))
op.endpc.refs = int(int32(bo.Uint32(data[5:])))
op.endpc.data = bo.Uint32(data[1:])
op.endpc.refs = bo.Uint32(data[5:])
}
func (m *macroOp) decode(data []byte, refs []interface{}) {
@@ -183,8 +183,8 @@ func (m *macroOp) decode(data []byte, refs []interface{}) {
data = data[:TypeCallLen]
m.ops = refs[0].(*Ops)
m.start.data = int(int32(bo.Uint32(data[1:])))
m.start.refs = int(int32(bo.Uint32(data[5:])))
m.end.data = int(int32(bo.Uint32(data[9:])))
m.end.refs = int(int32(bo.Uint32(data[13:])))
m.start.data = bo.Uint32(data[1:])
m.start.refs = bo.Uint32(data[5:])
m.end.data = bo.Uint32(data[9:])
m.end.refs = bo.Uint32(data[13:])
}