Answer "have I asked this child?" in one read
A container's draw asked it once per child by searching the list of children it had added so far, and four other per-child steps searched a list too, so one draw cost the square of its children: 70% of a 1,600-child redraw was those searches. A draw takes a DrawId and leaves it on every widget it asks about; one note per widget is enough because the handle a container holds a child by cannot be cloned. tests/children_cost.rs is the rig that shows it, and it is the only one here that varies width: 3.680 ms to 0.811 ms at 1,600 children, and flat per child. Beside it, the rest of the fourteenth sweep of #19: a mask's rectangle resolved once per fragment instead of once per instance, which takes the storage buffers out of the fragment stage and is 8.8x on a screenful of deeply nested clips; TextBuffer::shape copying its attrs before the check that would not need them, which allocated once per named-family text per frame; a should_panic test on a debug assertion that made cargo test --release fail; Fixed::div, reached only by its own test; Moves::remove re-uploading an array it cannot have changed; and two comments the branch itself falsified. docs/LAYOUT_LOG.md has all eight with their measurements, the five things looked at and left, and what was verified.
This commit is contained in:
1 parent
cbccfb600a
commit
97fca76108
17 files changed
+588
-149
No files matched your search
@@ -0,0 +1,59 @@
|
||||
//! What one container's draw costs against the number of children it has.
|
||||
//!
|
||||
//! cargo test --release --test children_cost -- --ignored --nocapture
|
||||
//!
|
||||
//! Every other rig here varies depth, the window, or what changed between
|
||||
//! frames; this one varies width, which is the dimension a container's own
|
||||
//! per-child bookkeeping is counted in. A list of rows is the shape that gets
|
||||
//! wide -- a transcript, a file tree -- and a cost per child that is not flat
|
||||
//! down this table is a cost paid twice for every child added.
|
||||
//!
|
||||
//! Wall time rather than instructions, because what is being told apart here
|
||||
//! is a factor rather than a few percent, and the table says which it is: a
|
||||
//! flat right-hand column is linear and a rising one is not.
|
||||
|
||||
mod rig;
|
||||
|
||||
use iris::harness::Harness;
|
||||
use iris::prelude::*;
|
||||
use rig::env;
|
||||
use std::time::Instant;
|
||||
|
||||
/// A column of leaves each with a length of its own, so the span asks every
|
||||
/// one of them and reads what each answered.
|
||||
fn build(h: &mut Harness, children: usize) -> WidgetId {
|
||||
let mut col = Span::empty(Dir::DOWN);
|
||||
for _ in 0..children {
|
||||
col.push(
|
||||
rect(Color::RED)
|
||||
.height(LayoutLen::px(4.0))
|
||||
.add_strong(&mut h.rsc),
|
||||
);
|
||||
}
|
||||
let root = col.add(&mut h.rsc);
|
||||
h.set_root(root);
|
||||
root.id()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "measurement, not a check"]
|
||||
fn draw_cost_by_children() {
|
||||
let frames = env("FRAMES", 40_usize);
|
||||
println!("{frames} full redraws of one span, per child in the last column");
|
||||
for children in [100_usize, 200, 400, 800, 1600] {
|
||||
// Tall enough that no child is collapsed for want of room.
|
||||
let mut h = Harness::new((600.0, children as f32 * 8.0));
|
||||
let root = build(&mut h, children);
|
||||
h.frame();
|
||||
let start = Instant::now();
|
||||
for _ in 0..frames {
|
||||
h.rsc.widgets_mut().mark_for_redraw(root);
|
||||
h.frame();
|
||||
}
|
||||
let ms = start.elapsed().as_secs_f64() * 1000.0 / frames as f64;
|
||||
println!(
|
||||
"children {children:>5}: {ms:>8.3} ms per redraw, {:>7.4} ms each",
|
||||
ms / children as f64
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user