feat: something resembling a benchmark runs

This commit is contained in:
cscherr 2025-07-15 12:57:30 +02:00
parent cb53f81662
commit 6132a2ea61
Signed by: cscherrNT
GPG key ID: 8E2B45BC51A27EA7
7 changed files with 116 additions and 36 deletions

View file

@ -1,6 +1,20 @@
[target.thumbv6m-none-eabi]
runner = 'probe-rs run --chip STM32L053R8'
[build]
target = "thumbv6m-none-eabi"
[run]
target = "thumbv6m-none-eabi"
[check]
target = "thumbv6m-none-eabi"
[clippy]
target = "thumbv6m-none-eabi"
[test]
[alias]
arun = "run --target thumbv6m-none-eabi"
abuild = "build --target thumbv6m-none-eabi"

View file

@ -79,7 +79,9 @@
- -Wall # all warnings on
- -O3 # optimizations
- -g # debug info
- -march=armv6-m # NOTE: This is essential! It tells the compiler which target architecture to compile for!!!
# NOTE: This is essential! It tells the compiler which target architecture to compile for!!!
# Currently, this is set by build.rs with the CC_FLAGS env var
# - -march=armv6-m
:unity:
:defines:
- UNITY_EXCLUDE_FLOAT
@ -98,6 +100,7 @@
- "${1}"
- "-o"
- "${2}"
- "#{ENV['CC_FLAGS']}"
:optional: FALSE
:release_linker:
:executable: "#{ENV['AR']}"

View file

@ -38,7 +38,8 @@ fn main() {
if arch == "arm" && pw == "32" && os == "none" {
cmd.env("CC", "arm-none-eabi-gcc")
.env("AR", "arm-none-eabi-ar");
.env("AR", "arm-none-eabi-ar")
.env("CC_FLAGS", "-march=armv6-m");
} else if os == "linux" || os == "windows" {
cmd.env("CC", "gcc").env("AR", "ar");
} else {

View file

@ -4,6 +4,7 @@ unsafe extern "C" {
fn algorithms_c_is_loaded() -> i32;
}
#[inline]
pub fn ffi_is_loaded() -> bool {
unsafe { algorithms_c_is_loaded() == 1 }
}

59
src/bench.rs Normal file
View file

@ -0,0 +1,59 @@
use algorithms::crc::{Crc, Crc32 as Crc32Rust, ffi::Crc32 as Crc32C};
use defmt::info;
use hal::{
delay::Delay,
gpio::{Output, Pin, PushPull},
prelude::*,
};
macro_rules! display_results {
($name:expr, $rust_cycles:expr, $c_cycles:expr) => {
info!(
"Benchmark {}:\nRust\t: {}\nC\t: {}",
$name, $rust_cycles, $c_cycles
)
};
}
#[inline]
pub fn bench(pin: &mut Pin<Output<PushPull>>, delay: &mut Delay) {
bench_delay(pin, delay);
bench_crc(pin);
}
fn bench_delay(pin: &mut Pin<Output<PushPull>>, delay: &mut Delay) {
let short_sleep = time_exec(pin, || delay.delay_ms(20u32));
let long_sleep = time_exec(pin, || delay.delay_ms(50u32));
info!("Bench for short sleep: {}", short_sleep);
info!("Bench for long sleep: {}", long_sleep);
}
fn time_exec<F>(pin: &mut Pin<Output<PushPull>>, mut f: F) -> u32
where
F: FnMut(),
{
info!("Running the requested function 50 times and returning the average");
const RUNS: u32 = 50;
let start = cortex_m::peripheral::SYST::get_current();
pin.set_high().expect("could not set pun to high");
for _ in 0..RUNS {
f();
}
pin.set_low().expect("could not set pun to low");
let end = cortex_m::peripheral::SYST::get_current();
// the timer counts down
info!("Start: {}\nEnd: {}", start, end);
let total = start.wrapping_sub(end);
total / RUNS
}
fn bench_crc(pin: &mut Pin<Output<PushPull>>) {
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
let native = time_exec(pin, || {
Crc32Rust::checksum(DATA);
});
let c_code = time_exec(pin, || {
Crc32C::checksum(DATA);
});
display_results!("CRC", native, c_code);
}

View file

@ -1,4 +1,12 @@
use cortex_m_rt::ExceptionFrame;
use defmt::error;
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
cortex_m::asm::udf()
}
fn display_ef(ef: &ExceptionFrame) {
struct Wrapper(ExceptionFrame);

View file

@ -1,31 +1,31 @@
#![no_main]
// If rust-analyzer says it can't find `test`, you need to disable `allTargets` in it's
// configuration. This project has a `.cargo/config.toml` file that explicitly sets targets.
// See https://github.com/rust-lang/rust-analyzer/issues/3297
#![no_std]
#![no_main]
use algorithms::crc::{Crc, Crc32 as Crc32Rust, ffi::Crc32 as Crc32C};
#[cfg(not(all(target_os = "none", target_pointer_width = "32", target_arch = "arm")))]
compile_error!("This program can only be compiled for arm32 bare metal");
use defmt::{debug, error, info};
use defmt::{debug, info};
use panic_probe as _;
use defmt_rtt as _; // global logger
use cortex_m_rt::{ExceptionFrame, entry};
use hal::{pac, prelude::*, rcc::Config};
use cortex_m_rt::entry;
use hal::{
pac::{self},
prelude::*,
rcc::Config,
};
mod hardfaults; // defines a handler for evil hardfaults
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
#[defmt::panic_handler]
fn panic() -> ! {
cortex_m::asm::udf()
}
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
mod bench;
mod error_handlers; // defines a handler for evil hardfaults
#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();
let cp = cortex_m::Peripherals::take().unwrap();
let mut cp = cortex_m::Peripherals::take().unwrap();
// Configure the clock.
let mut rcc = dp.RCC.freeze(Config::hsi16());
@ -35,31 +35,25 @@ fn main() -> ! {
let gpioa = dp.GPIOA.split(&mut rcc);
// Configure PA5 as output.
let mut led = gpioa.pa5.into_push_pull_output();
let mut led = gpioa.pa5.into_push_pull_output().downgrade();
// setup timer for measuring time of benchmarks
cp.SYST.set_reload(0x00ffffff); // max
cp.SYST.clear_current();
cp.SYST.enable_counter();
// Get the delay provider.
let mut delay = cp.SYST.delay(rcc.clocks);
debug!("Asserting that libalgorithms is correctly loaded");
assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?");
let mut crc;
info!("Starting the Rust vs C benchmark");
bench::bench(&mut led, &mut delay);
info!("Benchmark done, nothing else to do");
#[allow(clippy::never_loop)]
loop {
led.set_high().unwrap();
delay.delay_ms(500_u16);
info!("Calculating CRCs for: {:?}", DATA);
debug!("Now calculating Crc32Rust...");
crc = Crc32Rust::checksum(DATA);
info!("CRC (Rust): {:08x}", crc);
debug!("Now calculating Crc32C...");
crc = Crc32C::checksum(DATA);
info!("CRC (C) : {:08x}", crc);
led.set_low().unwrap();
delay.delay_ms(500_u16);
#[allow(clippy::empty_loop)]
loop {
delay.delay_ms(200u32);
}
}