|
| 1 | +//! A performance benchmark publisher in Rust, modeled on the eCAL C++ sample. |
| 2 | +//! |
| 3 | +//! This will send messages of the given size in a tight loop, logging |
| 4 | +//! throughput every second. |
| 5 | +
|
| 6 | +use std::{env, sync::Arc, time::{Duration, Instant}}; |
| 7 | +use rustecal::{Ecal, EcalComponents, Configuration, TypedPublisher}; |
| 8 | +use rustecal_types_bytes::BytesMessage; |
| 9 | + |
| 10 | +// performance settings |
| 11 | +const ZERO_COPY: bool = true; |
| 12 | +const BUFFER_COUNT: u32 = 1; |
| 13 | +const ACKNOWLEDGE_TIMEOUT_MS: i32 = 50; |
| 14 | +const PAYLOAD_SIZE_DEFAULT: usize = 8 * 1024 * 1024; |
| 15 | + |
| 16 | +fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 17 | + // parse payload size from CLI (or use default) |
| 18 | + let args: Vec<String> = env::args().collect(); |
| 19 | + let mut payload_size = if args.len() > 1 { |
| 20 | + args[1].parse::<usize>().unwrap_or(PAYLOAD_SIZE_DEFAULT) |
| 21 | + } else { |
| 22 | + PAYLOAD_SIZE_DEFAULT |
| 23 | + }; |
| 24 | + if payload_size == 0 { |
| 25 | + payload_size = 1; |
| 26 | + } |
| 27 | + |
| 28 | + // log performance settings |
| 29 | + println!("Zero copy mode: {}", ZERO_COPY); |
| 30 | + println!("Number of write buffers: {}", BUFFER_COUNT); |
| 31 | + println!("Acknowledge timeout: {} ms", ACKNOWLEDGE_TIMEOUT_MS); |
| 32 | + println!("Payload size: {} bytes", payload_size); |
| 33 | + println!(); |
| 34 | + |
| 35 | + // prepare and tweak eCAL Configuration |
| 36 | + let mut cfg = Configuration::new()?; |
| 37 | + cfg.publisher.layer.shm.zero_copy_mode = ZERO_COPY as i32; |
| 38 | + cfg.publisher.layer.shm.memfile_buffer_count = BUFFER_COUNT; |
| 39 | + cfg.publisher.layer.shm.acknowledge_timeout_ms = ACKNOWLEDGE_TIMEOUT_MS as u32; |
| 40 | + |
| 41 | + // initialize eCAL with custom config |
| 42 | + Ecal::initialize( |
| 43 | + Some("performance send rust"), |
| 44 | + EcalComponents::DEFAULT, |
| 45 | + Some(&cfg), |
| 46 | + ) |
| 47 | + .expect("eCAL initialization failed"); |
| 48 | + |
| 49 | + // create payload buffer and publisher |
| 50 | + let payload_vec: Vec<u8> = vec![0u8; payload_size]; |
| 51 | + let mut payload: Arc<[u8]> = Arc::from(payload_vec); |
| 52 | + let publisher: TypedPublisher<BytesMessage> = TypedPublisher::new("Performance")?; |
| 53 | + |
| 54 | + // benchmark loop |
| 55 | + let mut msgs_sent = 0u64; |
| 56 | + let mut bytes_sent = 0u64; |
| 57 | + let mut iterations = 0u64; |
| 58 | + let mut last_log = Instant::now(); |
| 59 | + |
| 60 | + // wait for at least one subscriber to be ready |
| 61 | + while publisher.get_subscriber_count() == 0 { |
| 62 | + println!("Waiting for performance receive to start ..."); |
| 63 | + std::thread::sleep(Duration::from_millis(1000)); |
| 64 | + } |
| 65 | + |
| 66 | + // send loop |
| 67 | + while Ecal::ok() { |
| 68 | + // modify the payload for each message |
| 69 | + { |
| 70 | + let buf: &mut [u8] = Arc::make_mut(&mut payload); |
| 71 | + let chr = (msgs_sent % 9 + 48) as u8; |
| 72 | + buf[0..16].fill(chr); |
| 73 | + } |
| 74 | + |
| 75 | + let wrapped = BytesMessage { data: payload.clone() }; |
| 76 | + publisher.send(&wrapped); |
| 77 | + |
| 78 | + msgs_sent += 1; |
| 79 | + bytes_sent += payload_size as u64; |
| 80 | + iterations += 1; |
| 81 | + |
| 82 | + // every second, print statistics |
| 83 | + if iterations % 2000 == 0 { |
| 84 | + let elapsed = last_log.elapsed(); |
| 85 | + if elapsed >= Duration::from_secs(1) { |
| 86 | + let secs = elapsed.as_secs_f64(); |
| 87 | + let kbyte_s = (bytes_sent as f64 / 1024.0) / secs; |
| 88 | + let mbyte_s = kbyte_s / 1024.0; |
| 89 | + let gbyte_s = mbyte_s / 1024.0; |
| 90 | + let msg_s = (msgs_sent as f64) / secs; |
| 91 | + let latency_us = (secs * 1e6) / (msgs_sent as f64); |
| 92 | + |
| 93 | + println!("Payload size : {} kB", payload_size / 1024); |
| 94 | + println!("Throughput (kB/s) : {:.0}", kbyte_s); |
| 95 | + println!("Throughput (MB/s) : {:.2}", mbyte_s); |
| 96 | + println!("Throughput (GB/s) : {:.3}", gbyte_s); |
| 97 | + println!("Messages/s : {:.0}", msg_s); |
| 98 | + println!("Latency (µs) : {:.2}", latency_us); |
| 99 | + println!(); |
| 100 | + |
| 101 | + msgs_sent = 0; |
| 102 | + bytes_sent = 0; |
| 103 | + last_log = Instant::now(); |
| 104 | + } |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + // clean up and finalize eCAL |
| 109 | + Ecal::finalize(); |
| 110 | + Ok(()) |
| 111 | +} |
0 commit comments