Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ The reference compilers live in era containers built from `provision/eras` and p

`rk config-diff`, `rk probes`, `rk flags-diff`, `rk demands` and `rk asm-inventory` read build directories and write markdown tables: the `.config` differences, the compiler probes the two compilers answered differently, the flags each unit was compiled with on one side only (read from the `.cmd` files kbuild writes), the failed units by error, and the instructions the kernel writes itself. `rk config-diff --why` also names the Kconfig expressions behind each difference and the probe that decided them, and needs the kernel tree, which it finds through `build.json` or `--source`. `rk syntax --build DIR --cc rucc` replays every unit of a reference build through rucc's front end with the reference's own command lines, `-fsyntax-only` for C and `-E` for assembly, and writes the failing units grouped by their first error. Units listed with an issue in `syntax-known.toml` are known failures, so the command fails only on new ones.

`rk sections-diff`, `rk symvers-diff`, `rk vec-audit`, `rk modules-audit` and `rk objtool-report` look at what the compilers produced. `rk sections-diff` compares the section names of every object two builds share, the size and relocation count of each kernel table (exports, jump labels, alternatives, exception fixups, initcalls and the rest), the call-site lists per function, and the `.modinfo` and `__ksymtab_strings` strings. `rk symvers-diff` compares `Module.symvers`, CRCs and namespaces included, and the global symbols of `System.map`. `rk vec-audit` decodes the x86-64 code of every unit built with `-mno-sse` or `-mgeneral-regs-only` and lists the vector and x87 instructions it finds, only those above the reference's count when given `--reference`. `rk modules-audit` fails on any module relocation the loader rejects, a wrong `vermagic` or an imported CRC that does not match `Module.symvers`. `rk objtool-report` buckets the objtool warnings of two build logs by message and function shape. `rk frames` compares the stack frame of every function in two builds made with `rk build --stack-usage`, which passes `KCFLAGS=-fstack-usage` so that each compiler writes a `.su` file next to every object. It fails on a function over `CONFIG_FRAME_WARN` that the reference keeps under it, and on a run time stack high water mark more than 10% above the reference's when both build directories have a `boot.log` from a kernel with `CONFIG_DEBUG_STACK_USAGE`. `rk sections-diff`, `rk vec-audit` and `rk frames` take `--save FILE` to keep what they read as JSON, and accept such a file in place of a build directory, which is how CI compares builds without moving their objects.
`rk sections-diff`, `rk symvers-diff`, `rk vec-audit`, `rk modules-audit` and `rk objtool-report` look at what the compilers produced. `rk sections-diff` compares the section names of every object two builds share, the size and relocation count of each kernel table (exports, jump labels, alternatives, exception fixups, initcalls and the rest), the call-site lists per function, and the `.modinfo` and `__ksymtab_strings` strings. It lists the first 60 differences, and every one with `--all`. `rk symvers-diff` compares `Module.symvers`, CRCs and namespaces included, and the global symbols of `System.map`. `rk vec-audit` decodes the x86-64 code of every unit built with `-mno-sse` or `-mgeneral-regs-only` and lists the vector and x87 instructions it finds, only those above the reference's count when given `--reference`. `rk modules-audit` fails on any module relocation the loader rejects, a wrong `vermagic` or an imported CRC that does not match `Module.symvers`. `rk objtool-report` buckets the objtool warnings of two build logs by message and function shape. `rk frames` compares the stack frame of every function in two builds made with `rk build --stack-usage`, which passes `KCFLAGS=-fstack-usage` so that each compiler writes a `.su` file next to every object. It fails on a function over `CONFIG_FRAME_WARN` that the reference keeps under it, and on a run time stack high water mark more than 10% above the reference's when both build directories have a `boot.log` from a kernel with `CONFIG_DEBUG_STACK_USAGE`. `rk sections-diff`, `rk vec-audit` and `rk frames` take `--save FILE` to keep what they read as JSON, and accept such a file in place of a build directory, which is how CI compares builds without moving their objects.

The nightly workflow builds every pin in the current set on X64 with gcc-14 and with rucc, from `tinyconfig` and the test fragment, and runs `rk test` on boot, smoke and KUnit. When the rucc kernel fails a unit, `rk mixed` runs on the first one in the same job. The run's summary has a line per version, green or red, and what `rk mixed` found. A manual run takes a branch or commit of tamnd/rucc and another configuration target.

Expand Down
5 changes: 3 additions & 2 deletions crates/rk/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ fn accepted(command: &str) -> Option<(bool, &'static [&'static str])> {
"probes" | "flags-diff" | "symvers-diff" | "objtool-report" => {
(false, &["reference", "other"])
}
"sections-diff" | "frames" => (false, &["reference", "other", "save"]),
"sections-diff" => (false, &["reference", "other", "save", "all"]),
"frames" => (false, &["reference", "other", "save"]),
"vec-audit" => (false, &["build", "reference", "save"]),
"modules-audit" => (false, &["build"]),
"syntax" => (false, &["build", "cc", "allow", "jobs"]),
Expand Down Expand Up @@ -152,7 +153,7 @@ usage:
rk config-diff --reference DIR --other DIR [--why] [--source DIR]
rk flags-diff --reference DIR --other DIR
rk probes --reference DIR --other DIR
rk sections-diff --reference DIR|FILE [--other DIR|FILE] [--save FILE]
rk sections-diff --reference DIR|FILE [--other DIR|FILE] [--save FILE] [--all]
rk symvers-diff --reference DIR --other DIR
rk vec-audit --build DIR|FILE [--reference DIR|FILE] [--save FILE]
rk modules-audit --build DIR
Expand Down
2 changes: 1 addition & 1 deletion crates/rk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ fn sections_diff(args: &Args) -> Result<ExitCode, String> {
}
let other = objects::load_or_scan(std::path::Path::new(other), sections::scan)?;
let comparison = sections::compare(&reference, &other);
print!("{}", sections::report(&comparison));
print!("{}", sections::report(&comparison, args.has("all")));
Ok(verdict(comparison.clean()))
}

Expand Down
21 changes: 13 additions & 8 deletions crates/rk/src/sections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,10 @@ fn cell(s: &str) -> String {
}
}

/// The comparison as markdown.
/// The comparison as markdown, with the first 60 differences or, with `all`, every one.
#[must_use]
pub fn report(c: &Comparison) -> String {
pub fn report(c: &Comparison, all: bool) -> String {
let rows = if all { c.differences.len() } else { ROWS };
let mut s = String::from("### Sections and kernel tables\n\n");
let _ = writeln!(
s,
Expand All @@ -615,7 +616,7 @@ pub fn report(c: &Comparison) -> String {
let _ = writeln!(s, "| `{what}` | {n} |");
}
s.push_str("\n| object | what | reference only | other only |\n|---|---|---|---|\n");
for d in c.differences.iter().take(ROWS) {
for d in c.differences.iter().take(rows) {
let _ = writeln!(
s,
"| {} | {} | {} | {} |",
Expand All @@ -625,8 +626,12 @@ pub fn report(c: &Comparison) -> String {
cell(&d.other)
);
}
if c.differences.len() > ROWS {
let _ = writeln!(s, "\nand {} more.", c.differences.len() - ROWS);
if c.differences.len() > rows {
let _ = writeln!(
s,
"\nand {} more, which `--all` lists.",
c.differences.len() - rows
);
}
s.push('\n');
}
Expand Down Expand Up @@ -725,8 +730,8 @@ mod tests {
let c = compare(&reference, &other);
let what: Vec<&str> = c.differences.iter().map(|d| d.what.as_str()).collect();
assert_eq!(what, ["__jump_table", "__mcount_loc in f", ".modinfo"]);
assert!(report(&c).contains("| a.o | __mcount_loc in f | 1 | 3 |"));
assert!(report(&c).contains("| a.o | __jump_table | 8=key1+0 | nothing |"));
assert!(report(&c, false).contains("| a.o | __mcount_loc in f | 1 | 3 |"));
assert!(report(&c, false).contains("| a.o | __jump_table | 8=key1+0 | nothing |"));
}

/// Two copies of one site, as when a function with a static branch is inlined twice.
Expand Down Expand Up @@ -767,6 +772,6 @@ mod tests {
let c = compare(&reference, &other);
assert!(c.clean());
assert_eq!(c.only_reference, ["b.o"]);
assert!(report(&c).contains("Only in the reference: b.o"));
assert!(report(&c, false).contains("Only in the reference: b.o"));
}
}
Loading