Integrate Rust -> BSW logger bridge#480
Conversation
| 2. The Rust compiler | ||
|
|
||
| Install Rust 1.90.0 to be compatible with the CI builds: | ||
| Install Rust 1.96.0 to be compatible with the CI builds: |
There was a problem hiding this comment.
The ubuntu version is defined only once. Probably we should use the same approach for rust:
:prop:`tool:ubuntu_version`
There was a problem hiding this comment.
done. There's even a nice mechanism already in place in doc/dev/conf.py to replace x.x in code blocks with the correct version number depending on which marker string is nearby.
ThoFrankACN
left a comment
There was a problem hiding this comment.
Really nice work!
I only have some minor feedback. In my opinion the vendoring approach is good. We have everything available for an offline build and can track changes, but using dependencies from crates.io is still simple.
| if it is unset the message is dropped. The crate name is prepended to the | ||
| message so the originating module is still visible. | ||
|
|
||
| .. warning:: |
There was a problem hiding this comment.
Should we also warn about the performance implications of double-buffering here?
And not sure how cpp behaves, but the formatting overhead for rust messages is still there even if the cpp logger component is disabled.
There was a problem hiding this comment.
Good points, I'll add the two caveats.
I'll also check how it's done in C++, maybe some performance gains hidden there by disabling serialization if it's not going to get printed anyway.
There was a problem hiding this comment.
In the bsw logger it's gated through if (isEnabled(componentIndex, _level)) in Logger.h. I can also (double) check isEnabled via FFI from Rust before doing the serialization. Maybe with some profiling of some format heavy logs to see whether that optimization is worth it.
There was a problem hiding this comment.
Test log line with some formatting.
"rx id={:#05x} dlc={} ts={:>8}ms seq={:05} crc={:#06x}"
-> "rx id=0x1a4 dlc=8 ts= 123456ms seq=00042 crc=0xbeef"
Results (200k iterations/run, 3 runs)
| gated | naive (always format) | delta | |
|---|---|---|---|
| disabled component | ~6.5 ns/call | ~160 ns/call | saving ~155 ns (~24x) |
| enabled component | ~160 ns/call | ~160 ns/call | overhead ~ 0 |
definitely seems to be worth it to add the additional is_enabled FFI call also to Rust to skip serializing entirely when the logging component is disabled.
| for &b in s { | ||
| self.buffer[self.bytes_used] = b; | ||
| self.bytes_used += 1; | ||
| } | ||
| Ok(()) | ||
| } else { | ||
| // not enough space | ||
| // only copy what fits | ||
| let s = &s[0..(LOG_BUF_SIZE - self.bytes_used - 1)]; | ||
| for &b in s { | ||
| self.buffer[self.bytes_used] = b; | ||
| self.bytes_used += 1; | ||
| } |
There was a problem hiding this comment.
Maybe the loops should be replaced by copy_from_slice.
| pub use component::LoggerComponent; | ||
|
|
||
| #[doc(hidden)] | ||
| pub use paste as __paste; |
There was a problem hiding this comment.
Why is there the need to re-export paste?
There was a problem hiding this comment.
It's used in the expansion of the log macro. If we don't re-export then it's not available at the callsite of the macro and every caller of our logging macros would need to add a dependency to paste in their Cargo.toml. Similar to https://stackoverflow.com/questions/65164156/how-to-set-dependencies-for-a-macro-in-rust#:~:text=lib%2Ers%2E-,Library,attribute
/opt/cargo and /opt/rustup are filled as root during the image build (rustup setup and cargo install cbindgen), but the container runs under the UID injected via DOCKER_UID, which then cannot read or lock the cargo registry. This caused the following CI error: error: failed to open `/opt/cargo/registry/cache/.../equivalent-1.0.2.crate` Caused by: Permission denied (os error 13) chmod the cargo and rustup homes world-accessible after install, the same fix already applied to /home/build/.cache. Change-Id: I6cd61820097a6f56d030c0972ca25b0e2dd88320
Introduce the openbsw-logger crate (libs/bsw/logger/rust) so Rust code can emit log messages through the existing C++ ::util::logger::Logger. First-party Rust code uses per-component macros: declare_logger_component! binds a component to the extern "C" getter that DECLARE/DEFINE_LOGGER_COMPONENT now emit on the C++ side, and bsw_debug!/info!/warn!/error!/critical! format into a stack buffer and forward to bsw_cpp_logger_log. The component index is fetched from C++ on every call rather than cached, so there is no Rust-side init step and no dependency on logger::init() ordering (the symbols hold COMPONENT_NONE until applyMapping() runs). Messages routed through the `log` facade (e.g. third-party crates) fall back to a single component set via set_default_component, with the crate name prepended; they are dropped if no default is configured. bsw_cpp_logger_log passes the already-formatted message through a literal "%s" so stray '%' characters are not interpreted as printf specifiers against an empty va_list. Trace maps to DEBUG, since a trace level does not exist in the BSW logger. Use in referenceApp: rustHelloWorld logs under the DEMO component and app.cpp installs the logger and default component under BUILD_RUST. Document the Rust API in the logger module docs. Change-Id: Iab2756f03f322b5e5354c3ee94e41c8f4f00eac9
This will exclude 3rdparty code from the GitHub language stats bars. Change-Id: Ied6c8add46a2a7ec819ed4762c3966242a9593dd
Vendor the workspace's crate dependencies into libs/3rdparty/cargo-vendor alongside the other third-party imports. Remove cbindgen from the build so the vendored tree stays small. cbindgen only generates the logger's C header (include/BswLogger.h, checked in), and made cargo vendor 88 MB large across 71 crates by dragging in unneeded windows deps. Dropping it leaves just log and paste (576 KB, 2 crates). The header is now a checked-in artifact regenerated outside of the build with the cbindgen CLI. .ci/cbindgen.py regenerates it and fails on drift via git diff --exit-code, mirroring .ci/format.py, and a matching cbindgen.yml workflow runs it in the development container. Bump the cbindgen CLI already installed in that image from 0.27.0 to 0.29.2 so it matches the version that produced the committed header. Remove the logger crate's build.rs, which existed only to run cbindgen Change-Id: I2de261e9b4e4e5cc1c3504051874578b701087f7
Also adapt the .treefmt.toml script and Dockerfile because on the CI rustfmt wasn't available for the new Rust version. Change-Id: Ie7b52473792e1d5f0a74dd595952d568368c8394
This PR improves Rust support and offline/containerized build reliability:
the dev container.