Skip to content

Commit 220852f

Browse files
committed
Add whitebox test for query plan reordering
1 parent c89c9ee commit 220852f

File tree

6 files changed

+143
-18
lines changed

6 files changed

+143
-18
lines changed

flecs.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60660,7 +60660,7 @@ char* ecs_rule_str_w_profile(
6066060660

6066160661
#ifdef FLECS_LOG
6066260662
char *str = ecs_strbuf_get(&buf);
60663-
flecs_colorize_buf(str, true, &buf);
60663+
flecs_colorize_buf(str, ecs_os_api.flags_ & EcsOsApiLogWithColors, &buf);
6066460664
ecs_os_free(str);
6066560665
#endif
6066660666
return ecs_strbuf_get(&buf);
@@ -62462,6 +62462,24 @@ int flecs_rule_compile_term(
6246262462
return -1;
6246362463
}
6246462464

62465+
static
62466+
bool flecs_rule_var_is_unknown(
62467+
ecs_rule_t *rule,
62468+
ecs_var_id_t var_id,
62469+
ecs_rule_compile_ctx_t *ctx)
62470+
{
62471+
ecs_rule_var_t *vars = rule->vars;
62472+
if (ctx->written & (1ull << var_id)) {
62473+
return false;
62474+
} else {
62475+
ecs_var_id_t table_var = vars[var_id].table_id;
62476+
if (table_var != EcsVarNone) {
62477+
return flecs_rule_var_is_unknown(rule, table_var, ctx);
62478+
}
62479+
}
62480+
return true;
62481+
}
62482+
6246562483
static
6246662484
bool flecs_rule_term_is_unknown(
6246762485
ecs_rule_t *rule,
@@ -62473,7 +62491,7 @@ bool flecs_rule_term_is_unknown(
6247362491
&dummy.first, EcsRuleFirst, EcsVarEntity, ctx, false);
6247462492
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->second,
6247562493
&dummy.second, EcsRuleSecond, EcsVarEntity, ctx, false);
62476-
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->second,
62494+
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->src,
6247762495
&dummy.src, EcsRuleSrc, EcsVarAny, ctx, false);
6247862496

6247962497
bool has_vars = dummy.flags &
@@ -62487,17 +62505,17 @@ bool flecs_rule_term_is_unknown(
6248762505
}
6248862506

6248962507
if (dummy.flags & (EcsRuleIsVar << EcsRuleFirst)) {
62490-
if (ctx->written & (1 << dummy.first.var)) {
62508+
if (!flecs_rule_var_is_unknown(rule, dummy.first.var, ctx)) {
6249162509
return false;
6249262510
}
6249362511
}
6249462512
if (dummy.flags & (EcsRuleIsVar << EcsRuleSecond)) {
62495-
if (ctx->written & (1 << dummy.second.var)) {
62513+
if (!flecs_rule_var_is_unknown(rule, dummy.second.var, ctx)) {
6249662514
return false;
6249762515
}
6249862516
}
6249962517
if (dummy.flags & (EcsRuleIsVar << EcsRuleSrc)) {
62500-
if (ctx->written & (1 << dummy.src.var)) {
62518+
if (!flecs_rule_var_is_unknown(rule, dummy.src.var, ctx)) {
6250162519
return false;
6250262520
}
6250362521
}
@@ -62518,7 +62536,7 @@ int32_t flecs_rule_term_next_known(
6251862536

6251962537
for (i = offset; i < count; i ++) {
6252062538
ecs_term_t *term = &terms[i];
62521-
if (compiled & (1 << i)) {
62539+
if (compiled & (1ull << i)) {
6252262540
continue;
6252362541
}
6252462542

@@ -62593,7 +62611,7 @@ int flecs_rule_compile(
6259362611
ecs_term_t *term = &terms[i];
6259462612
int32_t compile = i;
6259562613

62596-
if (compiled & (1 << i)) {
62614+
if (compiled & (1ull << i)) {
6259762615
continue; /* Already compiled */
6259862616
}
6259962617

@@ -62623,7 +62641,7 @@ int flecs_rule_compile(
6262362641
return -1;
6262462642
}
6262562643

62626-
compiled |= (1 << compile);
62644+
compiled |= (1ull << compile);
6262762645
}
6262862646

6262962647
ecs_var_id_t this_id = flecs_rule_find_var_id(rule, "This", EcsVarEntity);

src/addons/rules/api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ char* ecs_rule_str_w_profile(
295295

296296
#ifdef FLECS_LOG
297297
char *str = ecs_strbuf_get(&buf);
298-
flecs_colorize_buf(str, true, &buf);
298+
flecs_colorize_buf(str, ecs_os_api.flags_ & EcsOsApiLogWithColors, &buf);
299299
ecs_os_free(str);
300300
#endif
301301
return ecs_strbuf_get(&buf);

src/addons/rules/compile.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,24 @@ int flecs_rule_compile_term(
16841684
return -1;
16851685
}
16861686

1687+
static
1688+
bool flecs_rule_var_is_unknown(
1689+
ecs_rule_t *rule,
1690+
ecs_var_id_t var_id,
1691+
ecs_rule_compile_ctx_t *ctx)
1692+
{
1693+
ecs_rule_var_t *vars = rule->vars;
1694+
if (ctx->written & (1ull << var_id)) {
1695+
return false;
1696+
} else {
1697+
ecs_var_id_t table_var = vars[var_id].table_id;
1698+
if (table_var != EcsVarNone) {
1699+
return flecs_rule_var_is_unknown(rule, table_var, ctx);
1700+
}
1701+
}
1702+
return true;
1703+
}
1704+
16871705
static
16881706
bool flecs_rule_term_is_unknown(
16891707
ecs_rule_t *rule,
@@ -1695,7 +1713,7 @@ bool flecs_rule_term_is_unknown(
16951713
&dummy.first, EcsRuleFirst, EcsVarEntity, ctx, false);
16961714
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->second,
16971715
&dummy.second, EcsRuleSecond, EcsVarEntity, ctx, false);
1698-
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->second,
1716+
flecs_rule_compile_term_id(NULL, rule, &dummy, &term->src,
16991717
&dummy.src, EcsRuleSrc, EcsVarAny, ctx, false);
17001718

17011719
bool has_vars = dummy.flags &
@@ -1709,17 +1727,17 @@ bool flecs_rule_term_is_unknown(
17091727
}
17101728

17111729
if (dummy.flags & (EcsRuleIsVar << EcsRuleFirst)) {
1712-
if (ctx->written & (1 << dummy.first.var)) {
1730+
if (!flecs_rule_var_is_unknown(rule, dummy.first.var, ctx)) {
17131731
return false;
17141732
}
17151733
}
17161734
if (dummy.flags & (EcsRuleIsVar << EcsRuleSecond)) {
1717-
if (ctx->written & (1 << dummy.second.var)) {
1735+
if (!flecs_rule_var_is_unknown(rule, dummy.second.var, ctx)) {
17181736
return false;
17191737
}
17201738
}
17211739
if (dummy.flags & (EcsRuleIsVar << EcsRuleSrc)) {
1722-
if (ctx->written & (1 << dummy.src.var)) {
1740+
if (!flecs_rule_var_is_unknown(rule, dummy.src.var, ctx)) {
17231741
return false;
17241742
}
17251743
}
@@ -1740,7 +1758,7 @@ int32_t flecs_rule_term_next_known(
17401758

17411759
for (i = offset; i < count; i ++) {
17421760
ecs_term_t *term = &terms[i];
1743-
if (compiled & (1 << i)) {
1761+
if (compiled & (1ull << i)) {
17441762
continue;
17451763
}
17461764

@@ -1815,7 +1833,7 @@ int flecs_rule_compile(
18151833
ecs_term_t *term = &terms[i];
18161834
int32_t compile = i;
18171835

1818-
if (compiled & (1 << i)) {
1836+
if (compiled & (1ull << i)) {
18191837
continue; /* Already compiled */
18201838
}
18211839

@@ -1845,7 +1863,7 @@ int flecs_rule_compile(
18451863
return -1;
18461864
}
18471865

1848-
compiled |= (1 << compile);
1866+
compiled |= (1ull << compile);
18491867
}
18501868

18511869
ecs_var_id_t this_id = flecs_rule_find_var_id(rule, "This", EcsVarEntity);

test/addons/project.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,9 @@
795795
"unknown_before_known_after_or",
796796
"unknown_before_known_after_not",
797797
"unknown_before_known_after_optional",
798-
"unknown_before_known_after_scope"
798+
"unknown_before_known_after_scope",
799+
"reordered_plan_1",
800+
"reordered_plan_2"
799801
]
800802
}, {
801803
"id": "RulesVariables",

test/addons/src/RulesBasic.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6022,6 +6022,8 @@ void RulesBasic_unknown_before_known(void) {
60226022
test_uint(c, ecs_iter_get_var(&it, c_var));
60236023
test_uint(gc, ecs_iter_get_var(&it, gc_var));
60246024
test_assert(!ecs_rule_next(&it));
6025+
6026+
ecs_rule_fini(r);
60256027

60266028
ecs_fini(world);
60276029
}
@@ -6072,6 +6074,8 @@ void RulesBasic_unknown_before_known_after_or(void) {
60726074
test_uint(gc2, ecs_iter_get_var(&it, gc_var));
60736075
test_assert(!ecs_rule_next(&it));
60746076

6077+
ecs_rule_fini(r);
6078+
60756079
ecs_fini(world);
60766080
}
60776081

@@ -6109,6 +6113,8 @@ void RulesBasic_unknown_before_known_after_not(void) {
61096113
test_uint(c, ecs_iter_get_var(&it, c_var));
61106114
test_uint(gc1, ecs_iter_get_var(&it, gc_var));
61116115
test_assert(!ecs_rule_next(&it));
6116+
6117+
ecs_rule_fini(r);
61126118

61136119
ecs_fini(world);
61146120
}
@@ -6159,6 +6165,8 @@ void RulesBasic_unknown_before_known_after_optional(void) {
61596165
test_uint(c, ecs_iter_get_var(&it, c_var));
61606166
test_uint(gc2, ecs_iter_get_var(&it, gc_var));
61616167
test_assert(!ecs_rule_next(&it));
6168+
6169+
ecs_rule_fini(r);
61626170

61636171
ecs_fini(world);
61646172
}
@@ -6197,6 +6205,75 @@ void RulesBasic_unknown_before_known_after_scope(void) {
61976205
test_uint(c, ecs_iter_get_var(&it, c_var));
61986206
test_uint(gc1, ecs_iter_get_var(&it, gc_var));
61996207
test_assert(!ecs_rule_next(&it));
6208+
6209+
ecs_rule_fini(r);
62006210

62016211
ecs_fini(world);
62026212
}
6213+
6214+
void RulesBasic_reordered_plan_1(void) {
6215+
ecs_world_t *world = ecs_mini();
6216+
6217+
ECS_TAG(world, Foo);
6218+
ECS_TAG(world, Bar);
6219+
6220+
ecs_rule_t *r = ecs_rule(world, {
6221+
.expr = "Foo, ChildOf($this, $p, $gp, $ggp), Bar($ggp)"
6222+
});
6223+
6224+
ecs_log_enable_colors(false);
6225+
6226+
const char *expect =
6227+
HEAD " 0. [-1, 1] setids "
6228+
LINE " 1. [ 0, 2] selfup $[this] (Foo)"
6229+
LINE " 2. [ 1, 3] and $[this] (ChildOf, $p)"
6230+
LINE " 3. [ 2, 4] and $p (ChildOf, $gp)"
6231+
LINE " 4. [ 3, 5] and $gp (ChildOf, $ggp)"
6232+
LINE " 5. [ 4, 6] selfup $ggp (Bar)"
6233+
LINE " 6. [ 5, 7] setvars "
6234+
LINE " 7. [ 6, 8] yield "
6235+
LINE "";
6236+
char *plan = ecs_rule_str(r);
6237+
6238+
test_str(expect, plan);
6239+
ecs_os_free(plan);
6240+
6241+
ecs_rule_fini(r);
6242+
6243+
ecs_fini(world);
6244+
}
6245+
6246+
void RulesBasic_reordered_plan_2(void) {
6247+
ecs_world_t *world = ecs_mini();
6248+
6249+
ECS_TAG(world, Foo);
6250+
ECS_TAG(world, Bar);
6251+
6252+
ecs_rule_t *r = ecs_rule(world, {
6253+
.expr = "Foo($ggp), ChildOf($this, $p, $gp, $ggp), Bar($this)"
6254+
});
6255+
6256+
ecs_log_enable_colors(false);
6257+
6258+
const char *expect =
6259+
HEAD " 0. [-1, 1] setids "
6260+
LINE " 1. [ 0, 2] selfup $[ggp] (Foo)"
6261+
LINE " 2. [ 1, 3] each $ggp ($[ggp])"
6262+
LINE " 3. [ 2, 4] and $[gp] (ChildOf, $ggp)"
6263+
LINE " 4. [ 3, 5] each $gp ($[gp])"
6264+
LINE " 5. [ 4, 6] and $[p] (ChildOf, $gp)"
6265+
LINE " 6. [ 5, 7] each $p ($[p])"
6266+
LINE " 7. [ 6, 8] and $[this] (ChildOf, $p)"
6267+
LINE " 8. [ 7, 9] selfup $[this] (Bar)"
6268+
LINE " 9. [ 8, 10] setvars "
6269+
LINE "10. [ 9, 11] yield "
6270+
LINE "";
6271+
char *plan = ecs_rule_str(r);
6272+
6273+
test_str(expect, plan);
6274+
ecs_os_free(plan);
6275+
6276+
ecs_rule_fini(r);
6277+
6278+
ecs_fini(world);
6279+
}

test/addons/src/main.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,8 @@ void RulesBasic_unknown_before_known_after_or(void);
781781
void RulesBasic_unknown_before_known_after_not(void);
782782
void RulesBasic_unknown_before_known_after_optional(void);
783783
void RulesBasic_unknown_before_known_after_scope(void);
784+
void RulesBasic_reordered_plan_1(void);
785+
void RulesBasic_reordered_plan_2(void);
784786

785787
// Testsuite 'RulesVariables'
786788
void RulesVariables_1_ent_src_w_var(void);
@@ -4820,6 +4822,14 @@ bake_test_case RulesBasic_testcases[] = {
48204822
{
48214823
"unknown_before_known_after_scope",
48224824
RulesBasic_unknown_before_known_after_scope
4825+
},
4826+
{
4827+
"reordered_plan_1",
4828+
RulesBasic_reordered_plan_1
4829+
},
4830+
{
4831+
"reordered_plan_2",
4832+
RulesBasic_reordered_plan_2
48234833
}
48244834
};
48254835

@@ -8581,7 +8591,7 @@ static bake_test_suite suites[] = {
85818591
"RulesBasic",
85828592
NULL,
85838593
NULL,
8584-
130,
8594+
132,
85858595
RulesBasic_testcases
85868596
},
85878597
{

0 commit comments

Comments
 (0)