swc/crates/swc_ecma_transforms_base/benches/deps.rs
Donny/강동윤 581aafb4df
perf(visit): Introduce Pass API and adjust visitor APIs for it (#9680)
**Description:**

 - `Pass`: `FnMut(&mut Program)`.

**Breaking Changes:**

- `chain!`: Use a tuple instead. You can replace all `chain!(` with `(` with IDE feature and it will work.
- `chain!` with 13 or more args: Use nested tuples for items after 13th element.


**Related issue:**

 - Related to https://github.com/swc-project/swc/issues/9601
2024-10-29 11:25:16 +09:00

241 lines
6.4 KiB
Rust

use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Bencher, Criterion};
use swc_common::{FileName, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_parser::{lexer::Lexer, parse_file_as_module, Parser, StringInput, Syntax};
use swc_ecma_utils::ExprFactory;
use swc_ecma_visit::{Fold, FoldWith, Visit, VisitWith};
static SOURCE: &str = include_str!("assets/AjaxObservable.ts");
fn module_clone(b: &mut Bencher) {
let _ = ::testing::run_test(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Anon.into(), SOURCE.into());
let mut errors = Vec::new();
let module = parse_file_as_module(
&fm,
Syntax::Typescript(Default::default()),
Default::default(),
None,
&mut errors,
)
.map_err(|e| {
e.into_diagnostic(handler).emit();
})
.unwrap();
for e in errors {
e.into_diagnostic(handler).emit();
}
b.iter(|| black_box(module.clone()));
Ok(())
});
}
fn fold_empty(b: &mut Bencher) {
let _ = ::testing::run_test(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Anon.into(), SOURCE.into());
let mut errors = Vec::new();
let module = parse_file_as_module(
&fm,
Syntax::Typescript(Default::default()),
Default::default(),
None,
&mut errors,
)
.map_err(|e| {
e.into_diagnostic(handler).emit();
})
.unwrap();
for e in errors {
e.into_diagnostic(handler).emit();
}
let mut folder = noop_pass();
b.iter(|| black_box(Program::Module(module.clone()).apply(&mut folder)));
Ok(())
});
}
/// Optimized out
fn fold_noop_impl_all(b: &mut Bencher) {
let _ = ::testing::run_test(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Anon.into(), SOURCE.into());
let mut errors = Vec::new();
let module = parse_file_as_module(
&fm,
Syntax::Typescript(Default::default()),
Default::default(),
None,
&mut errors,
)
.map_err(|e| e.into_diagnostic(handler).emit())
.unwrap();
for e in errors {
e.into_diagnostic(handler).emit();
}
let mut folder = noop_pass();
b.iter(|| black_box(Program::Module(module.clone()).apply(&mut folder)));
Ok(())
});
}
/// Optimized out
fn fold_noop_impl_vec(b: &mut Bencher) {
let _ = ::testing::run_test(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Anon.into(), SOURCE.into());
let mut errors = Vec::new();
let module = parse_file_as_module(
&fm,
Syntax::Typescript(Default::default()),
Default::default(),
None,
&mut errors,
)
.map_err(|e| {
e.into_diagnostic(handler).emit();
})
.unwrap();
for e in errors {
e.into_diagnostic(handler).emit();
}
let mut folder = noop_pass();
b.iter(|| black_box(Program::Module(module.clone()).apply(&mut folder)));
Ok(())
});
}
fn mk_expr() -> Expr {
CallExpr {
span: DUMMY_SP,
callee: Ident::new_no_ctxt("foo".into(), DUMMY_SP).as_callee(),
args: Vec::new(),
..Default::default()
}
.into()
}
fn boxing_boxed_clone(b: &mut Bencher) {
let _ = ::testing::run_test(false, |_, _| {
let expr = Box::new(mk_expr());
b.iter(|| black_box(expr.clone()));
Ok(())
});
}
fn boxing_unboxed_clone(b: &mut Bencher) {
let _ = ::testing::run_test(false, |_, _| {
let expr = mk_expr();
b.iter(|| black_box(expr.clone()));
Ok(())
});
}
fn boxing_boxed(b: &mut Bencher) {
let _ = ::testing::run_test(false, |_, _| {
let mut folder = noop_fold();
let expr = Box::new(mk_expr());
b.iter(|| black_box(expr.clone().fold_with(&mut folder)));
Ok(())
});
}
fn boxing_unboxed(b: &mut Bencher) {
let _ = ::testing::run_test(false, |_, _| {
let mut folder = noop_fold();
let expr = mk_expr();
b.iter(|| black_box(expr.clone().fold_with(&mut folder)));
Ok(())
});
}
fn visit_contains_this(b: &mut Bencher) {
fn contains_this_expr(body: &Module) -> bool {
struct Visitor {
found: bool,
}
impl Visit for Visitor {
/// Don't recurse into fn
fn visit_fn_expr(&mut self, _: &FnExpr) {}
/// Don't recurse into fn
fn visit_fn_decl(&mut self, _: &FnDecl) {}
fn visit_this_expr(&mut self, _: &ThisExpr) {
self.found = true;
}
}
let mut visitor = Visitor { found: false };
body.visit_with(&mut visitor);
visitor.found
}
let _ = ::testing::run_test(false, |cm, _| {
let fm = cm.new_source_file(FileName::Anon.into(), SOURCE.into());
let lexer = Lexer::new(
Syntax::Typescript(Default::default()),
Default::default(),
StringInput::from(&*fm),
None,
);
let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().map_err(|_| ()).unwrap();
b.iter(|| black_box(contains_this_expr(&module)));
Ok(())
});
}
fn bench_cases(c: &mut Criterion) {
c.bench_function("es/visitor/base-perf/module_clone", module_clone);
c.bench_function("es/visitor/base-perf/fold_empty", fold_empty);
c.bench_function(
"es/visitor/base-perf/fold_noop_impl_all",
fold_noop_impl_all,
);
c.bench_function(
"es/visitor/base-perf/fold_noop_impl_vec",
fold_noop_impl_vec,
);
c.bench_function(
"es/visitor/base-perf/boxing_boxed_clone",
boxing_boxed_clone,
);
c.bench_function(
"es/visitor/base-perf/boxing_unboxed_clone",
boxing_unboxed_clone,
);
c.bench_function("es/visitor/base-perf/boxing_boxed", boxing_boxed);
c.bench_function("es/visitor/base-perf/boxing_unboxed", boxing_unboxed);
c.bench_function(
"es/visitor/base-perf/visit_contains_this",
visit_contains_this,
);
}
criterion_group!(benches, bench_cases);
criterion_main!(benches);
fn noop_fold() -> impl Fold {
struct Noop;
impl Fold for Noop {}
Noop
}