Skip to content

Commit

Permalink
internal/core/adt: introduce structure sharing
Browse files Browse the repository at this point in the history
Structure sharing allows the same node to be used in
multiple positions if the evaluation is known to be the
same. This is particularly the case if a field has a single
reference to another field:

    a: b // reference to b can be used as is
	b: 2

Structure sharing has the potential to greatly reduce the
time complexity of evaluation in certain conditions. See,
for instance, benchmarks/share.txtar, where a simplified
version of the Billion Laughs attack vector is evaluated
in O(n) time, where n is the number of input nodes.

In practice, there are many cases in CUE where repeated
computation can be avoided, and structure sharing has
been seen as one of the big wins to improve performance.

Note that although structure sharing is purely meant as
a performance improvement, it also alters computation
order and it may cut evaluation short before tricky cycle
situations are encountered. So it may fix some bugs as
a side effect.

Note that structure sharing may also interact with other
performance improvements, resulting in compounding
reductions.

Note that although this change also largely makes
structure sharing work with the API, it is mostly
intended to make it work with the core evaluator only.
We will still need to add thorough tests and
evaluation of the API w.r.t. structure sharing.
This is generally true for the new evaluator, so we
plan to do this towards the end of its development.

Issue #2884
Issue #2854

Signed-off-by: Marcel van Lohuizen <[email protected]>
Change-Id: Ic1c888e9567242d6779093fcb391d6e001881f60
  • Loading branch information
mpvl committed Apr 17, 2024
1 parent 80d681b commit d419d2a
Show file tree
Hide file tree
Showing 32 changed files with 1,682 additions and 3,715 deletions.
44 changes: 37 additions & 7 deletions cue/testdata/benchmarks/chain.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -2015,16 +2015,16 @@ f1000: f999
f999: 〈0;f998〉
f1000: 〈0;f999〉
}
-- out/eval/stats --
Leaks: 0
Freed: 1001
Reused: 999
Allocs: 2
-- out/evalalpha/stats --
Leaks: 1001
Freed: 0
Reused: 0
Allocs: 1001
Retain: 0

Unifications: 1001
Conjuncts: 500501
Disjuncts: 1001
Conjuncts: 2001
Disjuncts: 0
-- out/eval --
(struct){
f1: (string){ string }
Expand Down Expand Up @@ -3028,3 +3028,33 @@ Disjuncts: 1001
f999: (string){ string }
f1000: (string){ string }
}
-- diff/-out/evalalpha/stats<==>+out/eval/stats --
diff old new
--- old
+++ new
@@ -1,9 +1,9 @@
-Leaks: 0
-Freed: 1001
-Reused: 999
-Allocs: 2
+Leaks: 1001
+Freed: 0
+Reused: 0
+Allocs: 1001
Retain: 0

Unifications: 1001
-Conjuncts: 500501
-Disjuncts: 1001
+Conjuncts: 2001
+Disjuncts: 0
-- out/eval/stats --
Leaks: 0
Freed: 1001
Reused: 999
Allocs: 2
Retain: 0

Unifications: 1001
Conjuncts: 500501
Disjuncts: 1001
28 changes: 14 additions & 14 deletions cue/testdata/benchmarks/issue1684.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ out: #secrets & {
ONE: TWO: THREE: $secret: _id: "123"
}
-- out/evalalpha/stats --
Leaks: 2115
Freed: 539
Reused: 539
Allocs: 2115
Leaks: 1896
Freed: 461
Reused: 461
Allocs: 1896
Retain: 0

Unifications: 614
Conjuncts: 5842
Disjuncts: 846
Unifications: 533
Conjuncts: 5254
Disjuncts: 720
-- out/eval --
(struct){
#Secret: (#struct){
Expand Down Expand Up @@ -85,18 +85,18 @@ diff old new
-Freed: 1064043
-Reused: 1063992
-Allocs: 51
+Leaks: 2115
+Freed: 539
+Reused: 539
+Allocs: 2115
+Leaks: 1896
+Freed: 461
+Reused: 461
+Allocs: 1896
Retain: 0

-Unifications: 791999
-Conjuncts: 2479541
-Disjuncts: 1064043
+Unifications: 614
+Conjuncts: 5842
+Disjuncts: 846
+Unifications: 533
+Conjuncts: 5254
+Disjuncts: 720
-- out/eval/stats --
Leaks: 0
Freed: 1064043
Expand Down
401 changes: 401 additions & 0 deletions cue/testdata/benchmarks/issue2176.txtar

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions cue/testdata/benchmarks/listdedup.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ C: #steps: #Script & {mount: [B]}

#ref: {a: 1} | {b: 2}
-- out/evalalpha/stats --
Leaks: 12448
Freed: 1388
Reused: 1387
Allocs: 12449
Leaks: 163
Freed: 10
Reused: 10
Allocs: 163
Retain: 0

Unifications: 2716
Conjuncts: 48270
Disjuncts: 3272
Unifications: 53
Conjuncts: 431
Disjuncts: 40
-- out/eval --
(struct){
A: (#struct){ |((#struct){
Expand Down Expand Up @@ -216,18 +216,18 @@ diff old new
-Reused: 24051
-Allocs: 45
-Retain: 1
+Leaks: 12448
+Freed: 1388
+Reused: 1387
+Allocs: 12449
+Leaks: 163
+Freed: 10
+Reused: 10
+Allocs: 163
+Retain: 0

-Unifications: 18724
-Conjuncts: 100730
-Disjuncts: 24097
+Unifications: 2716
+Conjuncts: 48270
+Disjuncts: 3272
+Unifications: 53
+Conjuncts: 431
+Disjuncts: 40
-- out/eval/stats --
Leaks: 0
Freed: 24096
Expand Down
Loading

0 comments on commit d419d2a

Please sign in to comment.