Delete OrthoSize, and run the seeds in parallel
A span is as long across itself as its longest child, unless a rule beside it already says how long it is -- and then reading the children answers nothing and only makes its size depend on theirs. `OrthoSize::Full` was that second case written twice, once as an enum on the span and once as the rule that actually decides; `Painter::ruled` lets the span ask which it is in. The widget under a rule still does not learn what the rule says, only that its answer for that axis is not wanted. The fuzzers grow, lay out and drop a tree within one seed, so the seeds share nothing and take a thread each, one short of every core. Measured here: the generated oracle's hundred seeds went from 68 s to 10 s, and a shrinker case at 300 seeds from 18 s to 3.5 s. A seed that fails still shrinks and panics on its own thread, and `std::thread::scope` carries that out. The shrinker now allows the two steps the oracle already did -- the deeper trees these grow reach a second composition, and a step is a thousandth of a pixel. Checked: fmt, clippy, 102 tests, all five shrinker cases at 300 seeds, 100 generated seeds, and five examples byte-identical at 1920x1200. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb955f1023
commit
9d8415d65f
8 files changed
+94
-74
No files matched your search
+21
-4
@@ -216,10 +216,9 @@ fn describe_widget(id: WidgetId, h: &Harness) -> String {
|
||||
if let Some(w) = any.downcast_ref::<Span>() {
|
||||
let sign = if w.dir.sign == Sign::Neg { "-" } else { "+" };
|
||||
return format!(
|
||||
"Span{{dir:{:?}{sign},gap:{},ortho:{:?},n:{}}}",
|
||||
"Span{{dir:{:?}{sign},gap:{},n:{}}}",
|
||||
w.dir.axis,
|
||||
w.gap,
|
||||
w.ortho,
|
||||
w.children.len()
|
||||
);
|
||||
}
|
||||
@@ -555,7 +554,7 @@ fn a_long_run_of_seeds_agrees() {
|
||||
.and_then(|seed| seed.parse().ok())
|
||||
.map(|seed| seed..=seed)
|
||||
.unwrap_or_else(|| 1..=env("IRIS_GENERATED_SEEDS", 100));
|
||||
for seed in seeds {
|
||||
over_seeds(seeds.collect(), |seed| {
|
||||
changed_size(seed);
|
||||
changed_every_size(seed);
|
||||
repainted_together(seed);
|
||||
@@ -564,5 +563,23 @@ fn a_long_run_of_seeds_agrees() {
|
||||
for shuffle in SHUFFLES {
|
||||
reshuffled(seed, shuffle);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Every seed on its own thread's share of them. A tree is grown, laid out
|
||||
/// and dropped inside one call, so seeds share nothing, and this is most of
|
||||
/// the time a run takes. A thread that fails takes the scope down with it,
|
||||
/// which is the same panic libtest would have seen.
|
||||
///
|
||||
/// One core short of all of them, so the machine this runs on stays usable.
|
||||
pub fn over_seeds(seeds: Vec<u64>, run: impl Fn(u64) + Sync) {
|
||||
let threads =
|
||||
std::thread::available_parallelism().map_or(1, |n| n.get().saturating_sub(1).max(1));
|
||||
let chunk = seeds.len().div_ceil(threads).max(1);
|
||||
std::thread::scope(|scope| {
|
||||
for part in seeds.chunks(chunk) {
|
||||
let run = &run;
|
||||
scope.spawn(move || part.iter().for_each(|&seed| run(seed)));
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user