diff --git a/crates/algorithms/algorithms-c/src/crc/crc32.c b/crates/algorithms/algorithms-c/src/crc/crc32.c index cfcd686..b65b749 100755 --- a/crates/algorithms/algorithms-c/src/crc/crc32.c +++ b/crates/algorithms/algorithms-c/src/crc/crc32.c @@ -1,4 +1,5 @@ #include "crc32.h" +#include const uint32_t CRC32_INIT = 0xffffffff; 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); 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; +} diff --git a/crates/algorithms/algorithms-c/src/crc/crc32.h b/crates/algorithms/algorithms-c/src/crc/crc32.h index ecc60ae..6be5b19 100755 --- a/crates/algorithms/algorithms-c/src/crc/crc32.h +++ b/crates/algorithms/algorithms-c/src/crc/crc32.h @@ -19,5 +19,7 @@ Crc32 crc32_new(); 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_n_times(uint32_t n, const uint8_t *data, + uint32_t len); #endif // CRC32_H diff --git a/crates/algorithms/algorithms-c/src/hash/sha2.c b/crates/algorithms/algorithms-c/src/hash/sha2.c index 0ee0ace..8082aab 100644 --- a/crates/algorithms/algorithms-c/src/hash/sha2.c +++ b/crates/algorithms/algorithms-c/src/hash/sha2.c @@ -411,3 +411,11 @@ SHA2Result sha2_256_oneshot(const uint8_t data[], const size_t len, 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); + } +} diff --git a/crates/algorithms/algorithms-c/src/hash/sha2.h b/crates/algorithms/algorithms-c/src/hash/sha2.h index 900e099..decaf10 100644 --- a/crates/algorithms/algorithms-c/src/hash/sha2.h +++ b/crates/algorithms/algorithms-c/src/hash/sha2.h @@ -49,5 +49,7 @@ extern SHA2Result sha2_256_reset(SHA2Context *context); extern SHA2Result sha2_256_input(SHA2Context *context, const uint8_t data[], size_t len); 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 diff --git a/crates/algorithms/src/crc/ffi/crc32.rs b/crates/algorithms/src/crc/ffi/crc32.rs index 5ba85c0..5896d11 100755 --- a/crates/algorithms/src/crc/ffi/crc32.rs +++ b/crates/algorithms/src/crc/ffi/crc32.rs @@ -7,6 +7,7 @@ unsafe extern "C" { fn crc32_process(data: *const u8, len: u32, crc32: *mut Crc32); fn crc32_checksum(data: *const u8, len: u32) -> ChecksumCrc32; + fn crc32_checksum_n_times(n: u32, data: *const u8, len: u32) -> ChecksumCrc32; } #[repr(C)] @@ -19,27 +20,36 @@ impl Crc for Crc32 { type Checksum = ChecksumCrc32; - #[inline] + #[inline(always)] fn new() -> Self { unsafe { crc32_new() } } - #[inline] + #[inline(always)] fn process(&mut self, data: &Self::Input) { 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 { &mut self.buf } - #[inline] + #[inline(always)] fn checksum(data: &Self::Input) -> Self::Checksum { unsafe { crc32_checksum(ref_to_ptr(data), data.len() as u32) } } } +impl Crc32 { + #[inline(always)] + pub fn checksum_n_times(n: u32, data: &::Input) { + unsafe { + crc32_checksum_n_times(n, ref_to_ptr(data), data.len() as u32); + } + } +} + #[cfg(test)] mod tests { use crate::crc::CHECK_DATA; diff --git a/crates/algorithms/src/hash/ffi/sha2.rs b/crates/algorithms/src/hash/ffi/sha2.rs index 35de1ce..c455165 100644 --- a/crates/algorithms/src/hash/ffi/sha2.rs +++ b/crates/algorithms/src/hash/ffi/sha2.rs @@ -62,10 +62,12 @@ mod ffi { context: *mut Sha2_256Context, digest: *mut Digest256, ) -> 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 { let mut digest: Digest256 = DIGEST256_EMPTY; let res = @@ -73,23 +75,33 @@ pub fn sha2_256_oneshot(data: &[u8]) -> Result { to_res(digest, res) } +#[inline(always)] pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Outcome> { let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) }; to_res((), res) } +#[inline(always)] 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()) }; to_res((), res) } +#[inline(always)] pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result { let mut digest: Digest256 = DIGEST256_EMPTY; let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) }; 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(if_ok: T, res: SHA2Outcome) -> Result { if res == SHA2Outcome::shaSuccess { Ok(if_ok) diff --git a/scripts/flash.sh b/scripts/flash.sh index 0d41f22..2b90a19 100755 --- a/scripts/flash.sh +++ b/scripts/flash.sh @@ -3,4 +3,4 @@ # i can't build for x86_64 anymore, which means I can't run the unit tests. TARGET="thumbv6m-none-eabi" cargo build --target $TARGET -cargo run --target $TARGET $@ +cargo run -r --target $TARGET $@ diff --git a/scripts/winattach.sh b/scripts/winattach.sh new file mode 100755 index 0000000..471a39a --- /dev/null +++ b/scripts/winattach.sh @@ -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" diff --git a/scripts/winflash.sh b/scripts/winflash.sh index 75f3435..24dbcda 100755 --- a/scripts/winflash.sh +++ b/scripts/winflash.sh @@ -7,6 +7,6 @@ TARGET="thumbv6m-none-eabi" powershell.exe -Command " cd C:\SVN\nt\BA\trunk\Studium\Christoph_Scherr\system\Implementation\crcbench; -cargo build --target $TARGET; -cargo run --target $TARGET $@ +cargo build -r --target $TARGET; +cargo run -r --target $TARGET $@ " diff --git a/src/bench.rs b/src/bench.rs index f00abf3..f45e483 100644 --- a/src/bench.rs +++ b/src/bench.rs @@ -1,4 +1,5 @@ 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 hal::{ delay::Delay, @@ -6,38 +7,124 @@ use hal::{ prelude::*, }; +pub type SomePin = Pin>; + +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] -pub fn bench(pin: &mut Pin>, delay: &mut Delay) { - bench_delay(pin, delay); - bench_crc(pin, delay); +pub fn bench(pins: &mut MeasurePins, delay: &mut Delay) { + bench_crc(pins, delay); + bench_sha256(pins, delay); } -fn bench_delay(pin: &mut Pin>, delay: &mut Delay) { - time_exec(pin, || delay.delay_ms(20u32)); - time_exec(pin, || delay.delay_ms(50u32)); -} - -fn time_exec(pin: &mut Pin>, mut f: F) -where +fn time_exec( + id: &str, + kind: MeasurementKind, + pins: &mut MeasurePins, + delay: &mut Delay, + do_loop: bool, + mut f: F, +) where F: FnMut(), { - info!("Running the requested function 50 times and returning the average"); - const RUNS: u32 = 50; - pin.set_high().expect("could not set pun to high"); - for _ in 0..RUNS { + if do_loop { + info!("Running '{}' {} times", id, RUNS); + pins.set_for_kind(kind, PinState::High); + 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(); + 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>, delay: &mut Delay) { +fn bench_crc(pins: &mut MeasurePins, delay: &mut Delay) { const DATA: &[u8] = b"hello world AAAAAAAAAAAAAAAAAAAAAAA"; - delay.delay_ms(50_u32); - time_exec(pin, || { + time_exec("crc32_rs", MeasurementKind::Rust, pins, delay, true, || { Crc32Rust::checksum(DATA); }); - delay.delay_ms(50_u32); - time_exec(pin, || { + time_exec("crc32_c_ffi", MeasurementKind::C, pins, delay, true, || { 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); + }, + ); } diff --git a/src/main.rs b/src/main.rs index a5d31a4..a096fd9 100755 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,8 @@ use hal::{ rcc::Config, }; +use crate::bench::MeasurePins; + mod bench; 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 // the RCC register. let gpioa = dp.GPIOA.split(&mut rcc); + let gpiob = dp.GPIOB.split(&mut rcc); - // Configure PA5 as output. - let mut led = gpioa.pa5.into_push_pull_output().downgrade(); + // This is D4 on CN19 for the NCLEO L053R8 according to the user manual: + // "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 cp.SYST.set_reload(0x00ffffff); // max @@ -47,13 +57,19 @@ fn main() -> ! { debug!("Asserting that libalgorithms is correctly loaded"); assert!(algorithms::ffi_is_loaded(), "ffi is not loaded?"); - info!("Starting the Rust vs C benchmark"); - bench::bench(&mut led, &mut delay); - info!("Benchmark done, nothing else to do"); + let mut measurepins = bench::MeasurePins { + c: &mut measurepin_0, + 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 { - delay.delay_ms(200u32); + delay.delay_ms(5000u32); } }