mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
refactor(benchmark): make the benchmark run faster by using variable measurement time
This commit is contained in:
parent
8dfb50642d
commit
cb886d8a36
3 changed files with 118 additions and 85 deletions
|
|
@ -1,39 +1,59 @@
|
|||
use std::{path::PathBuf, str::FromStr};
|
||||
use std::{path::PathBuf, str::FromStr, time::Duration};
|
||||
|
||||
pub struct Code {
|
||||
pub url: &'static str,
|
||||
pub file_name: String,
|
||||
pub source_text: String,
|
||||
pub measurement_time: Duration,
|
||||
}
|
||||
|
||||
impl Code {
|
||||
/// # Errors
|
||||
pub fn new(measurement_seconds: u64, url: &'static str) -> Result<Self, String> {
|
||||
let (file_name, source_text) = Self::get_source_text(url)?;
|
||||
Ok(Self {
|
||||
url,
|
||||
file_name,
|
||||
source_text,
|
||||
measurement_time: Duration::new(measurement_seconds, 0),
|
||||
})
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// # Panics
|
||||
pub fn get_source_text(lib: &str) -> Result<(String, String), String> {
|
||||
let url = url::Url::from_str(lib).map_err(err_to_string)?;
|
||||
|
||||
let segments = url.path_segments().ok_or_else(|| "lib url has no segments".to_string())?;
|
||||
|
||||
let filename = segments.last().ok_or_else(|| "lib url has no segments".to_string())?;
|
||||
|
||||
let mut file = PathBuf::from_str("target").map_err(err_to_string)?;
|
||||
file.push(filename);
|
||||
|
||||
if let Ok(code) = std::fs::read_to_string(&file) {
|
||||
println!("[{filename}] - using [{}]", file.display());
|
||||
Ok((filename.to_string(), code))
|
||||
} else {
|
||||
println!("[{filename}] - Downloading [{lib}] to [{}]", file.display());
|
||||
match ureq::get(lib).call() {
|
||||
Ok(response) => {
|
||||
let mut reader = response.into_reader();
|
||||
|
||||
let _drop = std::fs::remove_file(&file);
|
||||
let mut writer = std::fs::File::create(&file).map_err(err_to_string)?;
|
||||
let _drop = std::io::copy(&mut reader, &mut writer);
|
||||
|
||||
std::fs::read_to_string(&file)
|
||||
.map_err(err_to_string)
|
||||
.map(|code| (filename.to_string(), code))
|
||||
}
|
||||
Err(e) => Err(format!("{e:?}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn err_to_string<E: std::fmt::Debug>(e: E) -> String {
|
||||
format!("{e:?}")
|
||||
}
|
||||
|
||||
/// # Errors
|
||||
/// # Panics
|
||||
pub fn get_code(lib: &str) -> Result<(String, String), String> {
|
||||
let url = url::Url::from_str(lib).map_err(err_to_string)?;
|
||||
|
||||
let segments = url.path_segments().ok_or_else(|| "lib url has no segments".to_string())?;
|
||||
|
||||
let filename = segments.last().ok_or_else(|| "lib url has no segments".to_string())?;
|
||||
|
||||
let mut file = PathBuf::from_str("target").map_err(err_to_string)?;
|
||||
file.push(filename);
|
||||
|
||||
if let Ok(code) = std::fs::read_to_string(&file) {
|
||||
println!("[{filename}] - using [{}]", file.display());
|
||||
Ok((filename.to_string(), code))
|
||||
} else {
|
||||
println!("[{filename}] - Downloading [{lib}] to [{}]", file.display());
|
||||
match ureq::get(lib).call() {
|
||||
Ok(response) => {
|
||||
let mut reader = response.into_reader();
|
||||
|
||||
let _drop = std::fs::remove_file(&file);
|
||||
let mut writer = std::fs::File::create(&file).map_err(err_to_string)?;
|
||||
let _drop = std::io::copy(&mut reader, &mut writer);
|
||||
|
||||
std::fs::read_to_string(&file)
|
||||
.map_err(err_to_string)
|
||||
.map(|code| (filename.to_string(), code))
|
||||
}
|
||||
Err(e) => Err(format!("{e:?}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
https://cdn.jsdelivr.net/npm/pdfjs-dist@2.12.313/build/pdf.js
|
||||
https://cdn.jsdelivr.net/npm/lodash@4.17.0/lodash.js
|
||||
https://cdn.jsdelivr.net/npm/d3@7.1.1/dist/d3.js
|
||||
https://cdn.jsdelivr.net/npm/typescript@4.6.2/lib/typescript.js
|
||||
https://cdn.jsdelivr.net/npm/babylonjs@4.2.1/babylon.max.js
|
||||
|
|
@ -1,19 +1,5 @@
|
|||
#![cfg(not(miri))] // Miri does not support custom allocators
|
||||
|
||||
use std::{
|
||||
hint::black_box, // See: `https://rust-lang.github.io/rfcs/2360-bench-black-box.html`
|
||||
rc::Rc,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use criterion::{BenchmarkId, Criterion, Throughput};
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::SourceType;
|
||||
use oxc_benchmark::get_code;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_semantic::SemanticBuilder;
|
||||
use pico_args::Arguments;
|
||||
|
||||
//
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
#[global_allocator]
|
||||
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
||||
|
|
@ -22,30 +8,49 @@ static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
|
|||
#[global_allocator]
|
||||
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
|
||||
|
||||
use std::{
|
||||
hint::black_box, // See: `https://rust-lang.github.io/rfcs/2360-bench-black-box.html`
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use criterion::{BenchmarkId, Criterion, Throughput};
|
||||
use oxc_allocator::Allocator;
|
||||
use oxc_ast::SourceType;
|
||||
use oxc_benchmark::Code;
|
||||
use oxc_parser::Parser;
|
||||
use oxc_semantic::SemanticBuilder;
|
||||
use pico_args::Arguments;
|
||||
|
||||
/// # Errors
|
||||
/// # Panics
|
||||
pub fn main() -> Result<(), &'static str> {
|
||||
pub fn main() -> Result<(), String> {
|
||||
let codes = vec![
|
||||
Code::new(5, "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.12.313/build/pdf.js")?,
|
||||
Code::new(5, "https://cdn.jsdelivr.net/npm/lodash@4.17.0/lodash.js")?,
|
||||
Code::new(5, "https://cdn.jsdelivr.net/npm/d3@7.1.1/dist/d3.js")?,
|
||||
Code::new(10, "https://cdn.jsdelivr.net/npm/typescript@4.6.2/lib/typescript.js")?,
|
||||
Code::new(10, "https://cdn.jsdelivr.net/npm/babylonjs@4.2.1/babylon.max.js")?,
|
||||
];
|
||||
|
||||
let mut args = Arguments::from_env();
|
||||
|
||||
let baseline: Option<String> = args.opt_value_from_str("--save-baseline").unwrap();
|
||||
|
||||
let mut criterion = Criterion::default().without_plots().measurement_time(Duration::new(20, 0));
|
||||
|
||||
let mut criterion = Criterion::default().without_plots();
|
||||
if let Some(ref baseline) = baseline {
|
||||
criterion = criterion.save_baseline(baseline.to_string());
|
||||
}
|
||||
|
||||
let codes =
|
||||
include_str!("./libs.txt").lines().map(|lib| get_code(lib).unwrap()).collect::<Vec<_>>();
|
||||
|
||||
// Check files
|
||||
for (_, code) in &codes {
|
||||
for code in &codes {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, black_box(code), SourceType::default()).parse();
|
||||
let ret =
|
||||
Parser::new(&allocator, black_box(&code.source_text), SourceType::default()).parse();
|
||||
if !ret.errors.is_empty() {
|
||||
for error in &ret.errors {
|
||||
println!("{error:?}");
|
||||
}
|
||||
return Err("Parse Failed.");
|
||||
return Err("Parse Failed.".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,33 +60,46 @@ pub fn main() -> Result<(), &'static str> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn bench_parser(criterion: &mut Criterion, codes: &[(String, String)]) {
|
||||
fn bench_parser(criterion: &mut Criterion, codes: &[Code]) {
|
||||
let mut group = criterion.benchmark_group("parser");
|
||||
for (id, code) in codes {
|
||||
group.throughput(Throughput::Bytes(code.len() as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(id), &code, |b, code| {
|
||||
let allocator = Allocator::default();
|
||||
b.iter(|| {
|
||||
let _drop = Parser::new(&allocator, black_box(code), SourceType::default()).parse();
|
||||
});
|
||||
});
|
||||
for code in codes {
|
||||
group.throughput(Throughput::Bytes(code.source_text.len() as u64));
|
||||
group.measurement_time(code.measurement_time);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(&code.file_name),
|
||||
&code.source_text,
|
||||
|b, source_text| {
|
||||
let allocator = Allocator::default();
|
||||
b.iter(|| {
|
||||
let _drop =
|
||||
Parser::new(&allocator, black_box(source_text), SourceType::default())
|
||||
.parse();
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
fn bench_semantic(criterion: &mut Criterion, codes: &[(String, String)]) {
|
||||
fn bench_semantic(criterion: &mut Criterion, codes: &[Code]) {
|
||||
let mut group = criterion.benchmark_group("semantic");
|
||||
for (id, code) in codes {
|
||||
group.throughput(Throughput::Bytes(code.len() as u64));
|
||||
group.bench_with_input(BenchmarkId::from_parameter(id), &code, |b, code| {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, black_box(code), SourceType::default()).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let trivias = Rc::new(ret.trivias);
|
||||
b.iter(|| {
|
||||
let _semantic = SemanticBuilder::new().build(black_box(program), trivias.clone());
|
||||
});
|
||||
});
|
||||
for code in codes {
|
||||
group.throughput(Throughput::Bytes(code.source_text.len() as u64));
|
||||
group.measurement_time(code.measurement_time);
|
||||
group.bench_with_input(
|
||||
BenchmarkId::from_parameter(&code.file_name),
|
||||
&code.source_text,
|
||||
|b, source_text| {
|
||||
let allocator = Allocator::default();
|
||||
let ret = Parser::new(&allocator, source_text, SourceType::default()).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let trivias = Rc::new(ret.trivias);
|
||||
b.iter(|| {
|
||||
let _semantic =
|
||||
SemanticBuilder::new().build(black_box(program), trivias.clone());
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue