Skip to content

Commit 5997d49

Browse files
committed
Use simpler state as debug data source
1 parent ad08cc7 commit 5997d49

File tree

2 files changed

+153
-101
lines changed

2 files changed

+153
-101
lines changed

rust/cubesql/cubesql/src/compile/rewrite/analysis.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
rewrite::{
44
converter::{is_expr_node, node_to_expr, LogicalPlanToLanguageConverter},
55
expr_column_name,
6-
rewriter::{CubeEGraph, DebugData},
6+
rewriter::{CubeEGraph, EGraphDebugState},
77
AggregateUDFExprFun, AliasExprAlias, AllMembersAlias, AllMembersCube, ChangeUserCube,
88
ColumnExprColumn, DimensionName, FilterMemberMember, FilterMemberOp, LiteralExprValue,
99
LiteralMemberRelation, LiteralMemberValue, LogicalPlanLanguage, MeasureName,
@@ -235,16 +235,14 @@ impl Member {
235235
}
236236
}
237237

238-
type EgraphDebugState = DebugData;
239-
240238
#[derive(Clone)]
241239
pub struct LogicalPlanAnalysis {
242240
/* This is 0, when creating the EGraph. It's set to 1 before iteration 0,
243241
2 before the iteration 1, etc. */
244242
pub iteration_timestamp: usize,
245243
/// Debug info, used with egraph-debug
246244
/// Will be filled by special hook in Runner
247-
pub debug_states: Vec<EgraphDebugState>,
245+
pub debug_states: Vec<EGraphDebugState>,
248246
cube_context: Arc<CubeContext>,
249247
planner: Arc<DefaultPhysicalPlanner>,
250248
}
@@ -283,16 +281,12 @@ impl LogicalPlanAnalysis {
283281
}
284282
}
285283

286-
fn prepare_egraph_debug_state(egraph: &CubeEGraph) -> EgraphDebugState {
287-
DebugData::prepare(egraph)
288-
}
289-
290284
pub fn store_egraph_debug_state(egraph: &mut CubeEGraph) {
291285
debug_assert_eq!(
292286
egraph.analysis.iteration_timestamp,
293287
egraph.analysis.debug_states.len()
294288
);
295-
let state = Self::prepare_egraph_debug_state(egraph);
289+
let state = EGraphDebugState::new(egraph);
296290
egraph.analysis.debug_states.push(state);
297291
}
298292

rust/cubesql/cubesql/src/compile/rewrite/rewriter.rs

Lines changed: 150 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -74,66 +74,76 @@ pub struct DebugData {
7474
#[serde(rename = "removedCombos")]
7575
removed_combos: Vec<DebugCombo>,
7676
#[serde(rename = "appliedRules")]
77-
applied_rules: Option<Vec<String>>,
77+
applied_rules: Vec<String>,
7878
}
7979

80-
impl DebugData {
81-
pub fn prepare(graph: &CubeEGraph) -> DebugData {
82-
DebugData {
83-
applied_rules: None,
84-
nodes: graph
85-
.classes()
86-
.flat_map(|class| {
87-
let mut result = class
88-
.nodes
89-
.iter()
90-
.map(|n| {
91-
let node_id = format!("{}-{:?}", class.id, n);
92-
DebugNode {
93-
id: node_id.to_string(),
94-
label: format!("{:?}", n),
95-
combo_id: format!("c{}", class.id),
96-
}
97-
})
98-
.collect::<Vec<_>>();
99-
result.push(DebugNode {
100-
id: class.id.to_string(),
101-
label: class.id.to_string(),
102-
combo_id: format!("c{}", class.id),
103-
});
104-
result
105-
})
106-
.collect(),
107-
edges: graph
108-
.classes()
109-
.flat_map(|class| {
110-
class
111-
.nodes
112-
.iter()
113-
.map(|n| DebugEdge {
114-
source: class.id.to_string(),
115-
target: format!("{}-{:?}", class.id, n,),
116-
})
117-
.chain(class.nodes.iter().flat_map(|n| {
118-
n.children().iter().map(move |c| DebugEdge {
119-
source: format!("{}-{:?}", class.id, n),
120-
target: c.to_string(),
121-
})
122-
}))
123-
.collect::<Vec<_>>()
124-
})
125-
.collect(),
126-
combos: graph
127-
.classes()
128-
.map(|class| DebugCombo {
129-
id: format!("c{}", class.id),
130-
label: format!("#{}", class.id),
131-
})
132-
.collect(),
133-
removed_nodes: Vec::new(),
134-
removed_edges: Vec::new(),
135-
removed_combos: Vec::new(),
136-
}
80+
#[derive(Clone)]
81+
struct DebugENodeId(String);
82+
83+
impl DebugENodeId {
84+
pub fn as_str(&self) -> &str {
85+
self.0.as_str()
86+
}
87+
}
88+
89+
impl From<&LogicalPlanLanguage> for DebugENodeId {
90+
fn from(value: &LogicalPlanLanguage) -> Self {
91+
Self(format!("{value:?}"))
92+
}
93+
}
94+
95+
#[derive(Clone)]
96+
pub struct EClassDebugData {
97+
id: Id,
98+
#[allow(dead_code)]
99+
canon: Id,
100+
}
101+
102+
#[derive(Clone)]
103+
pub struct ENodeDebugData {
104+
enode: DebugENodeId,
105+
eclass: Id,
106+
children: Vec<Id>,
107+
}
108+
109+
/// Representation is optimised for storing in JSON, to transfer to UI
110+
#[derive(Clone)]
111+
pub struct EGraphDebugState {
112+
eclasses: Vec<EClassDebugData>,
113+
enodes: Vec<ENodeDebugData>,
114+
}
115+
116+
impl EGraphDebugState {
117+
pub fn new(graph: &EGraph<LogicalPlanLanguage, LogicalPlanAnalysis>) -> Self {
118+
let current_eclasses = graph.classes().map(|ec| ec.id);
119+
let previous_debug_eclasses = graph
120+
.analysis
121+
.debug_states
122+
.iter()
123+
.flat_map(|state| state.eclasses.iter().map(|ecd| ecd.id));
124+
let all_known_eclasses = current_eclasses.chain(previous_debug_eclasses);
125+
126+
let all_known_eclasses = all_known_eclasses.collect::<HashSet<_>>();
127+
128+
let eclasses = all_known_eclasses
129+
.into_iter()
130+
.map(|ec| EClassDebugData {
131+
id: ec,
132+
canon: graph.find(ec),
133+
})
134+
.collect::<Vec<_>>();
135+
136+
let enodes = graph
137+
.classes()
138+
.flat_map(|ec| ec.nodes.iter().map(move |node| (ec.id, node)))
139+
.map(|(ec, node)| ENodeDebugData {
140+
enode: node.into(),
141+
eclass: ec,
142+
children: node.children().to_vec(),
143+
})
144+
.collect();
145+
146+
EGraphDebugState { eclasses, enodes }
137147
}
138148
}
139149

@@ -191,7 +201,7 @@ fn write_debug_states(runner: &CubeRunner, stage: &str) -> Result<(), CubeError>
191201
)?;
192202

193203
let mut states = Vec::new();
194-
let mut last_debug_data: Option<DebugData> = None;
204+
let mut previous_debug_data: Option<(Vec<DebugNode>, Vec<DebugEdge>, Vec<DebugCombo>)> = None;
195205

196206
let debug_data = runner.egraph.analysis.debug_states.as_slice();
197207
debug_assert_eq!(debug_data.len(), runner.iterations.len() + 1);
@@ -204,47 +214,95 @@ fn write_debug_states(runner: &CubeRunner, stage: &str) -> Result<(), CubeError>
204214
.zip(runner.iterations.iter().map(|i| Some(&i.applied)));
205215
let states_data = std::iter::once((&debug_data[0], None)).chain(states_data);
206216

217+
// TODO move this even later, to UI side
207218
for (debug_data, applied) in states_data {
208-
let mut debug_data = debug_data.clone();
209-
let debug_data_clone = debug_data.clone();
210-
211-
if let Some(last) = last_debug_data {
212-
debug_data
213-
.nodes
214-
.retain(|n| !last.nodes.iter().any(|ln| ln.id == n.id));
215-
debug_data.edges.retain(|n| {
216-
!last
217-
.edges
219+
let mut nodes = debug_data
220+
.enodes
221+
.iter()
222+
.map(|node| {
223+
let node_id = format!("{}-{}", node.eclass, node.enode.as_str());
224+
DebugNode {
225+
id: node_id,
226+
label: node.enode.0.clone(),
227+
combo_id: format!("c{}", node.eclass),
228+
}
229+
})
230+
.chain(debug_data.eclasses.iter().map(|eclass| DebugNode {
231+
id: eclass.id.to_string(),
232+
label: eclass.id.to_string(),
233+
combo_id: format!("c{}", eclass.id),
234+
}))
235+
.collect::<Vec<_>>();
236+
237+
let mut edges = debug_data
238+
.enodes
239+
.iter()
240+
.flat_map(|node| {
241+
std::iter::once(DebugEdge {
242+
source: node.eclass.to_string(),
243+
target: format!("{}-{}", node.eclass, node.enode.as_str()),
244+
})
245+
.chain(node.children.iter().map(move |child| DebugEdge {
246+
source: format!("{}-{}", node.eclass, node.enode.as_str()),
247+
target: child.to_string(),
248+
}))
249+
})
250+
.collect::<Vec<_>>();
251+
252+
let mut combos = debug_data
253+
.eclasses
254+
.iter()
255+
.map(|eclass| DebugCombo {
256+
id: format!("c{}", eclass.id),
257+
label: format!("#{}", eclass.id),
258+
})
259+
.collect::<Vec<_>>();
260+
261+
let nodes_clone = nodes.clone();
262+
let edges_clone = edges.clone();
263+
let combos_clone = combos.clone();
264+
265+
let mut removed_nodes = vec![];
266+
let mut removed_edges = vec![];
267+
let mut removed_combos = vec![];
268+
269+
if let Some((prev_nodes, prev_edges, prev_combos)) = previous_debug_data {
270+
nodes.retain(|n| !prev_nodes.iter().any(|ln| ln.id == n.id));
271+
edges.retain(|n| {
272+
!prev_edges
218273
.iter()
219274
.any(|ln| ln.source == n.source && ln.target == n.target)
220275
});
221-
debug_data
222-
.combos
223-
.retain(|n| !last.combos.iter().any(|ln| ln.id == n.id));
224-
225-
debug_data.removed_nodes = last.nodes.clone();
226-
debug_data
227-
.removed_nodes
228-
.retain(|n| !debug_data_clone.nodes.iter().any(|ln| ln.id == n.id));
229-
debug_data.removed_edges = last.edges.clone();
230-
debug_data.removed_edges.retain(|n| {
231-
!debug_data_clone
232-
.edges
276+
combos.retain(|n| !prev_combos.iter().any(|ln| ln.id == n.id));
277+
278+
removed_nodes = prev_nodes.clone();
279+
removed_nodes.retain(|n| !nodes_clone.iter().any(|ln| ln.id == n.id));
280+
removed_edges = prev_edges.clone();
281+
removed_edges.retain(|n| {
282+
!edges_clone
233283
.iter()
234284
.any(|ln| ln.source == n.source && ln.target == n.target)
235285
});
236-
debug_data.removed_combos = last.combos.clone();
237-
debug_data
238-
.removed_combos
239-
.retain(|n| !debug_data_clone.combos.iter().any(|ln| ln.id == n.id));
286+
removed_combos = prev_combos.clone();
287+
removed_combos.retain(|n| !combos_clone.iter().any(|ln| ln.id == n.id));
240288
}
241-
debug_data.applied_rules = Some(
242-
applied
243-
.map(|applied| applied.iter().map(|s| format!("{:?}", s)).collect())
244-
.unwrap_or(vec![]),
245-
);
246-
states.push(debug_data);
247-
last_debug_data = Some(debug_data_clone);
289+
290+
let applied_rules = applied
291+
.map(|applied| applied.iter().map(|s| format!("{:?}", s)).collect())
292+
.unwrap_or(vec![]);
293+
294+
let debug_data = DebugData {
295+
nodes,
296+
edges,
297+
combos,
298+
removed_nodes,
299+
removed_edges,
300+
removed_combos,
301+
applied_rules,
302+
};
303+
304+
states.push(debug_data.clone());
305+
previous_debug_data = Some((nodes_clone, edges_clone, combos_clone));
248306
}
249307
fs::write(
250308
format!("{}/src/states.json", dir),

0 commit comments

Comments
 (0)