fix: small bugfixes and adding n_times c functions

This commit is contained in:
cscherr 2025-08-07 18:34:45 +02:00
parent 55a1ff9445
commit 63c45edba1
Signed by: cscherrNT
GPG key ID: 8E2B45BC51A27EA7
11 changed files with 186 additions and 37 deletions

View file

@ -1,4 +1,5 @@
#include "crc32.h" #include "crc32.h"
#include <stdint.h>
const uint32_t CRC32_INIT = 0xffffffff; const uint32_t CRC32_INIT = 0xffffffff;
const uint32_t CRC32_TABLE[256] = { const uint32_t CRC32_TABLE[256] = {
@ -68,3 +69,12 @@ ChecksumCrc32 crc32_checksum(const uint8_t *data, uint32_t len) {
crc32_process(data, len, &crc32); crc32_process(data, len, &crc32);
return crc32.buf; return crc32.buf;
} }
ChecksumCrc32 crc32_checksum_n_times(uint32_t n, const uint8_t *data,
uint32_t len) {
ChecksumCrc32 buf;
for (uint32_t i = 0; i < n; i++) {
buf = crc32_checksum(data, len);
}
return buf;
}

View file

@ -19,5 +19,7 @@ Crc32 crc32_new();
void crc32_process(const uint8_t *data, size_t len, Crc32 *crc32); void crc32_process(const uint8_t *data, size_t len, Crc32 *crc32);
ChecksumCrc32 crc32_checksum(const uint8_t *data, uint32_t len); ChecksumCrc32 crc32_checksum(const uint8_t *data, uint32_t len);
ChecksumCrc32 crc32_checksum_n_times(uint32_t n, const uint8_t *data,
uint32_t len);
#endif // CRC32_H #endif // CRC32_H

View file

@ -411,3 +411,11 @@ SHA2Result sha2_256_oneshot(const uint8_t data[], const size_t len,
return res; return res;
} }
void sha2_256_oneshot_n_times(uint32_t n, const uint8_t data[],
const size_t len) {
SHA2Digest digest;
for (uint32_t i = 0; i < n; i++) {
sha2_256_oneshot(data, len, digest);
}
}

View file

@ -49,5 +49,7 @@ extern SHA2Result sha2_256_reset(SHA2Context *context);
extern SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[], extern SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[],
size_t len); size_t len);
extern SHA2Result sha2_256_result(SHA2Context *context, SHA2Digest digest); extern SHA2Result sha2_256_result(SHA2Context *context, SHA2Digest digest);
extern void sha2_256_oneshot_n_times(uint32_t n, const uint8_t data[],
const size_t len);
#endif // !SHA2_H #endif // !SHA2_H

View file

@ -7,6 +7,7 @@ unsafe extern "C" {
fn crc32_process(data: *const u8, len: u32, crc32: *mut Crc32); fn crc32_process(data: *const u8, len: u32, crc32: *mut Crc32);
fn crc32_checksum(data: *const u8, len: u32) -> ChecksumCrc32; fn crc32_checksum(data: *const u8, len: u32) -> ChecksumCrc32;
fn crc32_checksum_n_times(n: u32, data: *const u8, len: u32) -> ChecksumCrc32;
} }
#[repr(C)] #[repr(C)]
@ -19,27 +20,36 @@ impl Crc for Crc32 {
type Checksum = ChecksumCrc32; type Checksum = ChecksumCrc32;
#[inline] #[inline(always)]
fn new() -> Self { fn new() -> Self {
unsafe { crc32_new() } unsafe { crc32_new() }
} }
#[inline] #[inline(always)]
fn process(&mut self, data: &Self::Input) { fn process(&mut self, data: &Self::Input) {
unsafe { crc32_process(ref_to_ptr(data), data.len() as u32, self as *mut Self) } unsafe { crc32_process(ref_to_ptr(data), data.len() as u32, self as *mut Self) }
} }
#[inline] #[inline(always)]
fn shift_reg(&mut self) -> &mut Self::Checksum { fn shift_reg(&mut self) -> &mut Self::Checksum {
&mut self.buf &mut self.buf
} }
#[inline] #[inline(always)]
fn checksum(data: &Self::Input) -> Self::Checksum { fn checksum(data: &Self::Input) -> Self::Checksum {
unsafe { crc32_checksum(ref_to_ptr(data), data.len() as u32) } unsafe { crc32_checksum(ref_to_ptr(data), data.len() as u32) }
} }
} }
impl Crc32 {
#[inline(always)]
pub fn checksum_n_times(n: u32, data: &<Crc32 as Crc>::Input) {
unsafe {
crc32_checksum_n_times(n, ref_to_ptr(data), data.len() as u32);
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::crc::CHECK_DATA; use crate::crc::CHECK_DATA;

View file

@ -62,10 +62,12 @@ mod ffi {
context: *mut Sha2_256Context, context: *mut Sha2_256Context,
digest: *mut Digest256, digest: *mut Digest256,
) -> SHA2Outcome; ) -> SHA2Outcome;
pub fn sha2_256_oneshot_n_times(n: u32, data: *const u8, len: usize);
} }
} }
#[inline] #[inline(always)]
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> { pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
let mut digest: Digest256 = DIGEST256_EMPTY; let mut digest: Digest256 = DIGEST256_EMPTY;
let res = let res =
@ -73,23 +75,33 @@ pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Outcome> {
to_res(digest, res) to_res(digest, res)
} }
#[inline(always)]
pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Outcome> { pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Outcome> {
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) }; let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
to_res((), res) to_res((), res)
} }
#[inline(always)]
pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Outcome> { pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Outcome> {
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) }; let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
to_res((), res) to_res((), res)
} }
#[inline(always)]
pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Outcome> { pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Outcome> {
let mut digest: Digest256 = DIGEST256_EMPTY; let mut digest: Digest256 = DIGEST256_EMPTY;
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) }; let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
to_res(digest, res) to_res(digest, res)
} }
#[inline] #[inline(always)]
pub fn sha2_256_oneshot_n_times(n: u32, data: &[u8]) {
unsafe {
ffi::sha2_256_oneshot_n_times(n, ref_to_ptr(data), data.len());
};
}
#[inline(always)]
pub(crate) fn to_res<T>(if_ok: T, res: SHA2Outcome) -> Result<T, SHA2Outcome> { pub(crate) fn to_res<T>(if_ok: T, res: SHA2Outcome) -> Result<T, SHA2Outcome> {
if res == SHA2Outcome::shaSuccess { if res == SHA2Outcome::shaSuccess {
Ok(if_ok) Ok(if_ok)

View file

@ -3,4 +3,4 @@
# i can't build for x86_64 anymore, which means I can't run the unit tests. # i can't build for x86_64 anymore, which means I can't run the unit tests.
TARGET="thumbv6m-none-eabi" TARGET="thumbv6m-none-eabi"
cargo build --target $TARGET cargo build --target $TARGET
cargo run --target $TARGET $@ cargo run -r --target $TARGET $@

2
scripts/winattach.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
powershell.exe -Command "probe-rs attach C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench\target\thumbv6m-none-eabi\release\nucleo-l053r8-benches --chip STM32L053R8"

View file

@ -7,6 +7,6 @@ TARGET="thumbv6m-none-eabi"
powershell.exe -Command " powershell.exe -Command "
cd C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench; cd C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench;
cargo build --target $TARGET; cargo build -r --target $TARGET;
cargo run --target $TARGET $@ cargo run -r --target $TARGET $@
" "

View file

@ -1,4 +1,5 @@
use algorithms::crc::{Crc, Crc32 as Crc32Rust, ffi::Crc32 as Crc32C}; use algorithms::crc::{Crc, Crc32 as Crc32Rust, ffi::Crc32 as Crc32C};
use algorithms::hash::{ffi as sha2_ffi, sha2_256_oneshot};
use defmt::info; use defmt::info;
use hal::{ use hal::{
delay::Delay, delay::Delay,
@ -6,38 +7,124 @@ use hal::{
prelude::*, prelude::*,
}; };
pub type SomePin = Pin<Output<PushPull>>;
pub struct MeasurePins<'a> {
pub c: &'a mut SomePin,
pub rs: &'a mut SomePin,
pub led: &'a mut SomePin,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum MeasurementKind {
Rust,
C,
}
const RUNS: u32 = 5000;
impl MeasurePins<'_> {
pub fn set_led(&mut self, state: PinState) {
self.led.set_state(state).expect("could not set led state")
}
pub fn set_for_kind(&mut self, kind: MeasurementKind, state: PinState) {
match kind {
MeasurementKind::Rust => self.rs.set_state(state),
MeasurementKind::C => self.c.set_state(state),
}
.expect("could not set rs or c pin")
}
pub fn set_all(&mut self, state: PinState) {
self.led.set_state(state).expect("could not set led state");
self.rs.set_state(state).expect("could not set rs state");
self.c.set_state(state).expect("could not set c state");
}
}
#[inline] #[inline]
pub fn bench(pin: &mut Pin<Output<PushPull>>, delay: &mut Delay) { pub fn bench(pins: &mut MeasurePins, delay: &mut Delay) {
bench_delay(pin, delay); bench_crc(pins, delay);
bench_crc(pin, delay); bench_sha256(pins, delay);
} }
fn bench_delay(pin: &mut Pin<Output<PushPull>>, delay: &mut Delay) { fn time_exec<F>(
time_exec(pin, || delay.delay_ms(20u32)); id: &str,
time_exec(pin, || delay.delay_ms(50u32)); kind: MeasurementKind,
} pins: &mut MeasurePins,
delay: &mut Delay,
fn time_exec<F>(pin: &mut Pin<Output<PushPull>>, mut f: F) do_loop: bool,
where mut f: F,
) where
F: FnMut(), F: FnMut(),
{ {
info!("Running the requested function 50 times and returning the average"); if do_loop {
const RUNS: u32 = 50; info!("Running '{}' {} times", id, RUNS);
pin.set_high().expect("could not set pun to high"); pins.set_for_kind(kind, PinState::High);
for _ in 0..RUNS { for _ in 0..RUNS {
f();
}
pins.set_for_kind(kind, PinState::Low);
} else {
info!("Running '{}' 1 time", id);
pins.set_for_kind(kind, PinState::High);
f(); f();
pins.set_for_kind(kind, PinState::Low);
} }
pin.set_low().expect("could not set pun to low"); info!("Measurement of '{}' finished!", id);
delay.delay_ms(100_u32);
} }
fn bench_crc(pin: &mut Pin<Output<PushPull>>, delay: &mut Delay) { fn bench_crc(pins: &mut MeasurePins, delay: &mut Delay) {
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA"; const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
delay.delay_ms(50_u32); time_exec("crc32_rs", MeasurementKind::Rust, pins, delay, true, || {
time_exec(pin, || {
Crc32Rust::checksum(DATA); Crc32Rust::checksum(DATA);
}); });
delay.delay_ms(50_u32); time_exec("crc32_c_ffi", MeasurementKind::C, pins, delay, true, || {
time_exec(pin, || {
Crc32C::checksum(DATA); Crc32C::checksum(DATA);
}); });
time_exec(
"crc32_c_native",
MeasurementKind::C,
pins,
delay,
false,
|| {
Crc32C::checksum_n_times(RUNS, DATA);
},
);
}
fn bench_sha256(pins: &mut MeasurePins, delay: &mut Delay) {
const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA";
time_exec(
"sha256_rs",
MeasurementKind::Rust,
pins,
delay,
true,
|| {
sha2_256_oneshot(DATA).unwrap();
},
);
time_exec(
"sha256_c_ffi",
MeasurementKind::C,
pins,
delay,
true,
|| {
sha2_ffi::sha2_256_oneshot(DATA).unwrap();
},
);
time_exec(
"sha256_c_native",
MeasurementKind::C,
pins,
delay,
false,
|| {
sha2_ffi::sha2_256_oneshot_n_times(RUNS, DATA);
},
);
} }

View file

@ -19,6 +19,8 @@ use hal::{
rcc::Config, rcc::Config,
}; };
use crate::bench::MeasurePins;
mod bench; mod bench;
mod error_handlers; // defines a handler for evil hardfaults mod error_handlers; // defines a handler for evil hardfaults
@ -33,9 +35,17 @@ fn main() -> ! {
// Acquire the GPIOA peripheral. This also enables the clock for GPIOA in // Acquire the GPIOA peripheral. This also enables the clock for GPIOA in
// the RCC register. // the RCC register.
let gpioa = dp.GPIOA.split(&mut rcc); let gpioa = dp.GPIOA.split(&mut rcc);
let gpiob = dp.GPIOB.split(&mut rcc);
// Configure PA5 as output. // This is D4 on CN19 for the NCLEO L053R8 according to the user manual:
let mut led = gpioa.pa5.into_push_pull_output().downgrade(); // "UM1724"
let mut measurepin_0 = gpiob.pb5.into_push_pull_output().downgrade();
// This is D5 on CN19 for the NCLEO L053R8
let mut measurepin_1 = gpiob.pb4.into_push_pull_output().downgrade();
let mut led = gpioa.pa5.into_push_pull_output().downgrade(); // this is the led
measurepin_0.set_low().unwrap();
led.set_low().unwrap();
// setup timer for measuring time of benchmarks // setup timer for measuring time of benchmarks
cp.SYST.set_reload(0x00ffffff); // max cp.SYST.set_reload(0x00ffffff); // max
@ -47,13 +57,19 @@ fn main() -> ! {
debug!("Asserting that libalgorithms is correctly loaded"); debug!("Asserting that libalgorithms is correctly loaded");
assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?"); assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?");
info!("Starting the Rust vs C benchmark"); let mut measurepins = bench::MeasurePins {
bench::bench(&mut led, &mut delay); c: &mut measurepin_0,
info!("Benchmark done, nothing else to do"); rs: &mut measurepin_1,
led: &mut led,
};
info!("Starting the Rust vs C benchmark");
bench::bench(&mut measurepins, &mut delay);
info!("Benchmark done");
measurepins.set_all(PinState::Low);
led.set_high().unwrap();
#[allow(clippy::empty_loop)]
loop { loop {
delay.delay_ms(200u32); delay.delay_ms(5000u32);
} }
} }