Skip to content

Commit 0eeb374

Browse files
committed
Reduce string allocations by using a writer pattern
1 parent 87a4511 commit 0eeb374

File tree

18 files changed

+590
-308
lines changed

18 files changed

+590
-308
lines changed

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ xcp_idl_generator = { path = "./xcp_idl_generator/"}
129129
xcp_idl_generator_derive = { path = "./xcp_idl_generator/xcp_idl_generator_derive/"}
130130

131131

132+
#a2lfile = "1.5.0"
133+
a2lfile = "2.2.0"
132134

133135
[dev-dependencies]
134136

135137
# used to implement the integration test XCP client and A2L parser
136138
tokio = { version = "1.37.0", features = ["full"] }
137-
a2lfile = "1.5.0"
139+
138140
bytes = "1.6.0"
139141
xcp_client = { path = "xcp_client" }
140142

README.md

+15-12
Original file line numberDiff line numberDiff line change
@@ -267,31 +267,34 @@ All measurement and calibration code instrumentation is non blocking and the tri
267267
There are no heap allocation during runtime, except for the lazy registrations of and for A2L generation.
268268
269269
build.rs automatically builds a minimum static C library from individially preconfigured core XCPlite sources.
270-
On C level, there is a synchronisation mutex for the mpsc transmit queue.
270+
On C level, there is a synchronisation mutex or spinlock for the mpsc transmit queue.
271271
The C code has the option to start the server with 2 normal threads for rx and tx socket handling.
272272
273-
The generated A2L file is finalized on XCP connect and provided for upload via XCP.
274-
This is achieved with a simple A2L writer which uses a template for the A2L.
273+
The generated A2L file is finalized on XCP connect and provided for upload via XCP.
275274
276-
The proc macro for more convinient A2L generation is still in an experimantal state.
275+
The proc macro for more convinient A2L generation is still in an experimental state.
277276
278-
Measurement of local variables is done with a macro which either copies to a static transfer buffer or directly accesses the value on stack.
277+
Measurement of local variables is done with a macro which either copies to a static transfer buffer in the event or directly accesses the value on stack.
279278
This involves a lazy initialization of the structures to build the A2l file describing the local variables.
280279
281-
The low word of a calibration parameter (CHARACTERISTIC) memory address in the A2L file is a relative offset in the calibration page struct. The high word is the index of the calibration segment in alphabetic order.
282-
The memory addresses of local variables are relative addresses in their event capture buffer or to the stack location of the variable holding the event.
283-
This concept is currently not supported by the A2L update tools, though A2L generation at runtime is the only option.
280+
There are 3 different addressing shemes, indicated by address extension (called _ABS, _DYN and _APP in the code).
281+
In mode APP, the low word of a calibration parameters memory address in the A2L file is a relative offset in the calibration page struct.
282+
The high word (& 0x7FFF) is the index of the calibration segment in a alphabetic ordered list.
283+
The memory addresses of local measurement variables are relative addresses (mode DYN) in their event capture buffer on stack or to the stack location of the variable holding the event.
284+
Mode ABS is the usual absolute addressing mode, relative to the module load address, which is only usefull for static cells.
285+
These concepts are currently not supported by the A2L update tools, though A2L generation at runtime is the only option for now.
286+
287+
The EPK version string in the A2L file can be set by the application. It resides a seperate, hardcoded const memory segment.
284288
285-
The EPK version string in the A2L file can be set by the application. It resides a seperate const memory segment.
286289
287290
## Future improvements
288291
289-
- Create a zero lock MPSC event queue, increase queue efficiency (optimize mutex contention) for many daq lists and events
290-
- The A2L file should not be loaded to memory to provide it for upload
292+
- Create a minimal lock MPSC event queue, increase queue efficiency (optimize mutex contention) for many daq lists and events
291293
- Support more types of calibration parameters, including types for curves and maps with axis
292294
- Avoid the mutex lock in CalSeg::Sync when there is no pending parameter modification
293295
- Improve the meta data annotations of the A2L serializer
294-
- Reduce the number of heap allocations and strings in the proc-macros and in A2L generation, reduce the overall memory footprint
296+
- Reduce the number of heap allocations and strings, reduce the overall memory footprint
297+
- Add sub groups of measurements for event instances
295298
- Add support to decribe the application clock domain in rust
296299
- Provide a no-std version and create a embassy example
297300

examples/multi_thread_demo/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ fn main() {
126126

127127
// Test
128128
thread::sleep(Duration::from_millis(1000));
129-
xcp.write_a2l();
129+
xcp.write_a2l().unwrap();
130130

131131
t.into_iter().for_each(|t| t.join().unwrap());
132132

examples/point_cloud_demo/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,6 @@ fn main() {
162162
event_point_cloud.trigger();
163163

164164
params.sync();
165-
xcp.write_a2l();
165+
xcp.write_a2l().unwrap();
166166
}
167167
}

examples/protobuf_demo/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,6 @@ fn main() {
218218

219219
thread::sleep(Duration::from_micros(1000000));
220220

221-
xcp.write_a2l(); // @@@@ test
221+
xcp.write_a2l().unwrap(); // @@@@ test
222222
}
223223
}

examples/rayon_demo/src/main.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const MANDELBROT: Mandelbrot = Mandelbrot { x: -1.4, y: 0.0, width: 0.015 };
3939
// Image rendering
4040

4141
// Write the buffer `pixels` to the file named `filename`.
42-
fn write_image(filename: &str, pixels: &[u8]) -> Result<(), std::io::Error> {
42+
fn write_image(filename: &str, pixels: &[u8]) {
4343
// Rainbox color map (credits to CoPilot)
4444
let mut color_map = Vec::with_capacity(256);
4545
for i in 0..256 {
@@ -63,8 +63,6 @@ fn write_image(filename: &str, pixels: &[u8]) -> Result<(), std::io::Error> {
6363
*rgb_pixel = color_map[pixels[y as usize * X_RES as usize + x as usize] as usize];
6464
}
6565
imgbuf.save(filename).unwrap();
66-
67-
Ok(())
6866
}
6967

7068
//---------------------------------------------------------------------------------------
@@ -201,7 +199,7 @@ fn main() {
201199
}
202200

203201
// Write image to file
204-
write_image("mandelbrot.png", &pixels).expect("error writing PNG file");
202+
write_image("mandelbrot.png", &pixels);
205203
println!("Image written to mandelbrot.png, frame {} {:.4}s", mainloop_counter, elapsed_time);
206204
update_counter += 1;
207205
event_update.trigger();

examples/single_thread_demo/src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ fn main() {
111111

112112
thread::sleep(Duration::from_millis(10)); // 100 Hz
113113

114-
xcp.write_a2l();
114+
xcp.write_a2l().unwrap();
115115
}
116116

117117
// Stop the XCP server

src/daq/daq_event.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ mod daq_tests {
637637
break;
638638
}
639639
}
640-
xcp.write_a2l();
640+
xcp.write_a2l().unwrap();
641641
}
642642

643643
//-----------------------------------------------------------------------------
@@ -672,7 +672,7 @@ mod daq_tests {
672672
break;
673673
}
674674
}
675-
xcp.write_a2l();
675+
xcp.write_a2l().unwrap();
676676
}
677677

678678
//-----------------------------------------------------------------------------
@@ -731,6 +731,6 @@ mod daq_tests {
731731

732732
// daq_register_instance!(channel6, event5); // panic: duplicate measurement
733733

734-
xcp.write_a2l();
734+
xcp.write_a2l().unwrap();
735735
}
736736
}

src/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ fn main() {
487487
// Without this, the A2L file will be automatically written on XCP connect, to be available for download by CANape
488488
if idle_time >= 2.0 {
489489
// Test A2L write
490-
xcp.write_a2l();
490+
xcp.write_a2l().unwrap();
491491

492492
// Test init request
493493
// xcp.set_init_request();

src/reg/registry.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use std::net::Ipv4Addr;
88
mod a2l_writer;
99
use a2l_writer::A2lWriter;
1010

11+
mod a2l_reader;
12+
1113
use crate::xcp;
1214
use xcp::XcpEvent;
1315

@@ -736,11 +738,10 @@ impl Registry {
736738
}
737739

738740
/// Generate A2L file from registry
739-
/// Returns true, if file is rewritten due to changes
740-
pub fn write(&mut self) -> Result<bool, &'static str> {
741+
pub fn write_a2l(&mut self) -> Result<(), std::io::Error> {
741742
// Error if registry is closed
742743
if self.is_frozen() {
743-
return Err("Registry is frozen!");
744+
return Err(std::io::Error::new(std::io::ErrorKind::Other, "Registry is closed"));
744745
}
745746

746747
// Sort measurement and calibration lists to get deterministic order
@@ -799,12 +800,15 @@ mod registry_tests {
799800
Some("annotation".to_string()),
800801
));
801802

802-
std::fs::remove_file("test.a2h").ok();
803-
let res = r.write();
804-
let updated = res.expect("A2L write write failed");
805-
assert!(updated);
806-
let res = r.write(); // Write again and it should not be written
807-
let updated = res.expect("A2L write write failed");
808-
assert!(!updated);
803+
r.write_a2l().unwrap();
804+
805+
// Check update optimization
806+
//std::fs::remove_file("test.a2h").ok();
807+
// let res = r.write();
808+
// let updated = res.expect("A2L write write failed");
809+
// assert!(updated);
810+
// let res = r.write(); // Write again and it should not be written
811+
// let updated = res.expect("A2L write write failed");
812+
// assert!(!updated);
809813
}
810814
}

0 commit comments

Comments
 (0)