Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add: benchmark for ping1d and ping360 on CI #62

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,71 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./target/doc

bench:
needs: build
if: ${{ github.repository_owner == 'bluerobotics' }}
runs-on: raspbian-armv7-kernel-5.10.33
steps:
- uses: actions/checkout@master
- uses: dtolnay/rust-toolchain@stable
- name: Rust | Cache
uses: Swatinem/rust-cache@v2
with:
prefix-key: "rust-cache"
shared-key: "benchmark"
- name: Get previous benchmark data
run: |
echo "Fetching gh-pages branch"
git fetch origin gh-pages

echo "Checking out gh-pages branch"
git checkout gh-pages

if [ ! -d "cache" ]; then
echo "Cache folder does not exist, creating it"
mkdir cache
fi

echo "Copying data file from gh-pages to cache"
cp dev/cache/benchmark-data.json cache/benchmark-data.json || { echo "Failed to copy data file" ; exit 1; }

echo "Checking out current preivous branch"
git checkout -
- name: Cargo Bench
run: cargo bench --jobs 1 --bench bench -- --output-format bencher | tee output.txt || { echo "Benchmark failed"; exit 1; }
- name: Compare results & store cached results
uses: benchmark-action/[email protected]
with:
tool: 'cargo'
output-file-path: output.txt
summary-always: true
alert-threshold: "130%"
fail-on-alert: true
external-data-json-path: ./cache/benchmark-data.json
skip-fetch-gh-pages: "true"
- name: Update data file
if: ${{ github.ref == 'refs/heads/master' }}
run: |
git config user.name "GitHub Actions Bot"
git config user.email "[email protected]"

git fetch origin gh-pages

git checkout gh-pages

if [ ! -d "dev/cache" ]; then
echo "Cache folder does not exist, creating it"
mkdir -p dev/cache
fi

cp cache/benchmark-data.json dev/cache/benchmark-data.json

tree cache

git add dev/cache/benchmark-data.json
git commit -m "Update benchmark-data file"
git push origin gh-pages

deploy:
needs: build
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ serde_bytes = "0.11"
[dev-dependencies]
tracing-test = "0.2.4"
udp-stream = "0.0.12"
criterion = { version = "0.5.1", features = ["html_reports", "async_tokio"] }

[build-dependencies]
convert_case = "0.6.0"
Expand All @@ -38,3 +39,7 @@ serde_json = "1.0.64"
[features]
local_runner = []
default = ["serde"]

[[bench]]
name = "bench"
harness = false
209 changes: 209 additions & 0 deletions benches/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use bluerobotics_ping::{
device::{Ping1D, Ping360, PingDevice},
message::MessageInfo,
ping1d::{self, ProfileStruct},
Messages,
};
use criterion::black_box;
use criterion::{criterion_group, criterion_main, Criterion};
use std::time::Instant;
use std::{net::SocketAddr, str::FromStr};
use tokio::runtime::Runtime;
use tokio_serial::{Error, SerialPort, SerialPortBuilderExt};
use udp_stream::UdpStream;

fn rt() -> Runtime {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.worker_threads(1)
.thread_name("criterion-tokio-rt")
.build()
.unwrap()
}

async fn create_ping1d_usb() -> Ping1D {
let port = tokio_serial::new("/dev/ttyUSB0".to_string(), 115200)
.open_native_async()
.map_err(|e| {
eprintln!("Error opening serial port: {}", e);
e
})
.unwrap();
port.clear(tokio_serial::ClearBuffer::All).unwrap();

Ping1D::new(port)
}

async fn create_ping360_udp() -> Ping360 {
let socket_addr = SocketAddr::from_str(&format!("192.168.1.197:12345"))
.map_err(|e| {
eprintln!("Error parsing UDP address: {}", e);
e
})
.unwrap();
let port = UdpStream::connect(socket_addr)
.await
.map_err(|e| {
eprintln!("Error connecting to UDP socket: {}", e);
e
})
.unwrap();
Ping360::new(port)
}

async fn receive_10_profiles(
mut subscribed: tokio::sync::broadcast::Receiver<bluerobotics_ping::message::ProtocolMessage>,
) -> Result<(), Error> {
let mut profile_struct_vector: Vec<ProfileStruct> = Vec::new();
for _i in 1..10 {
let received = subscribed.recv().await;

match received {
Ok(msg) => {
if msg.message_id == bluerobotics_ping::ping1d::ProfileStruct::id() {
match Messages::try_from(&msg) {
Ok(Messages::Ping1D(ping1d::Messages::Profile(answer))) => {
profile_struct_vector.push(answer)
}
_ => panic!(),
}
}
}
Err(_e) => {
panic!()
}
}
}
Ok(())
}

fn ping1d_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("Ping1D");
group.sample_size(10); // Reduced sample size
group.measurement_time(std::time::Duration::from_secs(60)); // Increased measurement time

macro_rules! bench {
($bench_fn:ident($($arg:tt)*)) => {
group.bench_function(stringify!($bench_fn), move |b| {
b.to_async(rt()).iter_custom(|iters| async move {
let ping1d = create_ping1d_usb().await;

ping1d.continuous_stop(bluerobotics_ping::ping1d::ProfileStruct::id())
.await
.unwrap();

tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;

let mut total_duration = std::time::Duration::new(0, 0);
for _i in 0..iters {
let start = Instant::now();
let result = black_box(ping1d.$bench_fn($($arg)*).await);
total_duration += start.elapsed();
result.unwrap();
}
total_duration
})
});
}
}

// Get Methods
bench!(profile());
// bench!(ping_interval());
// bench!(transmit_duration());
// bench!(range());
// bench!(speed_of_sound());
// bench!(firmware_version());
// bench!(mode_auto());
// bench!(distance_simple());
// bench!(pcb_temperature());
// bench!(ping_enable());
// bench!(general_info());
// bench!(distance());
// bench!(processor_temperature());
// bench!(voltage_5());
// bench!(gain_setting());
// bench!(device_id());

// Custom - receive 10 profile packages
group.bench_function("Receive 10 profiles", move |b| {
b.to_async(rt()).iter_custom(|iters| async move {
let ping1d = create_ping1d_usb().await;

ping1d
.continuous_start(bluerobotics_ping::ping1d::ProfileStruct::id())
.await
.unwrap();

let mut total_duration = std::time::Duration::new(0, 0);
for _i in 0..iters {
let start = Instant::now();
black_box(receive_10_profiles(ping1d.subscribe()).await.unwrap());
total_duration += start.elapsed();
}

ping1d
.continuous_stop(bluerobotics_ping::ping1d::ProfileStruct::id())
.await
.unwrap();

total_duration
})
});

group.finish();
}

fn ping360_benchmark(c: &mut Criterion) {
let mut group = c.benchmark_group("Ping360");
group.sample_size(10);
group.measurement_time(std::time::Duration::from_secs(60));

macro_rules! bench360 {
($bench_fn:ident($($arg:tt)*)) => {
group.bench_function(stringify!($bench_fn), move |b| {
b.to_async(rt()).iter_custom(|iters| async move {
let ping360 = create_ping360_udp().await;
ping360.reset(0,0).await.unwrap();

let mut total_duration = std::time::Duration::new(0, 0);
for _i in 0..iters {
let start = Instant::now();
let result = black_box(ping360.$bench_fn($($arg)*).await);
total_duration += start.elapsed();
result.unwrap();
}
total_duration
})
});
}
}

let mode: u8 = 1;
let gain_setting: u8 = 0;
let angle: u16 = 360;
let transmit_duration: u16 = 7;
let sample_period: u16 = 80;
let transmit_frequency: u16 = 700;
let number_of_samples: u16 = 1200;
let transmit: u8 = 1;

// Get Methods
bench360!(transducer(
mode,
gain_setting,
angle,
transmit_duration,
sample_period,
transmit_frequency,
number_of_samples,
transmit,
0,
));
bench360!(motor_off());

group.finish();
}

criterion_group!(benches, ping1d_benchmark, ping360_benchmark);
criterion_main!(benches);
Loading