dash_read_bounds: time the short and long runs in turn, the least of seven each #400
1 changed files with 19 additions and 13 deletions
|
|
@ -7,7 +7,7 @@
|
|||
//! compared with each other within a footprint bounded by the document's size: the
|
||||
//! runs are held as written and compared run by run, never expanded.
|
||||
//! - Comparing them takes CPU time that does not grow with the segments a run lists.
|
||||
//! - One element of 40000 attributes is read in time linear in its attributes: the
|
||||
//! - One element of 32000 attributes is read in time linear in its attributes: the
|
||||
//! names already read are kept in a set, not scanned again for each attribute.
|
||||
//!
|
||||
//! Its own test binary with a single test, so that no other test's allocations land in
|
||||
|
|
@ -91,13 +91,17 @@ fn peak<T>(f: impl FnOnce() -> T) -> (T, usize) {
|
|||
(out, PEAK.load(Relaxed) - start)
|
||||
}
|
||||
|
||||
/// The CPU time of the best of three runs of `f`.
|
||||
fn cpu(f: impl Fn()) -> Duration {
|
||||
(0..3).map(|_| {
|
||||
/// The least CPU time of `f` and of `g` over seven runs each, taken in turn. On a virtual
|
||||
/// machine a thread's CPU clock also counts the time its host held the virtual CPU, so a
|
||||
/// busy host slows every run: taking the two in turn lets a busy spell slow both alike, and
|
||||
/// the least of each is the run it disturbed least.
|
||||
fn cpu_pair(f: impl Fn(), g: impl Fn()) -> (Duration, Duration) {
|
||||
let time = |h: &dyn Fn()| {
|
||||
let t = now();
|
||||
f();
|
||||
h();
|
||||
now() - t
|
||||
}).min().expect("three runs")
|
||||
};
|
||||
(0..7).map(|_| (time(&f), time(&g))).fold((Duration::MAX, Duration::MAX), |(a, b), (x, y)| (a.min(x), b.min(y)))
|
||||
}
|
||||
|
||||
/// `n` Representations, each a timeline of one `S` of 2^20 segments.
|
||||
|
|
@ -141,13 +145,15 @@ fn an_mpd_is_held_as_written_and_read_in_linear_time() {
|
|||
// themselves, take about the CPU time of 32 timelines of 2^10; one that steps a
|
||||
// segment at a time takes about a thousand times as long.
|
||||
let (few, many) = (bomb_of(32, 1 << 10), bomb_of(32, 1 << 20));
|
||||
let (t_few, t_many) = (cpu(|| check_dash_adjacent(&few, &few).unwrap()), cpu(|| check_dash_adjacent(&many, &many).unwrap()));
|
||||
let (t_few, t_many) = cpu_pair(|| check_dash_adjacent(&few, &few).unwrap(), || check_dash_adjacent(&many, &many).unwrap());
|
||||
assert!(t_many <= t_few * 4 + Duration::from_millis(20), "2^20 segments a timeline took {t_many:?}, 2^10 took {t_few:?}");
|
||||
// One element of 40000 attributes against one of 10000: linear, so about four times
|
||||
// the CPU time; a reader that scans the names read so far for each one takes about
|
||||
// sixteen times. The margin keeps a loaded host from deciding it.
|
||||
let (short, long) = (wide(10_000), wide(40_000));
|
||||
// One element of 32000 attributes against one of 1000: linear, so about 32 times the
|
||||
// CPU time, and up to about three times that again where the larger element's sets
|
||||
// leave a cache a busy host shares; a reader that scans the names read so far for each
|
||||
// one takes about a thousand times. The sizes are 32 apart so that no cache effect
|
||||
// reaches the bound between the two.
|
||||
let (short, long) = (wide(1_000), wide(32_000));
|
||||
read_xml(&long).unwrap();
|
||||
let (t_short, t_long) = (cpu(|| drop(read_xml(&short))), cpu(|| drop(read_xml(&long))));
|
||||
assert!(t_long <= t_short * 8 + Duration::from_millis(20), "40000 attributes took {t_long:?}, 10000 took {t_short:?}");
|
||||
let (t_short, t_long) = cpu_pair(|| drop(read_xml(&short)), || drop(read_xml(&long)));
|
||||
assert!(t_long <= t_short * 256 + Duration::from_millis(20), "32000 attributes took {t_long:?}, 1000 took {t_short:?}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue