perf(es/minifier): Make mangler faster by merging hash sets into one (#3983)

This commit is contained in:
Donny/강동윤 2022-03-12 15:16:02 +09:00 committed by GitHub
parent 77eb149f87
commit 107c91dd20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 570004 additions and 12 deletions

177
Cargo.lock generated
View File

@ -225,6 +225,18 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.9.1" version = "3.9.1"
@ -264,6 +276,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cast"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
dependencies = [
"rustc_version 0.4.0",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.72" version = "1.0.72"
@ -297,6 +318,17 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"bitflags",
"textwrap 0.11.0",
"unicode-width",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.1.0" version = "3.1.0"
@ -312,7 +344,7 @@ dependencies = [
"strsim", "strsim",
"termcolor", "termcolor",
"terminal_size", "terminal_size",
"textwrap", "textwrap 0.14.2",
] ]
[[package]] [[package]]
@ -497,6 +529,42 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "criterion"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap 2.34.0",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools",
]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.1" version = "0.5.1"
@ -557,6 +625,28 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "csv"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa 0.4.8",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "0.1.21" version = "0.1.21"
@ -933,6 +1023,12 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.11.2"
@ -1676,6 +1772,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.38" version = "0.10.38"
@ -1932,6 +2034,34 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "plotters"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
[[package]]
name = "plotters-svg"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
dependencies = [
"plotters-backend",
]
[[package]] [[package]]
name = "pmutil" name = "pmutil"
version = "0.5.3" version = "0.5.3"
@ -2356,6 +2486,15 @@ dependencies = [
"semver 0.9.0", "semver 0.9.0",
] ]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.4",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.6" version = "1.0.6"
@ -2482,6 +2621,16 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.136" version = "1.0.136"
@ -2580,7 +2729,7 @@ dependencies = [
"if_chain", "if_chain",
"lazy_static", "lazy_static",
"regex", "regex",
"rustc_version", "rustc_version 0.2.3",
"serde", "serde",
"serde_json", "serde_json",
"url", "url",
@ -2636,7 +2785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
dependencies = [ dependencies = [
"discard", "discard",
"rustc_version", "rustc_version 0.2.3",
"stdweb-derive", "stdweb-derive",
"stdweb-internal-macros", "stdweb-internal-macros",
"stdweb-internal-runtime", "stdweb-internal-runtime",
@ -2841,7 +2990,7 @@ version = "0.24.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atty", "atty",
"clap", "clap 3.1.0",
"path-absolutize", "path-absolutize",
"rayon", "rayon",
"relative-path", "relative-path",
@ -3126,6 +3275,7 @@ dependencies = [
"ansi_term", "ansi_term",
"anyhow", "anyhow",
"backtrace", "backtrace",
"criterion",
"indexmap", "indexmap",
"once_cell", "once_cell",
"parking_lot 0.12.0", "parking_lot 0.12.0",
@ -3843,6 +3993,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.14.2" version = "0.14.2"
@ -3938,6 +4097,16 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.5.1" version = "1.5.1"

View File

@ -45,6 +45,11 @@ unicode-id = "0.3.0"
[dev-dependencies] [dev-dependencies]
ansi_term = "0.12.1" ansi_term = "0.12.1"
anyhow = "1" anyhow = "1"
criterion = "0.3.5"
pretty_assertions = "1.1" pretty_assertions = "1.1"
swc_node_base = {version = "0.5.0", path = "../swc_node_base"} swc_node_base = {version = "0.5.0", path = "../swc_node_base"}
testing = {version = "0.18.0", path = "../testing"} testing = {version = "0.18.0", path = "../testing"}
[[bench]]
harness = false
name = "full"

View File

@ -0,0 +1,110 @@
//! Ported from https://github.com/privatenumber/minification-benchmarks
use std::fs::read_to_string;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use swc_common::{sync::Lrc, FileName, Mark, SourceMap};
use swc_ecma_codegen::text_writer::JsWriter;
use swc_ecma_minifier::{
optimize,
option::{ExtraOptions, MangleOptions, MinifyOptions},
};
use swc_ecma_parser::parse_file_as_module;
use swc_ecma_transforms::{fixer, resolver_with_mark};
use swc_ecma_visit::FoldWith;
pub fn bench_files(c: &mut Criterion) {
let mut group = c.benchmark_group("libs");
group.sample_size(10);
let mut bench_file = |name: &str| {
let src = read_to_string(&format!("benches/full/{}.js", name)).unwrap();
group.bench_function(name, |b| {
b.iter(|| {
// We benchmark full time, including time for creating cm, handler
run(&src)
})
});
};
bench_file("antd");
bench_file("d3");
bench_file("echarts");
bench_file("jquery");
bench_file("lodash");
bench_file("moment");
bench_file("react");
bench_file("terser");
bench_file("three");
bench_file("typescript");
bench_file("victory");
bench_file("vue");
}
criterion_group!(files, bench_files);
criterion_main!(files);
fn run(src: &str) {
testing::run_test2(false, |cm, handler| {
let fm = cm.new_source_file(FileName::Anon, src.into());
let top_level_mark = Mark::fresh(Mark::root());
let program = parse_file_as_module(
&fm,
Default::default(),
Default::default(),
None,
&mut vec![],
)
.map_err(|err| {
err.into_diagnostic(&handler).emit();
})
.map(|module| module.fold_with(&mut resolver_with_mark(top_level_mark)))
.unwrap();
let output = optimize(
program,
cm.clone(),
None,
None,
&MinifyOptions {
compress: Some(Default::default()),
mangle: Some(MangleOptions {
top_level: true,
..Default::default()
}),
..Default::default()
},
&ExtraOptions { top_level_mark },
);
let output = output.fold_with(&mut fixer(None));
let code = print(cm, &[output], true);
black_box(code);
Ok(())
})
.unwrap();
}
fn print<N: swc_ecma_codegen::Node>(cm: Lrc<SourceMap>, nodes: &[N], minify: bool) -> String {
let mut buf = vec![];
{
let mut emitter = swc_ecma_codegen::Emitter {
cfg: swc_ecma_codegen::Config { minify },
cm: cm.clone(),
comments: None,
wr: Box::new(JsWriter::new(cm, "\n", &mut buf, None)),
};
for n in nodes {
n.emit_with(&mut emitter).unwrap();
}
}
String::from_utf8(buf).unwrap()
}

File diff suppressed because one or more lines are too long

19566
crates/swc_ecma_minifier/benches/full/d3.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,10 +13,11 @@ pub(crate) struct Scope {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct ScopeData { pub struct ScopeData {
decls: AHashSet<Id>, // decls: AHashSet<Id>,
/// Usages in current scope. // /// Usages in current scope.
usages: AHashSet<Id>, // usages: AHashSet<Id>,
all: AHashSet<Id>,
queue: Vec<(Id, u32)>, queue: Vec<(Id, u32)>,
} }
@ -27,7 +28,8 @@ impl Scope {
return; return;
} }
self.data.decls.insert(id.clone()); // self.data.decls.insert(id.clone());
self.data.all.insert(id.clone());
{ {
if let Some((_, cnt)) = self.data.queue.iter_mut().find(|(i, _)| *i == *id) { if let Some((_, cnt)) = self.data.queue.iter_mut().find(|(i, _)| *i == *id) {
*cnt += 1; *cnt += 1;
@ -46,7 +48,8 @@ impl Scope {
*cnt += 1; *cnt += 1;
} }
self.data.usages.insert(id.clone()); // self.data.usages.insert(id.clone());
self.data.all.insert(id.clone());
} }
pub(super) fn rename( pub(super) fn rename(
@ -76,8 +79,10 @@ impl Scope {
if self.can_rename(&id, &sym, to) { if self.can_rename(&id, &sym, to) {
to.insert(id.clone(), sym); to.insert(id.clone(), sym);
self.data.decls.remove(&id); // self.data.decls.remove(&id);
self.data.usages.remove(&id); // self.data.usages.remove(&id);
self.data.all.remove(&id);
break; break;
} }
} }
@ -88,6 +93,7 @@ impl Scope {
} }
} }
#[inline]
fn can_rename(&self, id: &Id, symbol: &JsWord, renamed: &RenameMap) -> bool { fn can_rename(&self, id: &Id, symbol: &JsWord, renamed: &RenameMap) -> bool {
if let Some(lefts) = renamed.get_by_right(symbol) { if let Some(lefts) = renamed.get_by_right(symbol) {
for left in lefts { for left in lefts {
@ -96,7 +102,11 @@ impl Scope {
} }
// //
if self.data.usages.contains(left) || self.data.decls.contains(left) { // if self.data.usages.contains(left) || self.data.decls.contains(left) {
// return false;
// }
if self.data.all.contains(left) {
return false; return false;
} }
} }