@@ -27,7 +27,8 @@ pub type RuleId = usize;
27
27
28
28
#[ derive( Default , Clone , Debug ) ]
29
29
pub struct OptimizerContext {
30
- pub budget_used : bool ,
30
+ pub budget_used_logical : bool ,
31
+ pub budget_used_all : bool ,
31
32
pub rules_applied : usize ,
32
33
}
33
34
@@ -42,13 +43,20 @@ pub struct OptimizerProperties {
42
43
pub disable_pruning : bool ,
43
44
}
44
45
46
+ #[ derive( Debug , Default ) ]
47
+ pub struct CascadesStats {
48
+ pub rule_match_count : HashMap < usize , usize > ,
49
+ pub rule_total_bindings : HashMap < usize , usize > ,
50
+ }
51
+
45
52
pub struct CascadesOptimizer < T : NodeType , M : Memo < T > = NaiveMemo < T > > {
46
53
memo : M ,
47
54
pub ( super ) tasks : VecDeque < Box < dyn Task < T , M > > > ,
48
55
explored_group : HashSet < GroupId > ,
49
56
explored_expr : HashSet < ExprId > ,
50
57
fired_rules : HashMap < ExprId , HashSet < RuleId > > ,
51
58
rules : Arc < [ Arc < dyn Rule < T , Self > > ] > ,
59
+ pub stats : CascadesStats ,
52
60
disabled_rules : HashSet < usize > ,
53
61
cost : Arc < dyn CostModel < T , M > > ,
54
62
property_builders : Arc < [ Box < dyn LogicalPropertyBuilderAny < T > > ] > ,
@@ -123,6 +131,7 @@ impl<T: NodeType> CascadesOptimizer<T, NaiveMemo<T>> {
123
131
property_builders,
124
132
prop,
125
133
disabled_rules : HashSet :: new ( ) ,
134
+ stats : CascadesStats :: default ( ) ,
126
135
}
127
136
}
128
137
@@ -250,39 +259,63 @@ impl<T: NodeType, M: Memo<T>> CascadesOptimizer<T, M> {
250
259
self . tasks
251
260
. push_back ( Box :: new ( OptimizeGroupTask :: new ( group_id, None ) ) ) ;
252
261
// get the task from the stack
253
- self . ctx . budget_used = false ;
262
+ self . ctx . budget_used_logical = false ;
263
+ self . ctx . budget_used_all = false ;
254
264
let plan_space_begin = self . memo . estimated_plan_space ( ) ;
255
265
let mut iter = 0 ;
256
266
while let Some ( task) = self . tasks . pop_back ( ) {
257
267
let new_tasks = task. execute ( self ) ?;
258
268
self . tasks . extend ( new_tasks) ;
259
269
iter += 1 ;
260
- if !self . ctx . budget_used {
270
+ if !self . ctx . budget_used_logical {
261
271
let plan_space = self . memo . estimated_plan_space ( ) ;
262
272
if let Some ( partial_explore_space) = self . prop . partial_explore_space {
263
273
if plan_space - plan_space_begin > partial_explore_space {
264
274
println ! (
265
275
"plan space size budget used, not applying logical rules any more. current plan space: {}" ,
266
276
plan_space
267
277
) ;
268
- self . ctx . budget_used = true ;
278
+ self . ctx . budget_used_logical = true ;
269
279
if self . prop . panic_on_budget {
270
280
panic ! ( "plan space size budget used" ) ;
271
281
}
272
282
}
273
- } else if let Some ( partial_explore_iter) = self . prop . partial_explore_iter {
283
+ }
284
+ }
285
+ if !self . ctx . budget_used_all {
286
+ if let Some ( partial_explore_iter) = self . prop . partial_explore_iter {
274
287
if iter >= partial_explore_iter {
275
288
println ! (
276
- "plan explore iter budget used, not applying logical rules any more. current plan space : {}" ,
277
- plan_space
289
+ "plan explore iter budget used, not applying physical/ logical rules any more if there's no winner . current iter : {}" ,
290
+ iter
278
291
) ;
279
- self . ctx . budget_used = true ;
292
+ self . ctx . budget_used_all = true ;
280
293
if self . prop . panic_on_budget {
281
294
panic ! ( "plan space size budget used" ) ;
282
295
}
283
296
}
284
297
}
285
298
}
299
+ if iter > 100000 && iter % 10000 == 0 {
300
+ println ! ( "iter={}" , iter) ;
301
+ println ! ( "plan_space={}" , self . memo. estimated_plan_space( ) ) ;
302
+ for ( id, rule) in self . rules . iter ( ) . enumerate ( ) {
303
+ println ! (
304
+ "{}: matched={}, bindings={}" ,
305
+ rule. name( ) ,
306
+ self . stats
307
+ . rule_match_count
308
+ . get( & id)
309
+ . copied( )
310
+ . unwrap_or_default( ) ,
311
+ self . stats
312
+ . rule_total_bindings
313
+ . get( & id)
314
+ . copied( )
315
+ . unwrap_or_default( )
316
+ ) ;
317
+ }
318
+ }
286
319
}
287
320
Ok ( ( ) )
288
321
}
0 commit comments