Skip to content

Commit e2e68a3

Browse files
Backport tracer changes making it more tolerant to older HCI pre v2
1 parent 4cf30ed commit e2e68a3

5 files changed

Lines changed: 118 additions & 15 deletions

File tree

tracer/Cargo.lock

Lines changed: 22 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tracer/Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
name = "hci-tracer"
33
version = "0.1.0"
44
edition = "2021"
5-
rust-version = "1.85"
5+
rust-version = "1.81"
6+
# MSRV-aware resolution: pick dependency versions that build on `rust-version`.
7+
resolver = "3"
68
description = "Compare HCI-Core and HWPE-Stream transaction logs produced by hci_transaction_tracer and hwpe_stream_transaction_tracer"
79
authors = ["Francesco Conti <f.conti@unibo.it>"]
810
license = "Apache-2.0"
@@ -19,5 +21,7 @@ path = "src/lib.rs"
1921
[dependencies]
2022
serde = { version = "1.0.228", features = ["derive"] }
2123
serde_json = "1.0.150"
22-
clap = { version = "4.6.1", features = ["derive"] }
24+
# Capped below 4.6: clap 4.6 and its `clap_lex` are written in edition
25+
# 2024, which needs Rust >= 1.85. 4.5 is edition 2021 and builds on 1.81+.
26+
clap = { version = "~4.5", features = ["derive"] }
2327
owo-colors = "4.3.0"

tracer/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ cargo test # unit + integration tests
2222
Dependencies are `serde`, `serde_json`, `clap` and `owo-colors`; `--offline`
2323
works if the crates are already in the local registry.
2424

25+
The crate is edition 2021 and builds with **Rust 1.81 or newer**, which is what
26+
`rust-version` in `Cargo.toml` declares. Two things keep it that way, and both
27+
matter if you touch the dependencies:
28+
29+
* `clap` is capped below 4.6 (`~4.5`). clap 4.6 and its `clap_lex` are written in
30+
edition 2024 and need Rust 1.85, which fails on an older toolchain with
31+
`feature `edition2024` is required`.
32+
* `resolver = "3"` makes Cargo pick dependency versions compatible with the
33+
declared `rust-version` rather than the newest ones. It needs Cargo 1.84+.
34+
35+
`Cargo.lock` is committed, so a plain `cargo build` uses a known-good set
36+
regardless. If you bump a dependency, re-check with an old toolchain:
37+
38+
```sh
39+
rustup toolchain install 1.81 --profile minimal
40+
cargo +1.81 test
41+
```
42+
2543
## Usage
2644

2745
```
@@ -54,6 +72,13 @@ note saying how many.
5472
Never compared: `cycle` and `seq`. Off by default: `user`/`r_user`, `id`/`r_id`,
5573
`ecc`/`r_ecc` — switch them on with `--check-user`, `--check-id`, `--check-ecc`.
5674

75+
Older HCI-Core interfaces have fewer side channels than current ones: a log whose
76+
header declares `IW = 0` or `EW = 0` carries no `id` or `ecc` fields at all. Those
77+
are left out of the comparison, so a trace taken on an old interface diffs cleanly
78+
against one taken on a new interface. Asking for a side channel that a log does not
79+
carry is refused outright rather than compared against a stub value, which would
80+
report a difference for every transaction.
81+
5782
Byte enables are canonicalized to a bit-level mask before being compared, so
5883
`be = 0xf` with `BW = 8` is *equal* to `strb = 0xff` with `ELEMENT_WIDTH = 4` on a
5984
32-bit bus: both describe the same 32 enabled data bits. Bytes that neither side

tracer/src/compare.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
use std::path::Path;
2323

2424
use crate::error::{Error, Result};
25-
use crate::model::{Beat, LoadedLog, LogKind, Payload};
25+
use crate::model::{Beat, Iface, LoadedLog, LogKind, Payload};
2626
use crate::value::Value;
2727

2828
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -564,6 +564,45 @@ pub fn describe(beat: &Beat) -> String {
564564
}
565565
}
566566

567+
fn side_channel_width(iface: &Iface, name: &str) -> u32 {
568+
match iface {
569+
Iface::Hci { uw, iw, ew, .. } => match name {
570+
"user" => *uw,
571+
"id" => *iw,
572+
_ => *ew,
573+
},
574+
Iface::Stream { .. } => 0,
575+
}
576+
}
577+
578+
/// Refuse to compare a side channel that one of the logs does not carry.
579+
///
580+
/// Older HCI-Core interfaces have no `id` or `ecc` signals at all, so their logs
581+
/// declare `IW = 0` / `EW = 0` and leave those fields out. Comparing them anyway
582+
/// would silently treat the absent side as zero and report a difference for
583+
/// every transaction -- a misalignment that says nothing about the design.
584+
pub fn check_side_channels(a: &LoadedLog, b: &LoadedLog, ctx: &CmpCtx) -> Result<()> {
585+
for (on, name, flag) in [
586+
(ctx.spec.user, "user", "--check-user"),
587+
(ctx.spec.id, "id", "--check-id"),
588+
(ctx.spec.ecc, "ecc", "--check-ecc"),
589+
] {
590+
if !on {
591+
continue;
592+
}
593+
for (tag, log) in [("A", a), ("B", b)] {
594+
if side_channel_width(&log.iface, name) == 0 {
595+
return Err(Error::Usage(format!(
596+
"{flag} was given, but {tag} ({}) declares no `{name}` side channel: \
597+
comparing it would report a difference for every transaction",
598+
log.file.display()
599+
)));
600+
}
601+
}
602+
}
603+
Ok(())
604+
}
605+
567606
/// `--x-policy=error`: refuse to go on if any *enabled* byte carries x/z.
568607
pub fn check_unknowns(log: &LoadedLog, side: Side, ctx: &CmpCtx) -> Result<()> {
569608
if ctx.opts.x != XPolicy::Error {
@@ -702,6 +741,27 @@ mod tests {
702741
assert!(beats_equal(&a, &b, &lenient));
703742
}
704743

744+
#[test]
745+
fn refuses_to_compare_a_side_channel_that_is_not_there() {
746+
// An old HCI-Core interface has no `id` signal at all, so its log
747+
// declares IW = 0; comparing `id` anyway would flag every transaction.
748+
let no_id = req_log(vec![req_beat(0, 1, "0x0", "0x1", "0xf")]);
749+
let c = CmpCtx::new(
750+
Mode::HciReq,
751+
&no_id,
752+
&no_id,
753+
32,
754+
CompareOptions { check_id: true, ..Default::default() },
755+
);
756+
let err = check_side_channels(&no_id, &no_id, &c).unwrap_err();
757+
assert!(err.to_string().contains("--check-id"), "{err}");
758+
759+
// With the side channel present, it is compared as asked.
760+
let mut with_id = req_log(vec![req_beat(0, 1, "0x0", "0x1", "0xf")]);
761+
with_id.iface = Iface::Hci { dw: 32, aw: 32, bw: 8, uw: 0, iw: 8, ew: 0, ehw: 0 };
762+
assert!(check_side_channels(&with_id, &with_id, &c).is_ok());
763+
}
764+
705765
#[test]
706766
fn keep_writes_drops_loads() {
707767
let mut log = req_log(vec![

tracer/src/run.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use std::path::Path;
1111

1212
use crate::cli::{Cli, Command, CompareArgs};
1313
use crate::color::{use_color, Palette, RealEnv};
14-
use crate::compare::{beats_equal, check_unknowns, key_of, keep_writes, CmpCtx, Mode, Side};
14+
use crate::compare::{
15+
beats_equal, check_side_channels, check_unknowns, key_of, keep_writes, CmpCtx, Mode, Side,
16+
};
1517
use crate::diff::{diff, downgrade_replace, DiffOp, DiffStats};
1618
use crate::error::{Error, Result};
1719
use crate::load::{load_hci_request, load_hci_response, load_hwpe_stream, probe_kind, RepairMode};
@@ -152,6 +154,7 @@ fn compare(mode: Mode, mut a: LoadedLog, mut b: LoadedLog, args: &CompareArgs) -
152154
let width = normalize_widths(&mut a, &mut b, args.split, args.drop_empty)?;
153155
let ctx = CmpCtx::new(mode, &a, &b, width, args.options());
154156

157+
check_side_channels(&a, &b, &ctx)?;
155158
check_unknowns(&a, Side::A, &ctx)?;
156159
check_unknowns(&b, Side::B, &ctx)?;
157160

0 commit comments

Comments
 (0)