Benchmark rust in CI with iai, not criterion (#1937)
* Rename cargo-criterion to cargo-bench * Use iai not criterion in CI We want to benchmark the KCL parser and tokenizer to make sure we don't accidentally slow them down. Generally Rust projects use Criterion to benchmark code. Criterion runs your functions a few thousand times to get reliable wall-clock measurements. This is good for locally benchmarking but bad for benchmarking in CI. Why? Because in CI, you're running a container on some shared VM, so wall-clock time might have a lot of interference from noisy neighbours. Also, your benchmarks take a long time to run and eat up paid CI minutes. A better approach for benchmarking in CI is to just count the number of CPU instructions executed. This correlates with wall-clock time, but it only needs to run the function once, so it takes much less time. It also isn't changed by any noisy neighbours running on the same VM or hardware. This PR adds a new benchmark suite which counts instructions using `iai`, from the creator of criterion. He says iai and criterion complement each other nicely. We can run criterion locally and run iai in CI. * Update image in markdown docs
This commit is contained in:
@ -7,23 +7,23 @@ on:
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-criterion.yml
|
||||
- .github/workflows/cargo-bench.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
- '**/rust-toolchain.toml'
|
||||
- .github/workflows/cargo-criterion.yml
|
||||
- .github/workflows/cargo-bench.yml
|
||||
workflow_dispatch:
|
||||
permissions: read-all
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
name: cargo criterion
|
||||
name: cargo bench
|
||||
jobs:
|
||||
cargocriterion:
|
||||
name: cargo criterion
|
||||
cargo-bench:
|
||||
name: Benchmark with iai
|
||||
runs-on: ubuntu-latest-8-cores
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@ -31,10 +31,12 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
cargo install cargo-criterion
|
||||
sudo apt update
|
||||
sudo apt install -y valgrind
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2.6.1
|
||||
- name: Benchmark kcl library
|
||||
shell: bash
|
||||
run: |-
|
||||
cd src/wasm-lib/kcl; cargo criterion
|
||||
cd src/wasm-lib/kcl; cargo bench -- iai
|
||||
|
File diff suppressed because one or more lines are too long
7
src/wasm-lib/Cargo.lock
generated
7
src/wasm-lib/Cargo.lock
generated
@ -1646,6 +1646,12 @@ dependencies = [
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iai"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.60"
|
||||
@ -1877,6 +1883,7 @@ dependencies = [
|
||||
"expectorate",
|
||||
"futures",
|
||||
"gltf-json",
|
||||
"iai",
|
||||
"image",
|
||||
"insta",
|
||||
"itertools 0.12.1",
|
||||
|
@ -71,6 +71,7 @@ base64 = "0.22.0"
|
||||
convert_case = "0.6.0"
|
||||
criterion = "0.5.1"
|
||||
expectorate = "1.1.0"
|
||||
iai = "0.1"
|
||||
image = "0.24.9"
|
||||
insta = { version = "1.38.0", features = ["json"] }
|
||||
itertools = "0.12.1"
|
||||
@ -79,5 +80,9 @@ tokio = { version = "1.37.0", features = ["rt-multi-thread", "macros", "time"] }
|
||||
twenty-twenty = "0.7.0"
|
||||
|
||||
[[bench]]
|
||||
name = "compiler_benchmark"
|
||||
name = "compiler_benchmark_criterion"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "compiler_benchmark_iai"
|
||||
harness = false
|
||||
|
50
src/wasm-lib/kcl/benches/compiler_benchmark_iai.rs
Normal file
50
src/wasm-lib/kcl/benches/compiler_benchmark_iai.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use iai::black_box;
|
||||
|
||||
pub fn parse(program: &str) {
|
||||
let tokens = kcl_lib::token::lexer(program);
|
||||
let tok = tokens.clone();
|
||||
let parser = kcl_lib::parser::Parser::new(tok.clone());
|
||||
black_box(parser.ast().unwrap());
|
||||
}
|
||||
|
||||
fn lex_kitt() {
|
||||
black_box(kcl_lib::token::lexer(KITT_PROGRAM));
|
||||
}
|
||||
fn lex_pipes() {
|
||||
black_box(kcl_lib::token::lexer(PIPES_PROGRAM));
|
||||
}
|
||||
fn lex_cube() {
|
||||
black_box(kcl_lib::token::lexer(CUBE_PROGRAM));
|
||||
}
|
||||
fn lex_math() {
|
||||
black_box(kcl_lib::token::lexer(MATH_PROGRAM));
|
||||
}
|
||||
|
||||
fn parse_kitt() {
|
||||
parse(KITT_PROGRAM)
|
||||
}
|
||||
fn parse_pipes() {
|
||||
parse(PIPES_PROGRAM)
|
||||
}
|
||||
fn parse_cube() {
|
||||
parse(CUBE_PROGRAM)
|
||||
}
|
||||
fn parse_math() {
|
||||
parse(MATH_PROGRAM)
|
||||
}
|
||||
|
||||
iai::main! {
|
||||
lex_kitt,
|
||||
lex_pipes,
|
||||
lex_cube,
|
||||
lex_math,
|
||||
parse_kitt,
|
||||
parse_pipes,
|
||||
parse_cube,
|
||||
parse_math,
|
||||
}
|
||||
|
||||
const KITT_PROGRAM: &str = include_str!("../../tests/executor/inputs/kittycad_svg.kcl");
|
||||
const PIPES_PROGRAM: &str = include_str!("../../tests/executor/inputs/pipes_on_pipes.kcl");
|
||||
const CUBE_PROGRAM: &str = include_str!("../../tests/executor/inputs/cube.kcl");
|
||||
const MATH_PROGRAM: &str = include_str!("../../tests/executor/inputs/math.kcl");
|
Binary file not shown.
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 95 KiB |
Reference in New Issue
Block a user