From 19ff54e66eaccfb79ea2b47baddb89cd6e76c22d Mon Sep 17 00:00:00 2001 From: folex <0xdxdy@gmail.com> Date: Thu, 5 Nov 2020 16:50:09 +0300 Subject: [PATCH] Parser benchmarks (#16) --- Cargo.lock | 7 +- crates/air-parser/Cargo.toml | 9 +- crates/air-parser/benches/parser.rs | 130 +++++++++++++++++++++++++ crates/air-parser/src/lalrpop/tests.rs | 2 +- crates/air-parser/src/lib.rs | 15 +-- 5 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 crates/air-parser/benches/parser.rs diff --git a/Cargo.lock b/Cargo.lock index fe9ca29f..27024ae1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ version = "0.1.0" dependencies = [ "codespan", "codespan-reporting", + "criterion", "fstrings", "lalrpop", "lalrpop-util", @@ -991,8 +992,7 @@ dependencies = [ [[package]] name = "lalrpop" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60fb56191fb8ed5311597e5750debe6779c9fdb487dbaa5ff302592897d7a2c8" +source = "git+https://github.com/fluencelabs/lalrpop#149e77b301828392b09da5c2ba634fd19ce3a3a7" dependencies = [ "ascii-canvas", "atty", @@ -1016,8 +1016,7 @@ dependencies = [ [[package]] name = "lalrpop-util" version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6771161eff561647fad8bb7e745e002c304864fb8f436b52b30acda51fca4408" +source = "git+https://github.com/fluencelabs/lalrpop#149e77b301828392b09da5c2ba634fd19ce3a3a7" dependencies = [ "regex", ] diff --git a/crates/air-parser/Cargo.toml b/crates/air-parser/Cargo.toml index bb947066..6049afd4 100644 --- a/crates/air-parser/Cargo.toml +++ b/crates/air-parser/Cargo.toml @@ -5,13 +5,18 @@ authors = ["Fluence Labs"] edition = "2018" [build-dependencies] -lalrpop = { version = "0.19.1", features = ["lexer"] } +lalrpop = { git = "https://github.com/fluencelabs/lalrpop", version = "0.19.1", features = ["lexer"] } [dependencies] -lalrpop-util = { version = "0.19.1", features = ["lexer"] } +lalrpop-util = { git = "https://github.com/fluencelabs/lalrpop", version = "0.19.1", features = ["lexer"] } regex = "1.4.1" codespan = "0.9.5" codespan-reporting = "0.9.5" [dev-dependencies] fstrings = "0.2.3" +criterion = "0.3.3" + +[[bench]] +name = "parser" +harness = false diff --git a/crates/air-parser/benches/parser.rs b/crates/air-parser/benches/parser.rs new file mode 100644 index 00000000..ceda006b --- /dev/null +++ b/crates/air-parser/benches/parser.rs @@ -0,0 +1,130 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#[macro_use] +extern crate fstrings; + +use std::rc::Rc; + +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::Criterion; + +use air_parser::InstrParser; + +const SOURCE_CODE_BAD: &'static str = r#"(seq + (seq + (call node ("identity" "") [] void[]) + (call provider (service_id "{fname}") {arg_list} result) + ) + (seq + (call node ("identity" "") [] void[]) + (call "{LOCAL_VM}" ("return" "result") [result] void[]) + ) + )"#; + +const SOURCE_CODE_GOOD: &'static str = r#" + (seq + (seq + (call node ("identity" "") [] void[]) + (call provider (service_id "fname") [arg list] result) + ) + (seq + (call node ("identity" "") [] void[]) + (call "local_vm" ("return" "result") [result] void[]) + ) + )"#; + +#[cfg(test)] +mod gen { + use crate::SOURCE_CODE_GOOD; + + pub fn seq(left: &str, right: &str) -> String { + f!(r"(seq {left} {right})") + } + + pub fn deep_seq(mut depth: usize) -> String { + let mut instr = SOURCE_CODE_GOOD.to_string(); + loop { + depth -= 1; + if depth == 0 { + break; + } + instr = seq(&instr, &instr) + } + + instr + } +} + +fn bench_creation(c: &mut Criterion) { + c.bench_function("create_parser", move |b| b.iter(move || InstrParser::new())); +} + +fn parse(c: &mut Criterion) { + let parser = Rc::new(InstrParser::new()); + c.bench_function( + format!("parse {} bytes", SOURCE_CODE_GOOD.len()).as_str(), + move |b| { + let parser = parser.clone(); + b.iter(move || { + parser + .clone() + .parse(&mut Vec::new(), SOURCE_CODE_GOOD) + .expect("success") + }) + }, + ); +} + +fn parse_to_fail(c: &mut Criterion) { + let parser = Rc::new(InstrParser::new()); + c.bench_function( + format!("parse {} bytes to FAIL", SOURCE_CODE_BAD.len()).as_str(), + move |b| { + let parser = parser.clone(); + b.iter(move || parser.clone().parse(&mut Vec::new(), SOURCE_CODE_BAD)) + }, + ); +} + +fn parse_deep(c: &mut Criterion) { + let parser = Rc::new(InstrParser::new()); + let source_code: Vec<_> = (1..10).map(gen::deep_seq).collect(); + let index: Vec<_> = source_code + .iter() + .enumerate() + .map(|(i, code)| (i, code.len())) + .collect(); + + c.bench_function_over_inputs( + "parse generated script", + move |b, (i, _)| { + let parser = parser.clone(); + let code = &source_code[*i]; + b.iter(move || { + parser + .clone() + .parse(&mut Vec::new(), code) + .expect("success") + }); + }, + index, + ); +} + +criterion_group!(benches, bench_creation, parse, parse_to_fail, parse_deep); +criterion_main!(benches); diff --git a/crates/air-parser/src/lalrpop/tests.rs b/crates/air-parser/src/lalrpop/tests.rs index d4151ee4..fa41ef33 100644 --- a/crates/air-parser/src/lalrpop/tests.rs +++ b/crates/air-parser/src/lalrpop/tests.rs @@ -23,7 +23,7 @@ use Value::*; use fstrings::f; fn parse(source_code: &str) -> Instruction { - *super::parse(source_code).expect("parsing failed") + *crate::parse(source_code).expect("parsing failed") } #[test] diff --git a/crates/air-parser/src/lib.rs b/crates/air-parser/src/lib.rs index 4ab68609..e79e9657 100644 --- a/crates/air-parser/src/lib.rs +++ b/crates/air-parser/src/lib.rs @@ -4,17 +4,18 @@ #[macro_use] extern crate fstrings; -pub mod ast; mod lalrpop { #[cfg(test)] - mod tests; + pub mod tests; // aqua is auto-generated, so exclude it from `cargo fmt -- --check` #[rustfmt::skip] - mod aqua; - mod parser; - - pub use parser::parse; + pub mod aqua; + pub mod parser; } +pub mod ast; -pub use lalrpop::parse; +pub use lalrpop::parser::parse; + +// #[cfg(test)] +pub use lalrpop::aqua::InstrParser;