Skip to content

Consolidate AVR measurement campaigns - #96

Merged
kaidokert merged 21 commits into
mainfrom
agent/portable-stack-measurement
Jul 24, 2026
Merged

Consolidate AVR measurement campaigns#96
kaidokert merged 21 commits into
mainfrom
agent/portable-stack-measurement

Conversation

@kaidokert

@kaidokert kaidokert commented Jul 18, 2026

Copy link
Copy Markdown
Owner

What changed

  • migrate AVR parser footprint runs to the shared embedded-measure benchmark lifecycle and structured report schema
  • use the shared rollover-safe AVR timer, portable stack adapter, simavr command preset, and declarative campaign runner
  • report parser input metrics consistently across picojson, stream-parser, and serde-json-core fixtures
  • keep the existing Python analysis remnants for now; replacing them is intentionally outside this convergence pass

Impact

The parser now uses the same target-side measurement and host-side campaign interface as the crypto clients, demonstrating that the toolkit is not crypto-specific while removing most of the simulator and measurement boilerplate.

Dependency status

This PR intentionally remains a draft. embedded-measure is not published yet. The manifest declares its future crates.io version and uses a workspace-local [patch.crates-io] entry pointing at the sibling checkout. A standalone GitHub checkout is therefore expected not to build until the support crate is published or patched locally.

Verification

  • formatting checks passed
  • all AVR demo examples built in release mode using the local patch

Summary by Sourcery

Unify AVR parser measurement fixtures with the shared krabi-caliper benchmarking and reporting lifecycle, and align CI and tooling around the new stack and panic audit campaigns.

New Features:

  • Introduce krabi-caliper-based benchmarks for serde-json-core, picojson slice, and picojson stream AVR examples that record stack usage, timing, and input metrics.
  • Add negative-control panic audit entry points to the avr_demo crate and wire them into a structured cargo krabi-caliper panic-audit flow in CI.

Enhancements:

  • Replace custom Python stack and panic analysis scripts with a declarative krabi-caliper campaign configuration and cargo subcommands for AVR measurements.
  • Retarget avr_demo to atmega2560, add avr-device support, and centralize Timer1 overflow handling via krabi-caliper macros.
  • Simplify the local run_suite.py script to only drive binary size (cargo-bloat) analysis.
  • Document the AVR measurement workflow, depth matrix, and reporting locations in a new README for avr_demo.

CI:

  • Update AVR GitHub Actions workflows to install krabi-caliper host tooling, run the shared picojson-avr-stack campaign, and perform structured panic audits instead of manual cargo-binutils checks.

Documentation:

  • Add README.md describing how to run AVR stack and timing campaigns with krabi-caliper and where reports are produced.

Summary by CodeRabbit

  • New Features

    • Added benchmark-based AVR testing for JSON parsing scenarios.
    • Added configurable AVR simulation campaigns and stack-capacity checks.
    • Added automated panic auditing with JSON reporting.
    • Updated the demo target to support Arduino Mega 2560 hardware.
  • Refactor

    • Replaced manual stack measurement, simulator launching, and panic checks with unified tooling.
    • Retained the binary-size analysis workflow while removing obsolete test utilities.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AVR demos now use krabi-caliper for benchmark execution, stack analysis, and panic auditing. Mega2560 configuration, benchmark reporters, negative controls, campaign definitions, CI workflows, and the legacy Python suite are updated accordingly.

Changes

AVR caliper migration

Layer / File(s) Summary
Caliper platform integration
avr_demo/Cargo.toml, avr_demo/src/lib.rs
Adds Mega2560 and krabi-caliper dependencies, timer support, the NullReporter, and the neg-controls feature.
AVR benchmark harnesses
avr_demo/examples/test_*.rs, avr_demo/krabi-caliper.toml
Replaces manual parsing and stack measurement with krabi-caliper benchmark runners, AVR linker stacks, reporters, simulator parking, and benchmark campaign definitions.
Panic audit controls
avr_demo/examples/minimal.rs, avr_demo/src/lib.rs, .github/workflows/avr_tests.yaml
Adds feature-gated exported negative controls and invokes cargo krabi-caliper panic-audit with expected findings and JSON output.
CI and suite migration
.github/workflows/avr_tests.yaml, avr_demo/run_suite.py
Moves stack smoke and capacity checks to krabi-caliper and limits the Python suite to bloat analysis.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant krabi-caliper
  participant AVRExample
  participant simavr
  CI->>krabi-caliper: run stack analysis campaign
  krabi-caliper->>AVRExample: build and execute benchmark case
  AVRExample->>simavr: run Mega2560 benchmark
  simavr-->>AVRExample: return benchmark and stack data
  AVRExample-->>krabi-caliper: report metrics
  krabi-caliper-->>CI: publish campaign result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: consolidating AVR measurement and benchmark campaigns into shared krabi-caliper tooling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/portable-stack-measurement

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates the embedded-measure crate into the AVR demo to standardize stack usage and execution time benchmarking, replacing custom stack measurement logic and the simavr_wrapper.py tool. The examples (test_picojson.rs, test_serde.rs, and test_streamparser.rs) have been updated to use the new benchmark API. However, there is a critical compilation issue across all three examples: the serial variable is defined conditionally under the ufmt feature flag but is used unconditionally to initialize UfmtReporter, which will cause build failures when the feature is disabled.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread avr_demo/examples/test_picojson.rs
Comment thread avr_demo/examples/test_serde.rs
Comment thread avr_demo/examples/test_streamparser.rs
@kaidokert
kaidokert marked this pull request as ready for review July 23, 2026 04:15

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

Fixed security issues:

  • Command injection from untrusted input passed to OS command execution (link)

  • In the AVR examples, let mut dp = arduino_hal::Peripherals::take().unwrap(); is created unconditionally but only used under #[cfg(feature = "ufmt")], so non-ufmt builds will hit unused-variable warnings; consider guarding dp with the same cfg or factoring serial/benchmark setup into a helper that’s only compiled when needed.

  • The three AVR fixtures (test_serde, test_picojson, test_streamparser) duplicate nearly identical Benchmark/UfmtReporter/stack setup and run_atmega2560_benchmark wiring; pulling this into a shared helper or wrapper would reduce boilerplate and make it easier to keep the configurations in sync.

  • The magic constants in the measurement wiring (e.g., LinkerStack::<Avr>::avr_runtime(0x2200) and Some(15_625) for Timer1) would be easier to maintain if factored into named constants or derived from the board/memory configuration, so that future changes to the ATmega2560 setup don’t silently desynchronize the benchmark behavior.

Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the AVR examples, `let mut dp = arduino_hal::Peripherals::take().unwrap();` is created unconditionally but only used under `#[cfg(feature = "ufmt")]`, so non-`ufmt` builds will hit unused-variable warnings; consider guarding `dp` with the same cfg or factoring serial/benchmark setup into a helper that’s only compiled when needed.
- The three AVR fixtures (`test_serde`, `test_picojson`, `test_streamparser`) duplicate nearly identical `Benchmark`/`UfmtReporter`/stack setup and `run_atmega2560_benchmark` wiring; pulling this into a shared helper or wrapper would reduce boilerplate and make it easier to keep the configurations in sync.
- The magic constants in the measurement wiring (e.g., `LinkerStack::<Avr>::avr_runtime(0x2200)` and `Some(15_625)` for Timer1) would be easier to maintain if factored into named constants or derived from the board/memory configuration, so that future changes to the ATmega2560 setup don’t silently desynchronize the benchmark behavior.

## Individual Comments

### Comment 1
<location path="avr_demo/src/lib.rs" line_range="8-9" />
<code_context>
+
+#[cfg(feature = "neg-controls")]
+#[inline(never)]
+#[unsafe(no_mangle)]
+pub extern "C" fn panic_audit__neg__bounds_check(index: usize, out: *mut u8) {
+    let values = core::hint::black_box([0u8; 4]);
+    let value = values[core::hint::black_box(index)];
</code_context>
<issue_to_address>
**issue (bug_risk):** The `#[unsafe(no_mangle)]` attribute is likely invalid; consider using `#[no_mangle]` and expressing unsafety via the function signature instead.

Rust does not support an `unsafe` attribute here, and `#[no_mangle]` is the standard way to fix symbol names. To express unsafety, declare the function as `pub unsafe extern "C" fn ...` and use `#[no_mangle]` separately. As written, this attribute will either fail to compile or be ignored, so the symbol name for the audit hook may not be stable.
</issue_to_address>

### Comment 2
<location path="avr_demo/src/lib.rs" line_range="9-12" />
<code_context>
+#[cfg(feature = "neg-controls")]
+#[inline(never)]
+#[unsafe(no_mangle)]
+pub extern "C" fn panic_audit__neg__bounds_check(index: usize, out: *mut u8) {
+    let values = core::hint::black_box([0u8; 4]);
+    let value = values[core::hint::black_box(index)];
+    unsafe { *out = core::hint::black_box(value) };
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** These audit functions dereference raw pointers but are exposed as safe `extern` fns; consider either making them `unsafe` or taking `&mut u8` instead.

All three `panic_audit__neg__*` functions currently accept `*mut u8` and dereference it inside an `unsafe` block while remaining safe to call. This lets safe Rust and FFI callers pass null or invalid pointers without any type-system signal, leading to UB. Please either:
- Mark them `pub unsafe extern "C" fn` and document the required pointer invariants, or
- Change the parameter to `&mut u8` so Rust’s borrowing rules enforce validity on the Rust side, keeping `extern`/`#[no_mangle]` only for the symbol.
This ensures the public API correctly reflects the underlying unsafety.

Suggested implementation:

```rust
#[cfg(feature = "neg-controls")]
#[inline(never)]
#[unsafe(no_mangle)]
pub extern "C" fn panic_audit__neg__bounds_check(index: usize, out: &mut u8) {
    let values = core::hint::black_box([0u8; 4]);
    let value = values[core::hint::black_box(index)];
    *out = core::hint::black_box(value);
}

```

Apply the same pattern to the other `panic_audit__neg__*` functions in this file:
- Change their `out: *mut u8` parameter to `out: &mut u8`.
- Remove the `unsafe` block around `*out = ...` and perform a safe write via the mutable reference.
This keeps the functions safe to call while ensuring Rust callers must pass a valid, mutable reference, preventing UB from null/invalid pointers on the Rust side. For any purely FFI-facing usage where a raw pointer is required, consider adding separate `unsafe extern "C"` wrappers with documented pointer invariants instead of relaxing the safety of these audit functions.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread avr_demo/src/lib.rs Outdated
Comment thread avr_demo/src/lib.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d9e505314

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread avr_demo/examples/test_serde.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
.github/workflows/avr_tests.yaml (2)

128-146: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Harden interpolation in the run: block to avoid template-injection warnings.

zizmor flags ${{ }} expansion inside the shell script. The values here are workflow/matrix-controlled (not attacker input), so risk is low, but the idiomatic fix is to pass them via env: and reference shell variables instead of expanding directly into the script body.

♻️ Suggested hardening
      - name: Audit parser panic paths with negative controls
        working-directory: avr_demo
        env:
          EXAMPLE: ${{ matrix.example }}
          PROFILE: ${{ matrix.profile }}
          FEATURES: ${{ steps.feature_set.outputs.features }}
          INT_TYPE: ${{ matrix.int_type }}
          PICO_SIZE: ${{ matrix.pico_size }}
          DEFMT: ${{ matrix.defmt }}
        run: |
          cargo krabi-caliper panic-audit \
            --package avr_demo \
            --artifact-kind example \
            --artifact-name "$EXAMPLE" \
            --negative-artifact-name minimal \
            --target avr-none \
            --profile "$PROFILE" \
            --no-default-features \
            --features "$FEATURES" \
            --negative-features neg-controls \
            --owned-symbol '^picojson::' \
            --owned-symbol '^panic_audit__neg__' \
            --expect-negative 'panic_audit__neg__bounds' \
            --expect-negative 'panic_audit__neg__unwrap' \
            --expect-negative 'panic_audit__neg__expect' \
            --json "target/panic-audit/${EXAMPLE}-${INT_TYPE}-${PROFILE}-${PICO_SIZE}-${DEFMT}.json"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/avr_tests.yaml around lines 128 - 146, Harden the “Audit
parser panic paths with negative controls” step by moving all workflow and
matrix interpolations used by its run script into step-level environment
variables. Update the cargo command and JSON output path to reference the
corresponding quoted shell variables, while preserving the existing argument
values and behavior.

Source: Linters/SAST tools


62-63: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

Cache the krabi-caliper install and pin it with --locked. Both jobs cargo install krabi-caliper from source on every run without --locked or caching; the avr_panic_check matrix (2×2×2×2×2 = 32 legs) rebuilds it from source each leg, which is a large, avoidable CI cost, and the un---locked install risks non-reproducible dependency resolution. The existing cargo-bin cache (Lines 39-49) and the command -v install gates used for cargo-bloat/cargo-binutils are the pattern to follow.

  • .github/workflows/avr_tests.yaml#L62-L63: add --locked, gate with command -v, and include ~/.cargo/bin/cargo-krabi-caliper in the cargo-bin cache path/key.
  • .github/workflows/avr_tests.yaml#L112-L113: apply the same --locked + cached/gated install so the 32 matrix legs reuse a single cached binary instead of rebuilding.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/avr_tests.yaml around lines 62 - 63, Update both
krabi-caliper install steps at .github/workflows/avr_tests.yaml#L62-L63 and
.github/workflows/avr_tests.yaml#L112-L113 to install with --locked and gate
installation using command -v, following the existing cargo-bloat/cargo-binutils
pattern. Extend the existing cargo-bin cache configuration at
.github/workflows/avr_tests.yaml#L39-L49 to include
~/.cargo/bin/cargo-krabi-caliper in the cached paths and key so both jobs reuse
the binary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/avr_tests.yaml:
- Around line 128-146: Harden the “Audit parser panic paths with negative
controls” step by moving all workflow and matrix interpolations used by its run
script into step-level environment variables. Update the cargo command and JSON
output path to reference the corresponding quoted shell variables, while
preserving the existing argument values and behavior.
- Around line 62-63: Update both krabi-caliper install steps at
.github/workflows/avr_tests.yaml#L62-L63 and
.github/workflows/avr_tests.yaml#L112-L113 to install with --locked and gate
installation using command -v, following the existing cargo-bloat/cargo-binutils
pattern. Extend the existing cargo-bin cache configuration at
.github/workflows/avr_tests.yaml#L39-L49 to include
~/.cargo/bin/cargo-krabi-caliper in the cached paths and key so both jobs reuse
the binary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d3afa797-9256-4072-9456-1202210c4ec1

📥 Commits

Reviewing files that changed from the base of the PR and between de790a6 and 1a433cb.

📒 Files selected for processing (12)
  • .github/workflows/avr_tests.yaml
  • avr_demo/.cargo/config.toml
  • avr_demo/Cargo.toml
  • avr_demo/examples/minimal.rs
  • avr_demo/examples/test_picojson.rs
  • avr_demo/examples/test_serde.rs
  • avr_demo/examples/test_streamparser.rs
  • avr_demo/krabi-caliper.toml
  • avr_demo/run_suite.py
  • avr_demo/simavr_wrapper.py
  • avr_demo/src/lib.rs
  • avr_demo/src/stack_measurement.rs
💤 Files with no reviewable changes (3)
  • avr_demo/simavr_wrapper.py
  • avr_demo/src/stack_measurement.rs
  • avr_demo/.cargo/config.toml

@kaidokert
kaidokert merged commit 018f56a into main Jul 24, 2026
55 checks passed
@kaidokert
kaidokert deleted the agent/portable-stack-measurement branch July 24, 2026 05:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant