use std::path::{Path, PathBuf};
use comrak::{Arena, ComrakOptions};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
const GEN_SCRIPT_MD: &str = "crates/lex-core/benches/md_corpus/prep.py";
const GEN_SCRIPT_CORPUS: &str = "crates/lex-core/benches/corpus/gen.py";
fn lex_babel_comrak_options() -> ComrakOptions<'static> {
let mut options = ComrakOptions::default();
options.extension.table = true;
options.extension.strikethrough = true;
options.extension.autolink = true;
options.extension.tasklist = true;
options.extension.superscript = true;
options.extension.front_matter_delimiter = Some("---".to_string());
options
}
struct Fixture {
name: &'static str,
lex: &'static str,
md: &'static str,
}
const FIXTURES: &[Fixture] = &[
Fixture {
name: "010-kitchensink",
lex: "comms/specs/benchmark/010-kitchensink.lex",
md: "comms/specs/benchmark/010-kitchensink.md",
},
Fixture {
name: "20-ideas-naked",
lex: "comms/specs/benchmark/20-ideas-naked.lex",
md: "comms/specs/benchmark/20-ideas-naked.md",
},
Fixture {
name: "040-on-parsing",
lex: "comms/specs/benchmark/040-on-parsing.lex",
md: "crates/lex-core/benches/md_corpus/auto/040-on-parsing.md",
},
Fixture {
name: "080-gentle-introduction",
lex: "comms/specs/benchmark/080-gentle-introduction.lex",
md: "crates/lex-core/benches/md_corpus/auto/080-gentle-introduction.md",
},
Fixture {
name: "p1_10k",
lex: "crates/lex-core/benches/corpus/p1_10k/host.lex",
md: "crates/lex-core/benches/corpus/p1_10k/host.md",
},
Fixture {
name: "p2_100k",
lex: "crates/lex-core/benches/corpus/p2_100k/host.lex",
md: "crates/lex-core/benches/corpus/p2_100k/host.md",
},
Fixture {
name: "p3_1m",
lex: "crates/lex-core/benches/corpus/p3_1m/host.lex",
md: "crates/lex-core/benches/corpus/p3_1m/host.md",
},
];
fn repo_root() -> PathBuf {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
manifest
.join("../..")
.canonicalize()
.expect("repo root must canonicalise")
}
fn load(repo: &Path, rel: &str) -> String {
let path = repo.join(rel);
std::fs::read_to_string(&path).unwrap_or_else(|e| {
let hint = if rel.starts_with("comms/") {
"init the submodule: `git submodule update --init`".to_string()
} else if rel.starts_with("crates/lex-core/benches/corpus/") {
format!("run: python3 {}/{}", repo.display(), GEN_SCRIPT_CORPUS)
} else if rel.starts_with("crates/lex-core/benches/md_corpus/") {
format!("run: python3 {}/{}", repo.display(), GEN_SCRIPT_MD)
} else {
format!(
"see {}/{} or {}/{}",
repo.display(),
GEN_SCRIPT_CORPUS,
repo.display(),
GEN_SCRIPT_MD
)
};
panic!("missing fixture {}: {e}\n{hint}", path.display());
})
}
fn bench_parse(c: &mut Criterion) {
let repo = repo_root();
let mut group = c.benchmark_group("parse_vs_markdown");
group.measurement_time(std::time::Duration::from_secs(10));
group.warm_up_time(std::time::Duration::from_secs(3));
let md_opts = lex_babel_comrak_options();
for fx in FIXTURES {
let lex_src = load(&repo, fx.lex);
let md_src = load(&repo, fx.md);
let lex_name = format!("{}/lex", fx.name);
group.bench_function(&lex_name, |b| {
b.iter(|| {
let doc =
lex_core::lex::parsing::parse_document(black_box(&lex_src)).expect("lex parse");
black_box(doc);
});
});
let md_name = format!("{}/md", fx.name);
group.bench_function(&md_name, |b| {
b.iter(|| {
let arena = Arena::new();
let doc = comrak::parse_document(&arena, black_box(&md_src), &md_opts);
black_box(doc);
});
});
}
group.finish();
}
criterion_group!(benches, bench_parse);
criterion_main!(benches);