Skip to main content

xtask/
main.rs

1use std::{
2    env::{current_dir, var_os},
3    path::PathBuf,
4    process,
5};
6
7use anyhow::Result;
8use clap::{Command, arg};
9
10mod nft_bench;
11mod summarize_bench;
12mod visualize_bundler_bench;
13
14use nft_bench::show_result;
15use rustc_hash::{FxHashMap, FxHashSet};
16
17fn cli() -> Command {
18    Command::new("xtask")
19        .about("turbo-tooling cargo tasks")
20        .subcommand_required(true)
21        .arg_required_else_help(true)
22        .allow_external_subcommands(true)
23        .subcommand(
24            Command::new("nft-bench-result")
25                .about("Print node-file-trace benchmark result against @vercel/nft"),
26        )
27        .subcommand(
28            Command::new("upgrade-swc").about("Upgrade all SWC dependencies to the latest version"),
29        )
30        .subcommand(
31            Command::new("summarize-benchmarks")
32                .about(
33                    "Normalize all raw data based on similar benchmarks, average data by \
34                     system+sha and compute latest by system",
35                )
36                .arg(arg!(<PATH> "the path to the benchmark data directory")),
37        )
38        .subcommand(
39            Command::new("visualize-bundler-benchmarks")
40                .about("Generate visualizations of bundler benchmarks")
41                .long_about(
42                    "Generates visualizations of bundler benchmarks. Currently supports:
43    * Scaling: shows how each bundler scales with varying module counts
44
45To generate the summary json file:
46    * Check out this repository at the `benchmark-data` branch. An additional shallow clone or git \
47                     worktree is recommended.
48    * Run `cargo xtask summarize-benchmarks path/to/repo/data`
49    * A summary file is generated within the data dir, e.g.  \
50                     path/to/repo/data/ubuntu-latest-16-core.json
51
52Visualizations generated by this command will appear in a sibling directory to the summary data \
53                     file.",
54                )
55                .arg(arg!(<PATH_TO_SUMMARY_JSON> "the path to the benchmark summary json file"))
56                .arg(arg!(--bundlers <BUNDLERS> "comma separated list of bundlers to include in the visualization")),
57        )
58}
59
60fn main() -> Result<()> {
61    let matches = cli().get_matches();
62    match matches.subcommand() {
63        Some(("nft-bench-result", _)) => {
64            show_result();
65            Ok(())
66        }
67        Some(("upgrade-swc", _)) => {
68            let workspace_dir = var_os("CARGO_WORKSPACE_DIR")
69                .map(PathBuf::from)
70                .unwrap_or_else(|| current_dir().unwrap());
71            let cargo_lock_path = workspace_dir.join("../../Cargo.lock");
72            let lock = cargo_lock::Lockfile::load(cargo_lock_path).unwrap();
73            let swc_packages = lock
74                .packages
75                .iter()
76                .filter(|p| {
77                    p.name.as_str().starts_with("swc_")
78                        || p.name.as_str() == "swc"
79                        || p.name.as_str() == "testing"
80                })
81                .collect::<Vec<_>>();
82            let only_swc_set = swc_packages
83                .iter()
84                .map(|p| p.name.as_str())
85                .collect::<FxHashSet<_>>();
86            let packages = lock
87                .packages
88                .iter()
89                .map(|p| (format!("{}@{}", p.name, p.version), p))
90                .collect::<FxHashMap<_, _>>();
91            let mut queue = swc_packages.clone();
92            let mut set = FxHashSet::default();
93            while let Some(package) = queue.pop() {
94                for dep in package.dependencies.iter() {
95                    let ident = format!("{}@{}", dep.name, dep.version);
96                    let package = *packages.get(&ident).unwrap();
97                    if set.insert(ident) {
98                        queue.push(package);
99                    }
100                }
101            }
102            let status = process::Command::new("cargo")
103                .arg("upgrade")
104                .arg("--workspace")
105                .args(only_swc_set)
106                .current_dir(&workspace_dir)
107                .stdout(process::Stdio::inherit())
108                .stderr(process::Stdio::inherit())
109                .status()
110                .expect("Running cargo upgrade failed");
111            assert!(status.success());
112            let status = process::Command::new("cargo")
113                .arg("update")
114                .args(set.iter().flat_map(|p| ["-p", p]))
115                .current_dir(&workspace_dir)
116                .stdout(process::Stdio::inherit())
117                .stderr(process::Stdio::inherit())
118                .status()
119                .expect("Running cargo update failed");
120            assert!(status.success());
121            Ok(())
122        }
123        Some(("summarize-benchmarks", sub_matches)) => {
124            let path = sub_matches
125                .get_one::<String>("PATH")
126                .expect("PATH is required");
127            let path = PathBuf::from(path);
128            let path = path.canonicalize().unwrap();
129            summarize_bench::process_all(path);
130            Ok(())
131        }
132        Some(("visualize-bundler-benchmarks", sub_matches)) => {
133            let path = sub_matches
134                .get_one::<String>("PATH_TO_SUMMARY_JSON")
135                .expect("PATH_TO_SUMMARY_JSON is required");
136            let bundlers: Option<FxHashSet<&str>> = sub_matches
137                .get_one::<String>("bundlers")
138                .map(|s| s.split(',').collect());
139
140            let path = PathBuf::from(path);
141            let path = path.canonicalize().unwrap();
142            visualize_bundler_bench::generate(path, bundlers)
143        }
144        _ => {
145            anyhow::bail!("Unknown command {:?}", matches.subcommand().map(|c| c.0));
146        }
147    }
148}