Skip to content

Commit 2f3a6c3

Browse files
Merge branch 'main' into yihozhang-fix-subsume2
2 parents 9684208 + ca4f533 commit 2f3a6c3

37 files changed

+1494
-1404
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ lazy_static = "1.4"
5353
num = "0.4.3"
5454
smallvec = "1.11"
5555

56-
generic_symbolic_expressions = "5.0.4"
57-
5856
egraph-serialize = { version = "0.2.0", default-features = false }
5957

6058
# binary dependencies
@@ -84,3 +82,8 @@ libtest-mimic = "0.6.1"
8482

8583
[profile.release]
8684
incremental = true
85+
86+
# https://github.com/mstange/samply/?tab=readme-ov-file#turn-on-debug-info-for-full-stacks
87+
[profile.profiling]
88+
inherits = "release"
89+
debug = true

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,22 @@ We use 50ms as our cutoff currently, any benchmarks shorter than that are ignore
7373
any benchmarks with have changes > 1% when they haven't been modified. Note that all the ignoring is done manually,
7474
so if you add another example that's short, an admin on the codspeed project will need to manually ignore it.
7575

76+
## Profiling
77+
78+
One way to profile egglog is to use [samply](https://github.com/mstange/samply/). Here's how you can use it:
79+
80+
```bash
81+
# install samply
82+
cargo install --locked samply
83+
# build a profile build which includes debug symbols
84+
cargo build --profile profiling
85+
# run the egglog file and profile
86+
samply record ./target/profiling/egglog tests/extract-vec-bench.egg
87+
# [optional] run the egglog file without logging or printing messages, which can help reduce the stdout
88+
# when you are profiling extracting a large expression
89+
env RUST_LOG=error samply record ./target/profiling/egglog --dont-print-messages tests/extract-vec-bench.egg
90+
```
91+
7692
# Documentation
7793

7894
To view documentation, run `cargo doc --open`.

benches/example_benchmarks.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
use codspeed_criterion_compat::{criterion_group, criterion_main, Criterion};
22
use egglog::EGraph;
33

4-
fn run_example(filename: &str, program: &str) {
5-
EGraph::default()
4+
fn run_example(filename: &str, program: &str, no_messages: bool) {
5+
let mut egraph = EGraph::default();
6+
if no_messages {
7+
egraph.disable_messages();
8+
}
9+
egraph
610
.parse_and_run_program(Some(filename.to_owned()), program)
711
.unwrap();
812
}
@@ -17,7 +21,10 @@ pub fn criterion_benchmark(c: &mut Criterion) {
1721
let name = path.file_stem().unwrap().to_string_lossy().to_string();
1822
let filename = path.to_string_lossy().to_string();
1923
let program = std::fs::read_to_string(&filename).unwrap();
20-
c.bench_function(&name, |b| b.iter(|| run_example(&filename, &program)));
24+
let no_messages = path_string.contains("no-messages");
25+
c.bench_function(&name, |b| {
26+
b.iter(|| run_example(&filename, &program, no_messages))
27+
});
2128
}
2229
}
2330

src/actions.rs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,12 @@ impl EGraph {
339339
let variants = values[1].bits as i64;
340340
if variants == 0 {
341341
let (cost, term) = self.extract(values[0], &mut termdag, sort);
342-
let extracted = termdag.to_string(&term);
343-
log::info!("extracted with cost {cost}: {extracted}");
344-
self.print_msg(extracted);
342+
// dont turn termdag into a string if we have messages disabled for performance reasons
343+
if self.messages_enabled() {
344+
let extracted = termdag.to_string(&term);
345+
log::info!("extracted with cost {cost}: {extracted}");
346+
self.print_msg(extracted);
347+
}
345348
self.extract_report = Some(ExtractReport::Best {
346349
termdag,
347350
cost,
@@ -353,17 +356,20 @@ impl EGraph {
353356
}
354357
let terms =
355358
self.extract_variants(sort, values[0], variants as usize, &mut termdag);
356-
log::info!("extracted variants:");
357-
let mut msg = String::default();
358-
msg += "(\n";
359-
assert!(!terms.is_empty());
360-
for expr in &terms {
361-
let str = termdag.to_string(expr);
362-
log::info!(" {str}");
363-
msg += &format!(" {str}\n");
359+
// Same as above, avoid turning termdag into a string if we have messages disabled for performance
360+
if self.messages_enabled() {
361+
log::info!("extracted variants:");
362+
let mut msg = String::default();
363+
msg += "(\n";
364+
assert!(!terms.is_empty());
365+
for expr in &terms {
366+
let str = termdag.to_string(expr);
367+
log::info!(" {str}");
368+
msg += &format!(" {str}\n");
369+
}
370+
msg += ")";
371+
self.print_msg(msg);
364372
}
365-
msg += ")";
366-
self.print_msg(msg);
367373
self.extract_report = Some(ExtractReport::Variants { termdag, terms });
368374
}
369375

@@ -372,7 +378,7 @@ impl EGraph {
372378
Instruction::Panic(msg) => panic!("Panic: {msg}"),
373379
Instruction::Literal(lit) => match lit {
374380
Literal::Int(i) => stack.push(Value::from(*i)),
375-
Literal::F64(f) => stack.push(Value::from(*f)),
381+
Literal::Float(f) => stack.push(Value::from(*f)),
376382
Literal::String(s) => stack.push(Value::from(*s)),
377383
Literal::Bool(b) => stack.push(Value::from(*b)),
378384
Literal::Unit => stack.push(Value::unit()),

src/ast/desugar.rs

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ use crate::*;
66
/// makes rules into a SSA-like format (see [`NormFact`]).
77
pub(crate) fn desugar_program(
88
program: Vec<Command>,
9-
symbol_gen: &mut SymbolGen,
9+
parser: &mut Parser,
1010
seminaive_transform: bool,
1111
) -> Result<Vec<NCommand>, Error> {
1212
let mut res = vec![];
1313
for command in program {
14-
let desugared = desugar_command(command, symbol_gen, seminaive_transform)?;
14+
let desugared = desugar_command(command, parser, seminaive_transform)?;
1515
res.extend(desugared);
1616
}
1717
Ok(res)
@@ -22,7 +22,7 @@ pub(crate) fn desugar_program(
2222
/// makes rules into a SSA-like format (see [`NormFact`]).
2323
pub(crate) fn desugar_command(
2424
command: Command,
25-
symbol_gen: &mut SymbolGen,
25+
parser: &mut Parser,
2626
seminaive_transform: bool,
2727
) -> Result<Vec<NCommand>, Error> {
2828
let res = match command {
@@ -50,15 +50,9 @@ pub(crate) fn desugar_command(
5050
cost,
5151
unextractable,
5252
))],
53-
Command::Relation {
54-
span,
55-
constructor,
56-
inputs,
57-
} => vec![NCommand::Function(FunctionDecl::relation(
58-
span,
59-
constructor,
60-
inputs,
61-
))],
53+
Command::Relation { span, name, inputs } => vec![NCommand::Function(
54+
FunctionDecl::relation(span, name, inputs),
55+
)],
6256
Command::Datatype {
6357
span,
6458
name,
@@ -108,28 +102,28 @@ pub(crate) fn desugar_command(
108102

109103
res
110104
}
111-
Command::Rewrite(ruleset, rewrite, subsume) => {
112-
desugar_rewrite(ruleset, rewrite_name(&rewrite).into(), &rewrite, subsume)
105+
Command::Rewrite(ruleset, ref rewrite, subsume) => {
106+
desugar_rewrite(ruleset, rule_name(&command), rewrite, subsume)
113107
}
114-
Command::BiRewrite(ruleset, rewrite) => {
115-
desugar_birewrite(ruleset, rewrite_name(&rewrite).into(), &rewrite)
108+
Command::BiRewrite(ruleset, ref rewrite) => {
109+
desugar_birewrite(ruleset, rule_name(&command), rewrite)
116110
}
117111
Command::Include(span, file) => {
118112
let s = std::fs::read_to_string(&file)
119113
.unwrap_or_else(|_| panic!("{span} Failed to read file {file}"));
120114
return desugar_program(
121-
parse_program(Some(file), &s)?,
122-
symbol_gen,
115+
parse_program(Some(file), &s, parser)?,
116+
parser,
123117
seminaive_transform,
124118
);
125119
}
126120
Command::Rule {
127121
ruleset,
128122
mut name,
129-
rule,
123+
ref rule,
130124
} => {
131125
if name == "".into() {
132-
name = rule.to_string().replace('\"', "'").into();
126+
name = rule_name(&command);
133127
}
134128

135129
let result = vec![NCommand::NormRule {
@@ -150,7 +144,7 @@ pub(crate) fn desugar_command(
150144
span,
151145
expr,
152146
schedule,
153-
} => desugar_simplify(&expr, &schedule, span, symbol_gen),
147+
} => desugar_simplify(&expr, &schedule, span, parser),
154148
Command::RunSchedule(sched) => {
155149
vec![NCommand::RunSchedule(sched.clone())]
156150
}
@@ -177,14 +171,15 @@ pub(crate) fn desugar_command(
177171
// ((extract {fresh} {variants}))
178172
// :ruleset {fresh_ruleset})
179173
// (run {fresh_ruleset} 1)
180-
let fresh = symbol_gen.fresh(&"desugar_qextract_var".into());
181-
let fresh_ruleset = symbol_gen.fresh(&"desugar_qextract_ruleset".into());
182-
let fresh_rulename = symbol_gen.fresh(&"desugar_qextract_rulename".into());
174+
let fresh = parser.symbol_gen.fresh(&"desugar_qextract_var".into());
175+
let fresh_ruleset = parser.symbol_gen.fresh(&"desugar_qextract_ruleset".into());
176+
let fresh_rulename = parser.symbol_gen.fresh(&"desugar_qextract_rulename".into());
183177
let rule = Rule {
184178
span: span.clone(),
185179
body: vec![Fact::Eq(
186180
span.clone(),
187-
vec![Expr::Var(span.clone(), fresh), expr.clone()],
181+
Expr::Var(span.clone(), fresh),
182+
expr.clone(),
188183
)],
189184
head: Actions::singleton(Action::Extract(
190185
span.clone(),
@@ -223,7 +218,7 @@ pub(crate) fn desugar_command(
223218
vec![NCommand::Pop(span, num)]
224219
}
225220
Command::Fail(span, cmd) => {
226-
let mut desugared = desugar_command(*cmd, symbol_gen, seminaive_transform)?;
221+
let mut desugared = desugar_command(*cmd, parser, seminaive_transform)?;
227222

228223
let last = desugared.pop().unwrap();
229224
desugared.push(NCommand::Fail(span, Box::new(last)));
@@ -293,7 +288,8 @@ fn desugar_rewrite(
293288
span: span.clone(),
294289
body: [Fact::Eq(
295290
span.clone(),
296-
vec![Expr::Var(span, var), rewrite.lhs.clone()],
291+
Expr::Var(span, var),
292+
rewrite.lhs.clone(),
297293
)]
298294
.into_iter()
299295
.chain(rewrite.conditions.clone())
@@ -326,10 +322,10 @@ fn desugar_simplify(
326322
expr: &Expr,
327323
schedule: &Schedule,
328324
span: Span,
329-
symbol_gen: &mut SymbolGen,
325+
parser: &mut Parser,
330326
) -> Vec<NCommand> {
331327
let mut res = vec![NCommand::Push(1)];
332-
let lhs = symbol_gen.fresh(&"desugar_simplify".into());
328+
let lhs = parser.symbol_gen.fresh(&"desugar_simplify".into());
333329
res.push(NCommand::CoreAction(Action::Let(
334330
span.clone(),
335331
lhs,
@@ -343,7 +339,7 @@ fn desugar_simplify(
343339
variants: 0,
344340
expr: Expr::Var(span.clone(), lhs),
345341
},
346-
symbol_gen,
342+
parser,
347343
false,
348344
)
349345
.unwrap(),
@@ -353,6 +349,10 @@ fn desugar_simplify(
353349
res
354350
}
355351

356-
pub(crate) fn rewrite_name(rewrite: &Rewrite) -> String {
357-
rewrite.to_string().replace('\"', "'")
352+
pub fn rule_name<Head, Leaf>(command: &GenericCommand<Head, Leaf>) -> Symbol
353+
where
354+
Head: Clone + Display,
355+
Leaf: Clone + PartialEq + Eq + Hash + Display,
356+
{
357+
command.to_string().replace('\"', "'").into()
358358
}

src/ast/expr.rs

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
use super::ToSexp;
21
use crate::{core::ResolvedCall, *};
32
use ordered_float::OrderedFloat;
43
use std::{fmt::Display, hash::Hasher};
54

65
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
76
pub enum Literal {
87
Int(i64),
9-
F64(OrderedFloat<f64>),
8+
Float(OrderedFloat<f64>),
109
String(Symbol),
1110
Bool(bool),
1211
Unit,
@@ -33,14 +32,14 @@ macro_rules! impl_from {
3332
}
3433

3534
impl_from!(Int(i64));
36-
impl_from!(F64(OrderedFloat<f64>));
35+
impl_from!(Float(OrderedFloat<f64>));
3736
impl_from!(String(Symbol));
3837

3938
impl Display for Literal {
4039
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4140
match &self {
4241
Literal::Int(i) => Display::fmt(i, f),
43-
Literal::F64(n) => {
42+
Literal::Float(n) => {
4443
// need to display with decimal if there is none
4544
let str = n.to_string();
4645
if let Ok(_num) = str.parse::<i64>() {
@@ -97,12 +96,6 @@ impl Display for ResolvedVar {
9796
}
9897
}
9998

100-
impl ToSexp for ResolvedVar {
101-
fn to_sexp(&self) -> Sexp {
102-
Sexp::Symbol(self.name.to_string())
103-
}
104-
}
105-
10699
pub type Expr = GenericExpr<Symbol, Symbol>;
107100
/// A generated expression is an expression that is generated by the system
108101
/// and does not have annotations.
@@ -250,31 +243,18 @@ impl<Head: Clone + Display, Leaf: Hash + Clone + Display + Eq> GenericExpr<Head,
250243
}
251244
}
252245

253-
impl<Head: Display, Leaf: Display> GenericExpr<Head, Leaf> {
254-
/// Converts this expression into a
255-
/// s-expression (symbolic expression).
256-
/// Example: `(Add (Add 2 3) 4)`
257-
pub fn to_sexp(&self) -> Sexp {
258-
let res = match self {
259-
GenericExpr::Lit(_ann, lit) => Sexp::Symbol(lit.to_string()),
260-
GenericExpr::Var(_ann, v) => Sexp::Symbol(v.to_string()),
261-
GenericExpr::Call(_ann, op, children) => Sexp::List(
262-
vec![Sexp::Symbol(op.to_string())]
263-
.into_iter()
264-
.chain(children.iter().map(|c| c.to_sexp()))
265-
.collect(),
266-
),
267-
};
268-
res
269-
}
270-
}
271-
272246
impl<Head, Leaf> Display for GenericExpr<Head, Leaf>
273247
where
274248
Head: Display,
275249
Leaf: Display,
276250
{
277-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278-
write!(f, "{}", self.to_sexp())
251+
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
252+
match self {
253+
GenericExpr::Lit(_ann, lit) => write!(f, "{lit}"),
254+
GenericExpr::Var(_ann, var) => write!(f, "{var}"),
255+
GenericExpr::Call(_ann, op, children) => {
256+
write!(f, "({} {})", op, ListDisplay(children, " "))
257+
}
258+
}
279259
}
280260
}

0 commit comments

Comments
 (0)