mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Trim synthetic overlay benchmarks; record Mac real-pack numbers
The real-pack benchmark on the production resource_root path stays as the reproducible measurement. On the Mac mini it saves 1.18 s (Faithful 32x) and 5.29 s (FPBR) per startup with the pack enabled. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1295fccd17
commit
cc8744a06b
2 files changed
+10
-193
No files matched your search
@@ -756,185 +756,6 @@ mod tests {
|
||||
assert!(lock_path(&out).exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "reproducible overlay benchmark; run with --ignored --nocapture"]
|
||||
fn benchmark_overlay_reuse() {
|
||||
use std::{hint::black_box, time::Instant};
|
||||
let f = Fixture::new();
|
||||
let pack = f.dir_pack("pack");
|
||||
let mut files = vec![(
|
||||
"pack.mcmeta".to_owned(),
|
||||
fs::read(f.0.join("pack/pack.mcmeta")).unwrap(),
|
||||
)];
|
||||
// 2,048 overrides (32 MiB), 32 merged language files, 8,192 live
|
||||
// vanilla textures (128 MiB). Synthetic incompressible payloads approximate
|
||||
// already-compressed PNG bytes; texture decoding is outside this benchmark.
|
||||
let mut random = 0x1234_5678u32;
|
||||
let texture: Vec<u8> = (0..16384)
|
||||
.map(|_| {
|
||||
random ^= random << 13;
|
||||
random ^= random >> 17;
|
||||
random ^= random << 5;
|
||||
(random >> 24) as u8
|
||||
})
|
||||
.collect();
|
||||
for i in 0..8192 {
|
||||
let name = format!("assets/minecraft/textures/block/{i}.png");
|
||||
f.write(&format!("vanilla/{name}"), &texture);
|
||||
if i < 2048 {
|
||||
f.write(&format!("pack/{name}"), &texture);
|
||||
files.push((name, texture.clone()));
|
||||
}
|
||||
}
|
||||
for i in 0..32 {
|
||||
let name = format!("assets/minecraft/lang/{i}.json");
|
||||
let vanilla = serde_json::to_vec(&serde_json::Value::Object(
|
||||
(0..2000)
|
||||
.map(|j| {
|
||||
(
|
||||
format!("key{j}"),
|
||||
serde_json::json!(format!("Vanilla translation {j}")),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
.unwrap();
|
||||
let body = serde_json::to_vec(&serde_json::Value::Object(
|
||||
(0..1000)
|
||||
.map(|j| {
|
||||
(
|
||||
format!("key{j}"),
|
||||
serde_json::json!(format!("Pack translation {j}")),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
.unwrap();
|
||||
f.write(&format!("vanilla/{name}"), &vanilla);
|
||||
f.write(&format!("pack/{name}"), &body);
|
||||
files.push((name, body));
|
||||
}
|
||||
let borrowed: Vec<_> = files
|
||||
.iter()
|
||||
.map(|(name, body)| (name.as_str(), body.clone()))
|
||||
.collect();
|
||||
f.write("pack.zip", &archive(&borrowed, true));
|
||||
println!(
|
||||
"fixture ZIP bytes={}",
|
||||
fs::metadata(f.0.join("pack.zip")).unwrap().len()
|
||||
);
|
||||
let zip = packs::pack(
|
||||
"zip".into(),
|
||||
Text::empty(),
|
||||
Source::Zip(f.0.join("pack.zip")),
|
||||
)
|
||||
.unwrap();
|
||||
let median = |mut times: Vec<f64>| {
|
||||
times.sort_by(f64::total_cmp);
|
||||
times[times.len() / 2]
|
||||
};
|
||||
for (kind, pack) in [("directory", pack), ("deflated zip", zip)] {
|
||||
f.rebuild_matches(std::slice::from_ref(&pack));
|
||||
let vanilla = f.0.join("vanilla");
|
||||
let out = f.0.join("cached");
|
||||
let mut baseline = Vec::new();
|
||||
let mut cold = Vec::new();
|
||||
let mut hit = Vec::new();
|
||||
for _ in 0..11 {
|
||||
let start = Instant::now();
|
||||
build_overlay_uncached(
|
||||
black_box(&vanilla),
|
||||
black_box(std::slice::from_ref(&pack)),
|
||||
black_box(&f.0.join("reference")),
|
||||
&mut Dependencies::default(),
|
||||
)
|
||||
.unwrap();
|
||||
baseline.push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
fs::remove_file(marker_path(&out)).unwrap();
|
||||
let start = Instant::now();
|
||||
packs::build_overlay(
|
||||
black_box(&vanilla),
|
||||
black_box(std::slice::from_ref(&pack)),
|
||||
black_box(&out),
|
||||
)
|
||||
.unwrap();
|
||||
cold.push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
let start = Instant::now();
|
||||
packs::build_overlay(
|
||||
black_box(&vanilla),
|
||||
black_box(std::slice::from_ref(&pack)),
|
||||
black_box(&out),
|
||||
)
|
||||
.unwrap();
|
||||
hit.push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
assert_eq!(
|
||||
output_signature(&out).unwrap(),
|
||||
output_signature(&f.0.join("reference")).unwrap()
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"{kind}: baseline={:.3} ms cold={:.3} ms unchanged={:.3} ms (11 medians, full validation)",
|
||||
median(baseline),
|
||||
median(cold),
|
||||
median(hit)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "content-heavy few-file directory benchmark"]
|
||||
fn benchmark_content_heavy_directory() {
|
||||
use std::{hint::black_box, time::Instant};
|
||||
let f = Fixture::new();
|
||||
f.write("vanilla/facts.json", b"[]");
|
||||
let pack = f.dir_pack("pack");
|
||||
let bytes = vec![42; 8 * 1024 * 1024];
|
||||
for i in 0..4 {
|
||||
f.write(&format!("pack/assets/minecraft/textures/{i}.png"), &bytes);
|
||||
}
|
||||
let vanilla = f.0.join("vanilla");
|
||||
let out = f.0.join("cached");
|
||||
f.rebuild_matches(std::slice::from_ref(&pack));
|
||||
let mut timings = [Vec::new(), Vec::new(), Vec::new()];
|
||||
for _ in 0..11 {
|
||||
let start = Instant::now();
|
||||
build_overlay_uncached(
|
||||
black_box(&vanilla),
|
||||
black_box(std::slice::from_ref(&pack)),
|
||||
&f.0.join("reference"),
|
||||
&mut Dependencies::default(),
|
||||
)
|
||||
.unwrap();
|
||||
timings[0].push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
fs::remove_file(marker_path(&out)).unwrap();
|
||||
for times in &mut timings[1..] {
|
||||
let start = Instant::now();
|
||||
packs::build_overlay(
|
||||
black_box(&vanilla),
|
||||
black_box(std::slice::from_ref(&pack)),
|
||||
black_box(&out),
|
||||
)
|
||||
.unwrap();
|
||||
times.push(start.elapsed().as_secs_f64() * 1000.0);
|
||||
}
|
||||
assert_eq!(
|
||||
output_signature(&out).unwrap(),
|
||||
output_signature(&f.0.join("reference")).unwrap()
|
||||
);
|
||||
}
|
||||
let medians: Vec<_> = timings
|
||||
.into_iter()
|
||||
.map(|mut times| {
|
||||
times.sort_by(f64::total_cmp);
|
||||
times[5]
|
||||
})
|
||||
.collect();
|
||||
println!(
|
||||
"4 x 8 MiB directory textures: baseline={:.3} ms cold={:.3} ms unchanged={:.3} ms (11 medians, full validation)",
|
||||
medians[0], medians[1], medians[2]
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn relative_builder_targets_are_preserved() {
|
||||
|
||||
+10
-14
@@ -20,20 +20,17 @@ Linux x86_64/ext4/NVMe, Ryzen 5 5600X, Rust 1.99.0, Cargo `fast`, measured 2026-
|
||||
|
||||
Unchanged speedups are approximately 226x, 359x and 775x. Cold overhead on these ZIPs is 0.1–2.6%, replacing the original cache implementation's 73–79% synthetic overhead. This measures overlay assembly and cache validation, excluding scan, texture decoding, total startup and FPS.
|
||||
|
||||
Mac mini (M4 Pro, APFS, Rust stable, Cargo `fast`), same harness and packs, measured 2026-10-15 during review while the machine ran other builds:
|
||||
|
||||
| ZIP pack | Original rebuild | Cached cold | Unchanged hit | Saved per hit |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| Faithful 32x, 26.3 September 2026 | 1,184.400 ms | 1,295.069 ms | 0.571 ms | 1,183.829 ms |
|
||||
| FPBR, 1.21.9 R1.3 | 5,292.149 ms | 5,503.965 ms | 0.391 ms | 5,291.758 ms |
|
||||
|
||||
Creating thousands of files and links costs far more on macOS than on Linux, so the saving there is seconds per startup with a pack enabled.
|
||||
|
||||
Pack downloads were verified against publisher SHA-512 metadata. Exact versions, URLs, sizes, asset counts, hashes and prepared-manifest identity are recorded in `benchmarks/overlay-real-packs-2026-10-15.json`. Sources: [Faithful](https://modrinth.com/resourcepack/faithful-32x/version/lDYpMiqk), [Default HD](https://modrinth.com/resourcepack/default-hd-128x/version/rErHu3BE), [FPBR](https://modrinth.com/resourcepack/fpbr/version/dynf82xk). FPBR targets older 1.21.9 snapshots; it is measured as a large real 128x archive over prepared 26.3 resources, without claiming visual/version compatibility. Default HD is the publisher's free demo. Downloaded pack contents are not committed.
|
||||
|
||||
## Synthetic coverage
|
||||
|
||||
The existing fixtures contain 8,192 vanilla textures (128 MiB), 2,048 overrides (32 MiB) and 32 merged language files; equivalent directory/ZIP payloads are incompressible bytes. Eleven median samples compare identical output outside timing:
|
||||
|
||||
| Fixture | Original | Cached cold | Hit |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Directory | 108.487 ms | 126.438 ms | 7.438 ms |
|
||||
| Deflated ZIP, 32.45 MiB | 155.540 ms | 155.453 ms | 0.128 ms |
|
||||
| Directory, four 8 MiB files | 0.115 ms | 0.271 ms | 0.076 ms |
|
||||
|
||||
Directory topology scans remain a cost: the larger directory fixture adds about 17% cold overhead and gains 14.6x on hits. Tiny cold overlays add about 0.16 ms. No overall startup gain is inferred from either table.
|
||||
|
||||
## Reproduce and validate
|
||||
|
||||
```sh
|
||||
@@ -41,10 +38,9 @@ export CARGO_INCREMENTAL=0
|
||||
export HORIZON_OVERLAY_BENCH_VANILLA=/path/to/prepared/26.3
|
||||
export HORIZON_OVERLAY_BENCH_PACKS='["/path/to/Faithful.zip","/path/to/DefaultHD.zip","/path/to/FPBR.zip"]'
|
||||
cargo test -p horizon-client --lib --profile fast packs::cache::tests::benchmark_real_resource_root -- --ignored --nocapture --test-threads=1
|
||||
cargo test -p horizon-client --lib --profile fast packs::cache::tests::benchmark -- --ignored --nocapture --test-threads=1 --skip benchmark_real_resource_root
|
||||
cargo test -p horizon-client --lib --profile fast packs:: -- --nocapture
|
||||
cargo clippy -p horizon-client --lib --tests --profile fast -- -D warnings
|
||||
cargo fmt --all -- --check
|
||||
```
|
||||
|
||||
Thirteen focused tests pass, covering source edits/replacements, Unix preserved-mtime edits, pack order/removal, overlays/filters, vanilla membership, marker/output-root recovery, failed ZIP rebuilds, symlink aliases/cycles, contention and unchanged relative link targets. All three opt-in benchmarks pass; strict Clippy, formatting and whitespace checks pass. Each overlay retains a small marker and empty lock file; cache hits retain no archive byte buffer.
|
||||
Thirteen focused tests pass, covering source edits/replacements, Unix preserved-mtime edits, pack order/removal, overlays/filters, vanilla membership, marker/output-root recovery, failed ZIP rebuilds, symlink aliases/cycles, contention and unchanged relative link targets. The opt-in real-pack benchmark passes; strict Clippy, formatting and whitespace checks pass. Each overlay retains a small marker and empty lock file; cache hits retain no archive byte buffer.
|
||||
Reference in new issue
Block a user