Skip to content

Commit f4f6b5c

Browse files
committed
Criterion calibration sync performance bench
1 parent 2e19f21 commit f4f6b5c

File tree

17 files changed

+541
-183
lines changed

17 files changed

+541
-183
lines changed

Cargo.toml

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "xcp"
3-
version = "0.3.0"
3+
version = "0.1.0"
44
edition = "2021"
55
resolver = "2"
66
rust-version = "1.76"
@@ -158,6 +158,14 @@ image = "0.25.2"
158158
prost = "0.13.1"
159159
prost-types = "0.13.1"
160160

161+
# benchmarking
162+
criterion = { version = "0.4", features = ["html_reports"] }
163+
164+
[[bench]]
165+
name = "xcp_benchmark"
166+
harness = false
167+
168+
161169
[build-dependencies]
162170
cc = "1.0"
163171
build-info-build = "0.0.36"

benches/xcp_benchmark.rs

+276
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
3+
#[allow(unused_imports)]
4+
use log::{debug, error, info, trace, warn};
5+
use std::{
6+
fmt::Debug,
7+
sync::{Arc, Mutex},
8+
thread,
9+
time::Duration,
10+
};
11+
12+
use serde::{Deserialize, Serialize};
13+
use xcp::*;
14+
use xcp_type_description::prelude::*;
15+
16+
use xcp_client::xcp_client::*;
17+
18+
//-----------------------------------------------------------------------------
19+
// Calibration parameters
20+
21+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, XcpTypeDescription)]
22+
struct CalPage {
23+
#[type_description(comment = "Amplitude value")]
24+
#[type_description(min = "0")]
25+
#[type_description(max = "10000.0")]
26+
ampl: f64,
27+
28+
delay: u32,
29+
}
30+
31+
const CAL_PAGE: CalPage = CalPage { ampl: 123.456, delay: 100 };
32+
33+
//-----------------------------------------------------------------------------
34+
// XCP client
35+
36+
// Handle incomming DAQ data
37+
38+
#[derive(Debug, Clone, Copy)]
39+
struct DaqDecoder {
40+
event_count: u64,
41+
event_lost_count: u64,
42+
}
43+
44+
impl DaqDecoder {
45+
pub fn new() -> DaqDecoder {
46+
DaqDecoder { event_count: 0, event_lost_count: 0 }
47+
}
48+
}
49+
50+
impl XcpDaqDecoder for DaqDecoder {
51+
fn decode(&mut self, lost: u32, _daq: u16, _odt: u8, _time: u32, _data: &[u8]) {
52+
self.event_count += 1;
53+
self.event_lost_count += lost as u64;
54+
}
55+
}
56+
57+
// Handle incomming SERV_TEXT data
58+
59+
#[derive(Debug, Clone, Copy)]
60+
struct ServTextDecoder;
61+
62+
impl ServTextDecoder {
63+
pub fn new() -> ServTextDecoder {
64+
ServTextDecoder {}
65+
}
66+
}
67+
68+
impl XcpTextDecoder for ServTextDecoder {
69+
fn decode(&self, _data: &[u8]) {}
70+
}
71+
72+
#[derive(Debug, Clone, Copy, PartialEq)]
73+
enum ClientMode {
74+
Wait,
75+
Calibrate,
76+
Measure,
77+
Stop,
78+
}
79+
80+
// XCP client
81+
async fn xcp_client(dest_addr: std::net::SocketAddr, local_addr: std::net::SocketAddr, mode: Arc<parking_lot::Mutex<ClientMode>>) -> Result<(), Box<dyn std::error::Error>> {
82+
println!("XCP client ");
83+
84+
// Create xcp_client
85+
let mut xcp_client = XcpClient::new(dest_addr, local_addr);
86+
87+
// Connect to the XCP server
88+
info!("XCP Connect");
89+
let daq_decoder = Arc::new(Mutex::new(DaqDecoder::new()));
90+
xcp_client.connect(Arc::clone(&daq_decoder), ServTextDecoder::new()).await?;
91+
92+
// Upload A2L file
93+
info!("Load A2L file to file xcp_lite.a2l");
94+
xcp_client.load_a2l("xcp_lite.a2l", true, true).await?;
95+
96+
// Create a calibration object for CalPage.ampl
97+
info!("Create calibration object CalPage.ampl");
98+
let ampl = xcp_client
99+
.create_calibration_object("CalPage.ampl")
100+
.await
101+
.expect("Failed to create calibration object for CalPage.ampl");
102+
let v = xcp_client.get_value_f64(ampl);
103+
info!("CalPage.ampl = {}", v);
104+
105+
let mut last_mode = *mode.lock();
106+
107+
loop {
108+
let current_mode = *mode.lock();
109+
let first = current_mode != last_mode;
110+
111+
if first {
112+
match current_mode {
113+
ClientMode::Measure => {
114+
info!("Start Measurement");
115+
// Measurement of signal
116+
xcp_client.create_measurement_object("signal").expect("measurmeent signal not found");
117+
// Measure start
118+
xcp_client.start_measurement().await.expect("could not start measurement");
119+
}
120+
121+
ClientMode::Calibrate => {
122+
info!("Start Calibration");
123+
}
124+
125+
_ => {}
126+
}
127+
128+
info!("Client mode switched from {:?} to {:?}", last_mode, current_mode);
129+
}
130+
131+
last_mode = current_mode;
132+
133+
match current_mode {
134+
ClientMode::Wait => {
135+
tokio::time::sleep(Duration::from_micros(1000)).await;
136+
}
137+
138+
ClientMode::Measure => {
139+
tokio::time::sleep(Duration::from_micros(1000)).await;
140+
}
141+
142+
ClientMode::Calibrate => {
143+
// Do calibrations
144+
const LOOPS: usize = 10000;
145+
let mut v = 0.0;
146+
let mut t: u128 = 0;
147+
for _ in 0..LOOPS {
148+
v += 0.1;
149+
trace!("CalPage.ampl = {}", v);
150+
let t0 = tokio::time::Instant::now();
151+
xcp_client.set_value_f64(ampl, v).await.unwrap();
152+
t += t0.elapsed().as_nanos();
153+
}
154+
let t_avg = ((t / LOOPS as u128) as f64) / 1000.0; // us
155+
info!("Calibration performance, avg duration = {:.1} us ", t_avg);
156+
if t_avg > 100.0 {
157+
warn!("Calibration operation duration average time exceeds 100us!")
158+
};
159+
}
160+
ClientMode::Stop => {
161+
info!("Stop");
162+
break;
163+
}
164+
}
165+
}
166+
167+
// Stop measurement
168+
xcp_client.stop_measurement().await?;
169+
let event_count = daq_decoder.lock().unwrap().event_count;
170+
let event_lost_count = daq_decoder.lock().unwrap().event_lost_count;
171+
info!(
172+
"Measurement stopped, event count = {}, lost event count = {} - {:.1}%",
173+
event_count,
174+
event_lost_count,
175+
event_lost_count as f64 / event_count as f64 * 100.0
176+
);
177+
178+
// Disconnect
179+
xcp_client.disconnect().await?;
180+
181+
Ok(())
182+
}
183+
184+
fn xcp_client_task(mode: Arc<parking_lot::Mutex<ClientMode>>) {
185+
let dest_addr: std::net::SocketAddr = "127.0.0.1:5555".parse().unwrap();
186+
let local_addr: std::net::SocketAddr = "0.0.0.0:0".parse().unwrap();
187+
info!("dest_addr: {}", dest_addr);
188+
info!("local_addr: {}", local_addr);
189+
190+
let runtime = tokio::runtime::Runtime::new().unwrap();
191+
runtime.block_on(xcp_client(dest_addr, local_addr, mode)).unwrap()
192+
}
193+
194+
//-----------------------------------------------------------------------------
195+
196+
fn xcp_benchmark(c: &mut Criterion) {
197+
println!("XCP Benchmark");
198+
199+
env_logger::Builder::new().filter_level(log::LevelFilter::Info).init();
200+
201+
// Start XCP server
202+
let xcp = XcpBuilder::new("xcp_benchmark")
203+
.set_log_level(XcpLogLevel::Info)
204+
.set_epk("EPK_")
205+
.start_server(XcpTransportLayer::Udp, [127, 0, 0, 1], 5555)
206+
.unwrap();
207+
208+
// Create a calibration segment
209+
let cal_page = xcp.create_calseg("CalPage", &CAL_PAGE, true);
210+
211+
// Measurement signal
212+
let mut signal: f64 = 0.0;
213+
214+
// Register a measurement event and bind it to the counter signal
215+
let event = daq_create_event!("mainloop");
216+
daq_register!(signal, event);
217+
218+
// Wait a moment
219+
thread::sleep(Duration::from_millis(100));
220+
221+
// Start XCP client task
222+
let mode = Arc::new(parking_lot::Mutex::new(ClientMode::Wait));
223+
let mode_cloned = mode.clone();
224+
let xcp_client_task = thread::spawn(move || {
225+
xcp_client_task(mode_cloned);
226+
});
227+
228+
// Wait a moment
229+
thread::sleep(Duration::from_millis(100));
230+
231+
// Bench calibration segment sync
232+
// Bench calibration operations (in xcp_client_task)
233+
info!("Start calibration bench");
234+
*mode.lock() = ClientMode::Calibrate;
235+
let mut count = 0;
236+
c.bench_function("sync", |b| {
237+
b.iter(|| {
238+
if cal_page.sync() {
239+
count += 1;
240+
}
241+
})
242+
});
243+
*mode.lock() = ClientMode::Wait;
244+
info!("Calibration bench done, changes observed: {}", count);
245+
246+
// Wait a moment
247+
thread::sleep(Duration::from_millis(100));
248+
249+
// Bench measurement trigger
250+
info!("Start measurement bench");
251+
*mode.lock() = ClientMode::Measure;
252+
c.bench_function("trigger", |b| {
253+
b.iter(|| {
254+
signal += 1.0;
255+
event.trigger()
256+
})
257+
});
258+
*mode.lock() = ClientMode::Wait;
259+
thread::sleep(Duration::from_millis(100));
260+
info!("Measurement bench done, count = {}", signal);
261+
262+
// Wait a moment
263+
thread::sleep(Duration::from_millis(100));
264+
265+
// Wait for stop of XCP client
266+
*mode.lock() = ClientMode::Stop;
267+
xcp_client_task.join().unwrap();
268+
info!("Client stopped");
269+
270+
// Stop XCP server
271+
xcp.stop_server();
272+
info!("Server stopped");
273+
}
274+
275+
criterion_group!(benches, xcp_benchmark);
276+
criterion_main!(benches);

examples/hello_xcp/src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn main() {
4545
.start_server(XcpTransportLayer::Udp, [127, 0, 0, 1], 5555)
4646
.unwrap();
4747

48-
let calseg = xcp.create_calseg("calseg", &CAL_PAGE, true);
48+
let calseg = xcp.create_calseg("CalPage", &CAL_PAGE, true);
4949

5050
// Measurement signal
5151
let mut counter: u16 = calseg.min;
@@ -68,6 +68,6 @@ fn main() {
6868

6969
thread::sleep(Duration::from_micros(calseg.delay as u64));
7070

71-
//xcp.write_a2l();
71+
xcp.write_a2l().unwrap(); // Force writing the A2L file once (for inspection)
7272
}
7373
}

examples/rayon_demo/src/main.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn write_image(filename: &str, pixels: &[u8]) {
6060
// Create rgb image buffer and write to file
6161
let mut imgbuf = ImageBuffer::new(X_RES as u32, Y_RES as u32);
6262
for (x, y, rgb_pixel) in imgbuf.enumerate_pixels_mut() {
63-
*rgb_pixel = color_map[pixels[y as usize * X_RES as usize + x as usize] as usize];
63+
*rgb_pixel = color_map[pixels[y as usize * X_RES + x as usize] as usize];
6464
}
6565
imgbuf.save(filename).unwrap();
6666
}
@@ -113,6 +113,7 @@ fn render(pixels: &mut [u8], row: usize, length: usize, upper_left: Complex<f64>
113113
event.trigger(); // measure line and timestamp of calculation start
114114

115115
// Render line
116+
// @@@@
116117
for column in 0..length {
117118
let point = pixel_to_point((column, row), upper_left, lower_right);
118119
pixels[column] = match escape_time(point, 255) {

0 commit comments

Comments
 (0)