Skip to content

Commit 07c484a

Browse files
[CPP-30]Backend CPU Usage benchmark.
1 parent d941875 commit 07c484a

File tree

11 files changed

+178
-31
lines changed

11 files changed

+178
-31
lines changed

.gitattributes

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
src/main/fbs/* linguist-vendored
22
src/main/nuitka/* linguist-vendored
3-
console_backend/benches/data/2020-06-25-BayLoop/STEP_v2_SR_L2_OSR_staging_10Hz_GNSSOnly_AmotechL2/25-190704.sbp filter=lfs diff=lfs merge=lfs -text
3+
console_backend/benches/data/**/**/*.sbp filter=lfs diff=lfs merge=lfs -text

.github/workflows/main.yml

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,65 @@ on:
99
pull_request:
1010

1111
jobs:
12+
backend_bench:
13+
name: Backend Benchmarks
14+
strategy:
15+
matrix:
16+
os:
17+
- ubuntu-20.04
18+
# - macos-10.15
19+
# - windows-2019
20+
runs-on: ${{ matrix.os }}
21+
defaults:
22+
run:
23+
shell: bash -l {0}
24+
steps:
25+
26+
- name: Checkout source
27+
uses: actions/checkout@v2
28+
with:
29+
submodules: recursive
30+
ssh-key: ${{ secrets.SSH_KEY }}
31+
32+
- name: Install ${{ runner.os }} Dependencies.
33+
run: |
34+
if [ "$RUNNER_OS" == "Linux" ]; then
35+
sudo apt-get install -y capnproto
36+
elif [ "$RUNNER_OS" == "macOS" ]; then
37+
brew install capnp
38+
elif [ "$RUNNER_OS" == "Windows" ]; then
39+
choco install capnproto
40+
fi
41+
42+
- name: Install stable Rust
43+
uses: actions-rs/toolchain@v1
44+
with:
45+
toolchain: nightly
46+
override: true
47+
- uses: davidB/rust-cargo-make@v1
48+
with:
49+
version: '0.32.11'
50+
- name: Cache conda
51+
uses: actions/cache@v1
52+
env:
53+
CACHE_NUMBER: 0
54+
with:
55+
path: ~/conda_pkgs_dir
56+
key:
57+
${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{
58+
hashFiles('conda.yml') }}
59+
- uses: conda-incubator/setup-miniconda@v2
60+
with:
61+
activate-environment: console_pp
62+
environment-file: conda.yml
63+
use-only-tar-bz2: true
64+
- name: Poetry Install
65+
run: |
66+
conda activate console_pp
67+
python -m poetry install
68+
- name: Run Benchmarks
69+
run: |
70+
cargo make benches
1271
checks:
1372
runs-on: ubuntu-latest
1473
defaults:
@@ -21,10 +80,10 @@ jobs:
2180
submodules: recursive
2281
ssh-key: ${{ secrets.SSH_KEY }}
2382

24-
- name: Install stable Rust
83+
- name: Install nightly Rust
2584
uses: actions-rs/toolchain@v1
2685
with:
27-
toolchain: stable
86+
toolchain: nightly
2887
override: true
2988
components: rustfmt, clippy
3089
- uses: davidB/rust-cargo-make@v1
@@ -107,10 +166,10 @@ jobs:
107166
choco install capnproto nsis
108167
fi
109168
110-
- name: Install stable Rust
169+
- name: Install nightly Rust
111170
uses: actions-rs/toolchain@v1
112171
with:
113-
toolchain: stable
172+
toolchain: nightly
114173
override: true
115174
components: rustfmt, clippy
116175
- uses: davidB/rust-cargo-make@v1

Makefile.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,14 @@ dependencies = ["python-type-check", "rust-type-check"]
160160
[tasks.tests]
161161
dependencies = ["rust-tests"]
162162

163+
[tasks.bench-rust]
164+
dependencies = ["copy-capnp", "generate-resources"]
165+
command = "cargo"
166+
args = ["bench", "--all-features", "--", "--verbose", "--noplot"]
167+
168+
[tasks.bench-rust-validate]
169+
command = "python"
170+
args = ["console_backend/benches/benchmarks.py"]
171+
172+
[tasks.benches]
173+
dependencies = ["bench-rust", "bench-rust-validate"]

console_backend/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ sbp = { git = "https://github.com/swift-nav/libsbp.git", rev = "986af3f35033a720
1212
ordered-float = "2.0"
1313
ndarray = "0.14.0"
1414
glob = "0.3.0"
15-
criterion = "0.3"
15+
criterion = "0.3.4"
1616

1717
[[bench]]
18-
name = "tests"
18+
name = "benches"
1919
harness = false
2020

2121

@@ -25,6 +25,7 @@ capnpc = "0.14"
2525
[lib]
2626
name = "console_backend"
2727
crate-type = ["cdylib", "lib"]
28+
bench = false
2829

2930
[features]
3031
default = []

console_backend/benches/tests.rs renamed to console_backend/benches/benches.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,42 @@
11
#![feature(test)]
2+
#![allow(unused_imports)]
3+
use criterion::{criterion_group, criterion_main, Criterion};
24
use glob::glob;
3-
use std::{fs, path::Path, sync::mpsc, time, thread};
5+
use std::{fs, path::Path, sync::mpsc, thread, time};
46

5-
6-
const TEST_DATA_DIRECTORY: &str = "./benches/data/";
77
extern crate console_backend;
88
use console_backend::process_messages;
99

10-
use criterion::{black_box, criterion_group, criterion_main, Criterion};
10+
const TEST_DATA_DIRECTORY: &str = "./benches/data/";
11+
const BENCHMARK_TIME_LIMIT: u64 = 15000;
12+
const BENCHMARK_SAMPLE_SIZE: usize = 50;
1113

1214
pub fn criterion_benchmark(c: &mut Criterion) {
1315
let glob_pattern = Path::new(&TEST_DATA_DIRECTORY).join("**/**/*.sbp");
1416
let glob_pattern = glob_pattern.to_str().unwrap();
15-
17+
1618
for ele in glob(glob_pattern).expect("failed to read glob") {
17-
1819
match ele {
1920
Ok(filename) => {
2021
println!("{:?}", filename.display());
2122
let file_in_name = filename.to_str().unwrap();
2223
let mut group = c.benchmark_group("proc_messages");
23-
group.sample_size(10);
24-
group.bench_function("RPM", |b| b.iter(|| run_process_messages(file_in_name.clone())));
25-
24+
group.measurement_time(time::Duration::from_millis(BENCHMARK_TIME_LIMIT));
25+
group.sample_size(BENCHMARK_SAMPLE_SIZE);
26+
group.bench_function("RPM", |b| b.iter(|| run_process_messages(file_in_name)));
2627
}
2728
Err(e) => println!("{:?}", e),
2829
}
2930
}
30-
3131
}
3232
fn run_process_messages(file_in_name: &str) {
3333
let (client_send, client_recv) = mpsc::channel::<Vec<u8>>();
34-
thread::spawn(move|| {
35-
loop {
36-
if let Err(_) = client_recv.recv() {
37-
}
38-
thread::sleep(time::Duration::from_millis(1));
39-
}
40-
34+
thread::spawn(move || loop {
35+
if client_recv.recv().is_err() {}
4136
});
4237
let messages = sbp::iter_messages(Box::new(fs::File::open(file_in_name).unwrap()));
43-
process_messages::process_messages(messages, client_send)
38+
process_messages::process_messages(messages, client_send);
4439
}
45-
4640

4741
#[cfg(feature = "criterion_bench")]
4842
criterion_group!(benches, criterion_benchmark);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import json
2+
import sys
3+
from typing import Any, Optional
4+
5+
WINDOWS = "win32"
6+
MACOS = "darwin"
7+
LINUX = "linux"
8+
NAME = "name"
9+
FILE_PATH = "file_path"
10+
KEY_LOCATION = "key_location"
11+
EXPECTED = "expected"
12+
ERROR_MARGIN_FRAC = "error_margin_frac"
13+
14+
RUST_BENCHMARKS = {
15+
WINDOWS: [
16+
{
17+
NAME: "2020-09-04-BayLoop/M8L_BDS_ADR431_nativeODO_Swiftlets_OSR_prod_10Hz_AmotechL2/04-155800",
18+
FILE_PATH: "target/criterion/proc_messages/RPM/base/estimates.json",
19+
KEY_LOCATION: "mean.point_estimate",
20+
EXPECTED: 27500000,
21+
ERROR_MARGIN_FRAC: 0.05,
22+
},
23+
],
24+
MACOS: [
25+
{
26+
NAME: "2020-09-04-BayLoop/M8L_BDS_ADR431_nativeODO_Swiftlets_OSR_prod_10Hz_AmotechL2/04-155800",
27+
FILE_PATH: "target/criterion/proc_messages/RPM/base/estimates.json",
28+
KEY_LOCATION: "mean.point_estimate",
29+
EXPECTED: 27500000,
30+
ERROR_MARGIN_FRAC: 0.05,
31+
},
32+
],
33+
LINUX: [
34+
{
35+
NAME: "2020-09-04-BayLoop/M8L_BDS_ADR431_nativeODO_Swiftlets_OSR_prod_10Hz_AmotechL2/04-155800",
36+
FILE_PATH: "target/criterion/proc_messages/RPM/base/estimates.json",
37+
KEY_LOCATION: "mean.point_estimate",
38+
EXPECTED: 27500000,
39+
ERROR_MARGIN_FRAC: 0.05,
40+
},
41+
],
42+
}
43+
44+
45+
def get_nested_key(nested_dict: dict, key_path: str) -> Optional[Any]:
46+
"""Extract a key in nested dict/json assuming stringified key_path.
47+
48+
Assuming `key_path` format: <key1>.<key2>.<key3>
49+
50+
Args:
51+
nested_dict (dict): The nested dictionary containing the desired key.
52+
key_path (str): The stringified nested dictionary key location.
53+
54+
Returns:
55+
Optional[Any]: A value corresponding to the key_path in the nested dictionary.
56+
Otherwise, None if not found.
57+
"""
58+
current_key, *next_keys = key_path.split(".", 1)
59+
value = nested_dict.get(current_key, None)
60+
return value if not isinstance(value, dict) and len(next_keys) != 1 else get_nested_key(value, next_keys[0])
61+
62+
63+
def run_validate_benchmarks():
64+
"""Runner for a suite of benchmark validations.
65+
"""
66+
for os_, benchmarks in RUST_BENCHMARKS.items():
67+
if os_ != sys.platform:
68+
continue
69+
for bench in benchmarks:
70+
with open(bench[FILE_PATH]) as fileo:
71+
bench_result = json.load(fileo)
72+
bench_value = get_nested_key(bench_result, bench[KEY_LOCATION])
73+
assert bench_value is not None, f"Test:{bench[NAME]} retrieved bench value None."
74+
assert bench_value - bench[EXPECTED] <= bench[ERROR_MARGIN_FRAC] * bench[EXPECTED], (
75+
f"Test:{bench[NAME]} Bench Value:{bench_value} not within "
76+
f"{bench[ERROR_MARGIN_FRAC]} of {bench[EXPECTED]}."
77+
)
78+
print(f"PASS - {os_}:{bench[NAME]} MARGIN={bench_value - bench[EXPECTED]}")
79+
80+
81+
if __name__ == "__main__":
82+
run_validate_benchmarks()

console_backend/benches/data/2020-06-25-BayLoop/STEP_v2_SR_L2_OSR_staging_10Hz_GNSSOnly_AmotechL2/25-190704_chopped.sbp

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:2d30c1c7ee9bcfae65ddf74d86ef4f2b66df08bee054ef9c468ff2b327f6bd36
3+
size 289

console_backend/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
pub mod server;
21
pub mod process_messages;
2+
pub mod server;
33
pub mod console_backend_capnp {
44
include!(concat!(env!("OUT_DIR"), "/console_backend_capnp.rs"));
55
}

console_backend/src/process_messages.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
use capnp::message::Builder;
22
use capnp::serialize;
3-
use ndarray::{s, Array, Array2, Axis};
43
use ordered_float::*;
54
use sbp::messages::SBP;
6-
use std::collections::HashMap;
75
use std::sync::mpsc;
86

97
use crate::console_backend_capnp as m;
@@ -165,4 +163,4 @@ pub fn process_messages(
165163
}
166164
}
167165
}
168-
}
166+
}

0 commit comments

Comments
 (0)