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
135 changes: 135 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ tokio-tungstenite = "0.24"
async-trait = "0.1"
dashmap = "6"
blake3 = "1"
criterion = { version = "0.5", default-features = false, features = ["html_reports"] }
mimalloc = "0.1"
object = { version = "0.36", default-features = false, features = ["read", "std", "elf", "write"] }
rusqlite = { version = "0.31", features = ["bundled"] }
Expand Down
5 changes: 5 additions & 0 deletions crates/fbuild-header-scan/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ license.workspace = true
[dependencies]

[dev-dependencies]
criterion = { workspace = true }
tempfile = { workspace = true }

[[bench]]
name = "scan_throughput"
harness = false
20 changes: 20 additions & 0 deletions crates/fbuild-header-scan/benches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# benches

Criterion micro-benchmarks for `fbuild-header-scan`.

`scan_throughput.rs` measures `scan()` single-thread throughput (MB/s) over
three synthetic C++ fixtures: **tiny** (~64 B, per-call overhead),
**medium** (100 KB), and **large** (2 MB, stand-in for a Teensy-core-sized
translation unit). The fixtures exercise the scanner's adversary paths
(comments, string / raw-string literals containing fake `#include`s,
identifiers ending in `R` / `L`).

Per FastLED/fbuild#205 P-03 the aspirational threshold is **≥ 50 MB/s
single-thread**. This bench captures the baseline; it is not yet a CI
gate (Phase 7 will wire that up in a follow-up).

Run:

```bash
uv run soldr cargo bench -p fbuild-header-scan --bench scan_throughput
```
59 changes: 59 additions & 0 deletions crates/fbuild-header-scan/benches/scan_throughput.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//! Criterion benchmark for `fbuild_header_scan::scan` throughput.
//!
//! P-03 of FastLED/fbuild#205: capture single-thread MB/s on three input
//! sizes (tiny / medium / large) so future PRs can regress against a
//! recorded baseline. The aspirational threshold is ≥ 50 MB/s
//! single-thread; this harness records the number but does not gate CI.

use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use fbuild_header_scan::scan;

/// Generate a synthetic C++ source string at least `target_bytes` long.
///
/// The template intentionally exercises the scanner's adversary paths:
/// angled + quoted `#include`, line and multi-line block comments
/// containing fake `#include`s, string and raw-string literals with
/// embedded `#include` payloads, identifiers ending in `R` / `L`
/// (which must NOT be treated as raw-string prefixes), and a char
/// literal containing `#`. Repeated until we hit the byte budget.
fn fixture(target_bytes: usize) -> String {
let template = "\
#include <a.h>\n\
// comment with #include <not_real.h>\n\
const char* s = \"#include <also_not_real.h>\";\n\
const char* r = R\"(#include <not_real_either.h>)\";\n\
auto FooR = 0; // identifier ending in R, NOT a raw string\n\
auto FooL = 1; // identifier ending in L, NOT a wide-string prefix\n\
/* block\n #include <inside_block.h>\n*/\n\
char c = '#';\n\
#include \"b.h\"\n\
";
let mut s = String::with_capacity(target_bytes + template.len());
while s.len() < target_bytes {
s.push_str(template);
}
s
}

fn bench_scanner(c: &mut Criterion) {
let mut group = c.benchmark_group("scan");
for (name, size) in [
("tiny", 64usize),
("medium", 100 * 1024),
("large", 2 * 1024 * 1024),
] {
let src = fixture(size);
let actual_len = src.len();
group.throughput(Throughput::Bytes(actual_len as u64));
group.bench_function(name, |b| {
b.iter(|| {
let refs = scan(black_box(&src));
black_box(refs);
});
});
}
group.finish();
}

criterion_group!(benches, bench_scanner);
criterion_main!(benches);
6 changes: 6 additions & 0 deletions crates/fbuild-library-select/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ walkdir = { workspace = true }

[dev-dependencies]
tempfile = { workspace = true }
criterion = { workspace = true }
fbuild-test-support = { path = "../fbuild-test-support" }

[[bench]]
name = "resolve_cold"
harness = false
23 changes: 23 additions & 0 deletions crates/fbuild-library-select/benches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# fbuild-library-select benches

Criterion benchmarks for the PlatformIO-LDF-style library resolver.

## resolve_cold

End-to-end cold-path measurement of `resolve()` against a synthetic
~30-library framework tree (Teensyduino-class) built with `MiniFramework`. A
5-deep transitive include chain forces the two-pass LDF reconciliation; the
remaining libraries are unreferenced and must be rejected — that doubles as a
guard against the #204 over-selection regression. Walks the tempdir on every
iteration since no cache sits in front of `resolve()` today (Phase 4
memoization waits on zccache#130).

The Phase 7 P-02 threshold from FastLED/fbuild#205 is **≤ 200 ms cold for a
typical teensy41 project**. This bench captures the baseline; future PRs gate
against it.

Run:

```bash
uv run soldr cargo bench -p fbuild-library-select --bench resolve_cold
```
Loading
Loading