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 tinymist_std::typst_shim::syntax::VirtualPathExt;
21use typst::World;
22use typst::engine::{Engine, Route, Sink, Traced};
23use typst::foundations::{Context, Func, Value};
24use typst::introspection::EmptyIntrospector;
25
26pub fn bench(c: &mut Criterion, world: &mut LspWorld) -> anyhow::Result<()> {
29 let main_source = world.source(world.main())?;
31 let main_path = unix_slash(world.main().vpath().as_rooted_path_compat());
32
33 let library = world.library();
34 let traced = Traced::default();
35 let introspector = EmptyIntrospector;
36
37 let module = eval_compat(world, &main_source);
39 let module = module
40 .map_err(|e| anyhow::anyhow!("{e:?}"))
41 .context("evaluation error")?;
42
43 let mut goals: Vec<(EcoString, &Func)> = vec![];
45 for (name, bind) in module.scope().iter() {
46 if !name.starts_with("bench") {
47 continue;
48 }
49
50 if let Value::Func(func) = bind.read() {
51 goals.push((eco_format!("{main_path}@{name}"), func));
52 }
53 }
54
55 for (name, func) in goals {
57 let route = Route::default();
58 let mut sink = Sink::default();
59 let engine = &mut Engine {
60 library,
61 world: ((world) as &dyn World).track(),
62 introspector: typst::utils::Protected::new(introspector.track()),
63 traced: traced.track(),
64 sink: sink.track_mut(),
65 route,
66 };
67
68 let mut call_once = move || {
70 let context = Context::default();
71 let values = Vec::<Value>::default();
72 func.call(engine, context.track(), values)
73 };
74
75 if let Err(err) = call_once() {
79 eprintln!("call error in {name}: {err:?}");
80 continue;
81 }
82
83 c.bench_function(&name, move |b| {
85 b.iter(|| {
86 comemo::evict(0);
87 let _result = call_once();
88 })
89 });
90 }
91
92 Ok(())
93}