1use anyhow::Context as ContextTrait;
14use comemo::Track;
15use criterion::Criterion;
16use ecow::{EcoString, eco_format};
17use tinymist_project::LspWorld;
18use tinymist_std::path::unix_slash;
19use tinymist_std::typst_shim::eval::eval_compat;
20use typst::World;
21use typst::engine::{Engine, Route, Sink, Traced};
22use typst::foundations::{Context, Func, Value};
23use typst::introspection::Introspector;
24
25pub fn bench(c: &mut Criterion, world: &mut LspWorld) -> anyhow::Result<()> {
28 let main_source = world.source(world.main())?;
30 let main_path = unix_slash(world.main().vpath().as_rooted_path());
31
32 let traced = Traced::default();
33 let introspector = Introspector::default();
34
35 let module = eval_compat(world, &main_source);
37 let module = module
38 .map_err(|e| anyhow::anyhow!("{e:?}"))
39 .context("evaluation error")?;
40
41 let mut goals: Vec<(EcoString, &Func)> = vec![];
43 for (name, bind) in module.scope().iter() {
44 if !name.starts_with("bench") {
45 continue;
46 }
47
48 if let Value::Func(func) = bind.read() {
49 goals.push((eco_format!("{main_path}@{name}"), func));
50 }
51 }
52
53 for (name, func) in goals {
55 let route = Route::default();
56 let mut sink = Sink::default();
57 let engine = &mut Engine {
58 routines: &typst::ROUTINES,
59 world: ((world) as &dyn World).track(),
60 introspector: introspector.track(),
61 traced: traced.track(),
62 sink: sink.track_mut(),
63 route,
64 };
65
66 let mut call_once = move || {
68 let context = Context::default();
69 let values = Vec::<Value>::default();
70 func.call(engine, context.track(), values)
71 };
72
73 if let Err(err) = call_once() {
77 eprintln!("call error in {name}: {err:?}");
78 continue;
79 }
80
81 c.bench_function(&name, move |b| {
83 b.iter(|| {
84 comemo::evict(0);
85 let _result = call_once();
86 })
87 });
88 }
89
90 Ok(())
91}