Skip to content

Commit

Permalink
Add parse CLI to benchmark PGO
Browse files Browse the repository at this point in the history
  • Loading branch information
valeneiko committed May 18, 2024
1 parent c9d84af commit f9ea40d
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 0 deletions.
5 changes: 5 additions & 0 deletions crates/oxc_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ name = "oxlint"
path = "src/lint/main.rs"
test = false

[[bin]]
name = "oxparse"
path = "src/parse/main.rs"
test = false

[[bin]]
name = "oxformat"
path = "src/format/main.rs"
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod command;
mod format;
mod lint;
mod parse;
mod result;
mod runner;
mod walk;
Expand All @@ -9,6 +10,7 @@ pub use crate::{
command::*,
format::FormatRunner,
lint::LintRunner,
parse::ParseRunner,
result::{CliRunResult, LintResult},
runner::Runner,
};
26 changes: 26 additions & 0 deletions crates/oxc_cli/src/parse/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#![cfg(not(miri))] // Miri does not support custom allocators

#[cfg(not(debug_assertions))]
#[cfg(not(target_env = "msvc"))]
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[cfg(not(debug_assertions))]
#[cfg(target_os = "windows")]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

use oxc_cli::{CliRunResult, ParseRunner, Runner};

fn main() -> CliRunResult {
init_miette();

let command = oxc_cli::format_command().fallback_to_usage().run();
command.handle_threads();
ParseRunner::new(command.format_options).run()
}

// Initialize the data which relies on `is_atty` system calls so they don't block subsequent threads.
fn init_miette() {
miette::set_hook(Box::new(|_| Box::new(miette::MietteHandlerOpts::new().build()))).unwrap();
}
78 changes: 78 additions & 0 deletions crates/oxc_cli/src/parse/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::{env, path::Path};

use ignore::gitignore::Gitignore;
use oxc_allocator::Allocator;
use oxc_parser::Parser;
use oxc_span::{SourceType, VALID_EXTENSIONS};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};

use crate::{
command::FormatOptions,
result::{CliRunResult, ParseResult},
walk::{Extensions, Walk},
Runner,
};

pub struct ParseRunner {
options: FormatOptions,
}

impl Runner for ParseRunner {
type Options = FormatOptions;

fn new(options: Self::Options) -> Self {
Self { options }
}

fn run(self) -> CliRunResult {
let FormatOptions { paths, ignore_options, .. } = self.options;

let mut paths = paths;

// The ignore crate whitelists explicit paths, but priority
// should be given to the ignore file. Many users lint
// automatically and pass a list of changed files explicitly.
// To accommodate this, unless `--no-ignore` is passed,
// pre-filter the paths.
if !paths.is_empty() && !ignore_options.no_ignore {
let (ignore, _err) = Gitignore::new(&ignore_options.ignore_path);
paths.retain(|p| if p.is_dir() { true } else { !ignore.matched(p, false).is_ignore() });
}

if paths.is_empty() {
if let Ok(cwd) = env::current_dir() {
paths.push(cwd);
} else {
return CliRunResult::InvalidOptions {
message: "Failed to get current working directory.".to_string(),
};
}
}

let extensions = VALID_EXTENSIONS.to_vec();

let now = std::time::Instant::now();

let paths =
Walk::new(&paths, &ignore_options).with_extensions(Extensions(extensions)).paths();

let total_duration = paths.par_iter().map(|path| Self::parse(path)).sum();

CliRunResult::ParseResult(ParseResult {
parse_duration: total_duration,
duration: now.elapsed(),
number_of_files: paths.len(),
})
}
}

impl ParseRunner {
fn parse(path: &Path) -> std::time::Duration {
let source_text = std::fs::read_to_string(path).unwrap();
let allocator = Allocator::default();
let source_type = SourceType::from_path(path).unwrap();
let now = std::time::Instant::now();
let _ = Parser::new(&allocator, &source_text, source_type).preserve_parens(false).parse();
now.elapsed()
}
}
18 changes: 18 additions & 0 deletions crates/oxc_cli/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub enum CliRunResult {
PathNotFound { paths: Vec<PathBuf> },
LintResult(LintResult),
FormatResult(FormatResult),
ParseResult(ParseResult),
TypeCheckResult { duration: Duration, number_of_diagnostics: usize },
}

Expand All @@ -32,6 +33,13 @@ pub struct FormatResult {
pub number_of_files: usize,
}

#[derive(Debug)]
pub struct ParseResult {
pub parse_duration: Duration,
pub duration: Duration,
pub number_of_files: usize,
}

impl Termination for CliRunResult {
fn report(self) -> ExitCode {
match self {
Expand Down Expand Up @@ -95,6 +103,16 @@ impl Termination for CliRunResult {
);
ExitCode::from(0)
}
Self::ParseResult(ParseResult { parse_duration, duration, number_of_files }) => {
let threads = rayon::current_num_threads();
let time = Self::get_execution_time(&duration);
let parse_time = Self::get_execution_time(&parse_duration);
let s = if number_of_files == 1 { "" } else { "s" };
println!(
"Finished in {time} ({parse_time}) on {number_of_files} file{s} using {threads} threads."
);
ExitCode::from(0)
}
Self::TypeCheckResult { duration, number_of_diagnostics } => {
let time = Self::get_execution_time(&duration);
println!("Finished in {time}.");
Expand Down
30 changes: 30 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/usr/bin/env -S just --justfile

set windows-shell := ["pwsh.exe", "-c"]

_default:
@just --list -u

Expand Down Expand Up @@ -140,3 +142,31 @@ upgrade:
clone-submodule dir url sha:
git clone --depth=1 {{url}} {{dir}} || true
cd {{dir}} && git fetch origin {{sha}} && git reset --hard {{sha}}


ecosystem_dir := "C:/source/ecosystem"
oxlint_bin := "C:/source/rust/oxc/target/release/oxparse.exe"
threads := "12"

pgo_data_dir := "C:/source/rust/oxc/pgo-data"
llvm_profdata_bin := "~/.rustup/toolchains/1.78.0-x86_64-pc-windows-msvc/lib/rustlib/x86_64-pc-windows-msvc/bin/llvm-profdata.exe"

build-pgo:
just build-pgo-init
just oxlint_bin=C:/source/rust/oxc/target/x86_64-pc-windows-msvc/release/oxparse.exe ecosystem
{{llvm_profdata_bin}} merge -o {{pgo_data_dir}}/merged.profdata {{pgo_data_dir}}
just build-pgo-final

build-pgo-init $RUSTFLAGS="-Cprofile-generate=C:/source/rust/oxc/pgo-data":
cargo build --release -p oxc_cli --bin oxparse --features allocator --target x86_64-pc-windows-msvc

build-pgo-final $RUSTFLAGS="-Cprofile-use=C:/source/rust/oxc/pgo-data/merged.profdata -Cllvm-args=-pgo-warn-missing-function":
cargo build --release -p oxc_cli --bin oxparse --features allocator --target x86_64-pc-windows-msvc

ecosystem:
cd "{{ecosystem_dir}}/DefinitelyTyped" && {{oxlint_bin}} --threads={{threads}}
cd "{{ecosystem_dir}}/affine" && {{oxlint_bin}} --threads={{threads}}
cd "{{ecosystem_dir}}/napi-rs" && {{oxlint_bin}} --threads={{threads}} --ignore-path=.oxlintignore
cd "{{ecosystem_dir}}/preact" && {{oxlint_bin}} --threads={{threads}} oxlint src test debug compat hooks test-utils
cd "{{ecosystem_dir}}/rolldown" && {{oxlint_bin}} --threads={{threads}} --ignore-path=.oxlintignore
cd "{{ecosystem_dir}}/vscode" && {{oxlint_bin}} --threads={{threads}}

0 comments on commit f9ea40d

Please sign in to comment.