xtask coverage-libs using criterion to better assess performance
MODIFY
Cargo.lock
Cargo.lock
@@ -614,9 +614,9 @@ dependencies = [
[[package]]
name = "itertools"
-version = "0.10.1"
+version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
@@ -1759,9 +1759,11 @@ dependencies = [
"ascii_table",
"colored",
"convert_case",
+ "criterion",
"dhat",
"humansize",
"indicatif",
+ "itertools",
"num_cpus",
"once_cell",
"pico-args",

MODIFY
xtask/Cargo.toml
xtask/Cargo.toml
@@ -34,6 +34,8 @@ timing = "0.2.3"
ansi_rgb = "0.2.0"
dhat = { version = "0.2.4", optional = true }
humansize = "1.1.1"
+itertools = "0.10.3"
+criterion = "0.3.5"
[features]
dhat-on = ["dhat"]

MODIFY
xtask/src/libs/mod.rs
xtask/src/libs/mod.rs
use ansi_rgb::{red, Foreground};
-use std::cmp::Ordering;
+use itertools::Itertools;
+use rslint_errors::Diagnostic;
use std::fmt::{Display, Formatter};
use std::ops::Add;
use std::time::Duration;
@@ -41,7 +42,7 @@ fn print_diff(before: dhat::Stats, current: dhat::Stats) -> dhat::Stats {
current
}
-pub fn get_code(lib: &str) -> Result<String, String> {
+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()
@@ -56,7 +57,7 @@ pub fn get_code(lib: &str) -> Result<String, String> {
match std::fs::read_to_string(&file) {
Ok(code) => {
println!("[{}] - using [{}]", filename.fg(red()), file.display());
- Ok(code)
+ Ok((filename.to_string(), code))
}
Err(_) => {
println!(
@@ -73,7 +74,9 @@ pub fn get_code(lib: &str) -> Result<String, String> {
let mut writer = std::fs::File::create(&file).map_err(err_to_string)?;
let _ = std::io::copy(&mut reader, &mut writer);
- std::fs::read_to_string(&file).map_err(err_to_string)
+ std::fs::read_to_string(&file)
+ .map_err(err_to_string)
+ .map(|code| (filename.to_string(), code))
}
Err(e) => Err(format!("{:?}", e)),
}
@@ -81,7 +84,7 @@ pub fn get_code(lib: &str) -> Result<String, String> {
}
}
-pub fn run(filter: String) {
+pub fn run(filter: String, criterion: bool) {
let regex = regex::Regex::new(filter.as_str()).unwrap();
let libs = include_str!("libs.txt").lines();
@@ -93,30 +96,39 @@ pub fn run(filter: String) {
let code = get_code(lib);
match code {
- Ok(code) => {
+ Ok((id, code)) => {
+ let code = code.as_str();
+
+ // Do all steps with criterion now
+ if criterion {
+ let mut criterion = criterion::Criterion::default().without_plots();
+ criterion.bench_function(lib, |b| {
+ b.iter(|| {
+ let _ = criterion::black_box(rslint_parser::parse_module(code, 0));
+ })
+ });
+ } else {
+ //warmup
+ rslint_parser::parse_module(code, 0);
+ }
+
+ let result = benchmark_lib(&id, code);
println!("Benchmark: {}", lib);
- let result = benchmark_lib(&code);
- println!("\tTokenization: {:>10?}", result.tokenization);
- println!("\tParsing: {:>10?}", result.parsing);
- println!("\tTree_sink: {:>10?}", result.tree_sink);
- println!("\t ----------");
- println!("\tTotal: {:>10?}", result.total());
+ println!("{}", result);
}
Err(e) => println!("{:?}", e),
}
}
-
- println!("end");
}
-fn benchmark_lib(code: &str) -> BenchmarkResult {
+fn benchmark_lib(id: &str, code: &str) -> BenchmarkResult {
#[cfg(feature = "dhat-on")]
println!("Start");
#[cfg(feature = "dhat-on")]
let stats = dhat::get_stats().unwrap();
let tokenizer_timer = timing::start();
- let (tokens, mut errors) = rslint_parser::tokenize(code, 0);
+ let (tokens, mut diagnostics) = rslint_parser::tokenize(code, 0);
let tok_source = rslint_parser::TokenSource::new(code, &tokens);
let tokenization_duration = tokenizer_timer.stop();
@@ -126,17 +138,15 @@ fn benchmark_lib(code: &str) -> BenchmarkResult {
let stats = print_diff(stats, dhat::get_stats().unwrap());
let parser_timer = timing::start();
- let (events, parse_errors, tokens) = {
+ let (events, parsing_diags, tokens) = {
let mut parser =
rslint_parser::Parser::new(tok_source, 0, rslint_parser::Syntax::default().module());
rslint_parser::syntax::program::parse(&mut parser);
- let (events, p_errs) = parser.finish();
- (events, p_errs, tokens)
+ let (events, parsing_diags) = parser.finish();
+ (events, parsing_diags, tokens)
};
let parse_duration = parser_timer.stop();
- errors.extend(parse_errors);
-
#[cfg(feature = "dhat-on")]
println!("Parsed");
#[cfg(feature = "dhat-on")]
@@ -144,27 +154,32 @@ fn benchmark_lib(code: &str) -> BenchmarkResult {
let tree_sink_timer = timing::start();
let mut tree_sink = rslint_parser::LosslessTreeSink::new(code, &tokens);
- rslint_parser::process(&mut tree_sink, events, errors);
- let (_green, _parse_errors) = tree_sink.finish();
+ rslint_parser::process(&mut tree_sink, events, parsing_diags);
+ let (_green, sink_diags) = tree_sink.finish();
+ let tree_sink_duration = tree_sink_timer.stop();
#[cfg(feature = "dhat-on")]
println!("Tree-Sink");
#[cfg(feature = "dhat-on")]
print_diff(stats, dhat::get_stats().unwrap());
- let tree_sink_duration = tree_sink_timer.stop();
+ diagnostics.extend(sink_diags);
BenchmarkResult {
+ id: id.to_string(),
tokenization: tokenization_duration,
parsing: parse_duration,
tree_sink: tree_sink_duration,
+ diagnostics,
}
}
-#[derive(Eq, PartialEq, Debug, Clone)]
+#[derive(Debug, Clone)]
struct BenchmarkResult {
+ id: String,
tokenization: Duration,
parsing: Duration,
tree_sink: Duration,
+ diagnostics: Vec<Diagnostic>,
}
impl BenchmarkResult {
@@ -173,27 +188,29 @@ impl BenchmarkResult {
}
}
-impl PartialOrd for BenchmarkResult {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-impl Ord for BenchmarkResult {
- fn cmp(&self, other: &Self) -> Ordering {
- self.total().cmp(&other.total())
- }
-}
-
impl Display for BenchmarkResult {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- write!(
+ let _ = writeln!(f, "\tTokenization: {:>10?}", self.tokenization);
+ let _ = writeln!(f, "\tParsing: {:>10?}", self.parsing);
+ let _ = writeln!(f, "\tTree_sink: {:>10?}", self.tree_sink);
+ let _ = writeln!(f, "\t ----------");
+ let _ = writeln!(f, "\tTotal: {:>10?}", self.total());
+
+ let _ = writeln!(
f,
- "total: {:?} (tokenization: {:?}, parsing: {:?}, tree_sink: {:?})",
+ "\t[{}] Total Time: {:?} (tokenization: {:?}, parsing: {:?}, tree_sink: {:?})",
+ self.id,
self.total(),
- &self.tokenization,
- &self.parsing,
- &self.tree_sink,
- )
+ self.tokenization,
+ self.parsing,
+ self.tree_sink,
+ );
+
+ let _ = writeln!(f, "\tDiagnostics");
+ for (severity, items) in &self.diagnostics.iter().group_by(|x| x.severity) {
+ let _ = writeln!(f, "\t\t{:?}: {}", severity, items.count());
+ }
+
+ Ok(())
}
}

MODIFY
xtask/src/main.rs
xtask/src/main.rs
@@ -65,7 +65,11 @@ fn main() -> Result<()> {
.opt_value_from_str("--filter")
.unwrap()
.unwrap_or_else(|| ".*".to_string());
- xtask::libs::run(filter);
+ let criterion: bool = args
+ .opt_value_from_str("--criterion")
+ .unwrap()
+ .unwrap_or(true);
+ xtask::libs::run(filter, criterion);
Ok(())
}
_ => {

xtask coverage-libs using criterion to better assess performance (#1902)