Skip to content

Commit 1a2d2e7

Browse files
committed
internal/core/adt: use pointers for snapshot and result in nodeContext
These fields are only used in evalv2's disjunction algorithm, so they are entirely unused in evalv3, the current default. Given how often nodeContext structs are allocated, this helps reduce the memory usage of the new allocator. │ old │ new │ │ sec/op │ sec/op vs base │ VetAutomata 724.0m ± 13% 674.2m ± 9% -6.88% (p=0.050 n=8) │ old │ new │ │ B/op │ B/op vs base │ VetAutomata 700.7Mi ± 0% 631.9Mi ± 0% -9.81% (p=0.000 n=8) │ old │ new │ │ allocs/op │ allocs/op vs base │ VetAutomata 4.478M ± 0% 4.478M ± 0% ~ (p=0.316 n=8) Performance on evalv2 is unaffected; adt.TestEvalV2 still takes 3.9s, and Unity on evalv2 shows noise in the 0-5% range. Unity on evalv3 shows improvements between 0 and 10% for wall times as well as for Go.AllocBytes counters. Updates #3334. Signed-off-by: Daniel Martí <[email protected]> Change-Id: Idab308cb88980b9618c9c4164fae41b870442bd9 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1217121 TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 7777230 commit 1a2d2e7

File tree

2 files changed

+18
-16
lines changed

2 files changed

+18
-16
lines changed

internal/core/adt/disjunct.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ func (n *nodeContext) expandDisjuncts(
166166
// save nodeContext.
167167

168168
if recursive || len(n.disjunctions) > 0 {
169-
n.snapshot = clone(*n.node)
169+
n.snapshot = clone(n.node)
170170
} else {
171-
n.snapshot = *n.node
171+
n.snapshot = n.node
172172
}
173173

174174
defaultOffset := len(n.usedDefault)
@@ -206,8 +206,9 @@ func (n *nodeContext) expandDisjuncts(
206206

207207
if recursive {
208208
*n = m
209-
n.result = *n.node // XXX: n.result = snapshotVertex(n.node)?
210-
n.node = &n.result
209+
nn := *n.node
210+
n.result = &nn // XXX: n.result = snapshotVertex(n.node)?
211+
n.node = n.result
211212
n.disjuncts = append(n.disjuncts, n)
212213
}
213214
if n.node.BaseValue == nil {
@@ -246,7 +247,7 @@ func (n *nodeContext) expandDisjuncts(
246247
case d.expr != nil:
247248
for _, v := range d.expr.Values {
248249
cn := dn.clone()
249-
*cn.node = clone(dn.snapshot)
250+
*cn.node = *clone(dn.snapshot)
250251
cn.node.state = cn
251252

252253
c := MakeConjunct(d.env, v.Val, d.cloneID)
@@ -271,7 +272,7 @@ func (n *nodeContext) expandDisjuncts(
271272
case d.value != nil:
272273
for i, v := range d.value.Values {
273274
cn := dn.clone()
274-
*cn.node = clone(dn.snapshot)
275+
*cn.node = *clone(dn.snapshot)
275276
cn.node.state = cn
276277

277278
cn.addValueConjunct(d.env, v, d.cloneID)
@@ -425,7 +426,7 @@ func (n *nodeContext) expandDisjuncts(
425426
if last {
426427
flags |= IgnoreOptional
427428
}
428-
if Equal(n.ctx, &v.result, &d.result, flags) {
429+
if Equal(n.ctx, v.result, d.result, flags) {
429430
m := maybeDefault
430431
for _, u := range d.usedDefault {
431432
m = combineDefault(m, u.nestedMode)
@@ -497,7 +498,9 @@ func mode(hasDefault, marked bool) defaultMode {
497498
// and can be used as is, or Structs is assumed to not yet be computed at the
498499
// time that a clone is needed and must be nil. Conjuncts no longer needed and
499500
// can become nil. All other fields can be copied shallowly.
500-
func clone(v Vertex) Vertex {
501+
func clone(v *Vertex) *Vertex {
502+
v2 := *v
503+
v = &v2
501504
v.state = nil
502505
if a := v.Arcs; len(a) > 0 {
503506
v.Arcs = make([]*Vertex, len(a))
@@ -515,7 +518,7 @@ func clone(v Vertex) Vertex {
515518
a := *arc
516519
a.state = arc.state.clone()
517520
a.state.node = &a
518-
a.state.snapshot = clone(a)
521+
a.state.snapshot = clone(arc)
519522
v.Arcs[i] = &a
520523
}
521524
}

internal/core/adt/eval.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func (c *OpContext) unify(v *Vertex, flags combinedFlags) {
308308
switch len(n.disjuncts) {
309309
case 0:
310310
case 1:
311-
x := n.disjuncts[0].result
311+
x := *n.disjuncts[0].result
312312
x.state = nil
313313
x.cyclicReferences = n.node.cyclicReferences
314314
*v = x
@@ -973,21 +973,20 @@ func (n *nodeContext) createDisjunct() *Disjunction {
973973
p := 0
974974
hasDefaults := false
975975
for i, x := range n.disjuncts {
976-
v := new(Vertex)
977-
*v = x.result
976+
v := *x.result
978977
v.state = nil
979978
switch x.defaultMode {
980979
case isDefault:
981980
a[i] = a[p]
982-
a[p] = v
981+
a[p] = &v
983982
p++
984983
hasDefaults = true
985984

986985
case notDefault:
987986
hasDefaults = true
988987
fallthrough
989988
case maybeDefault:
990-
a[i] = v
989+
a[i] = &v
991990
}
992991
}
993992
// TODO: disambiguate based on concrete values.
@@ -1102,11 +1101,11 @@ type nodeContext struct {
11021101
hasDisjunction bool
11031102

11041103
// snapshot holds the last value of the vertex before calling postDisjunct.
1105-
snapshot Vertex
1104+
snapshot *Vertex
11061105

11071106
// Result holds the last evaluated value of the vertex after calling
11081107
// postDisjunct.
1109-
result Vertex
1108+
result *Vertex
11101109
}
11111110

11121111
type conjunct struct {

0 commit comments

Comments
 (0)