use std::io::{self, Write};
use subms::{SubMsLcg, SubMsPerfHarness, summarize, summary_to_json};
use subms_treap::Treap;
const ENTRIES: usize = 50_000;
const SEED: u64 = 0;
fn keys(seed: u64, count: usize) -> Vec<u64> {
let mut rng = SubMsLcg::new(seed);
(0..count).map(|_| rng.next_u32() as u64).collect()
}
fn main() -> io::Result<()> {
std::thread::Builder::new()
.stack_size(256 * 1024 * 1024)
.spawn(run)
.expect("spawn worker thread")
.join()
.expect("worker thread panicked")
}
fn run() -> io::Result<()> {
let mut h = SubMsPerfHarness::new("treap-features", "rust");
h.input("entries", &ENTRIES.to_string());
h.input("seed", &SEED.to_string());
let key_set = keys(SEED, ENTRIES);
{
let mut t: Treap<u64, u64> = Treap::with_capacity(SEED, ENTRIES);
let stage = h.stage("base_insert", ENTRIES);
for &k in &key_set {
stage.time(|| {
t.insert(k, k);
});
}
let stage = h.stage("base_get", ENTRIES);
for &k in &key_set {
stage.time(|| {
let _ = t.get(&k);
});
}
}
#[cfg(feature = "range-query")]
{
use subms_treap::RangeBound;
let mut t: Treap<u64, u64> = Treap::with_capacity(SEED, ENTRIES);
for k in 0..ENTRIES as u64 {
t.insert(k, k);
}
const WINDOW: u64 = 256;
let max_start = ENTRIES as u64 - WINDOW - 1;
let stage = h.stage("range", ENTRIES);
let mut rng = SubMsLcg::new(SEED ^ 0x9e37);
for _ in 0..ENTRIES {
let from = (rng.next_u32() as u64) % max_start;
let to = from + WINDOW;
stage.time(|| {
let mut it = t.range(RangeBound::Inclusive(&from), RangeBound::Inclusive(&to));
let _ = it.next();
});
}
let stage = h.stage("next", ENTRIES);
let mut rng = SubMsLcg::new(SEED ^ 0x9e37);
let mut recorded = 0usize;
'outer: loop {
let from = (rng.next_u32() as u64) % max_start;
let to = from + WINDOW;
let mut it = t.range(RangeBound::Inclusive(&from), RangeBound::Inclusive(&to));
let _ = it.next();
loop {
let advanced = stage.time(|| it.next().is_some());
if !advanced {
break;
}
recorded += 1;
if recorded >= ENTRIES {
break 'outer;
}
}
}
}
#[cfg(feature = "persistent")]
{
use subms_treap::PersistentTreap;
let mut t: PersistentTreap<u64, u64> = PersistentTreap::new(SEED);
let stage = h.stage("persistent_insert", ENTRIES);
for &k in &key_set {
t = stage.time(|| t.insert(k, k));
}
let final_version = t;
let stage = h.stage("persistent_get", ENTRIES);
for &k in &key_set {
stage.time(|| {
let _ = final_version.get(&k);
});
}
}
#[cfg(feature = "merge-split")]
{
use subms_treap::SplittableTreap;
const MS_ROUNDS: usize = 2_000;
let mut tree: SplittableTreap<u64, u64> = SplittableTreap::new(SEED);
for &k in &key_set {
tree.insert(k, k);
}
let pivots = keys(SEED ^ 0x5151, MS_ROUNDS);
let mut split_samples = Vec::with_capacity(MS_ROUNDS);
let mut merge_samples = Vec::with_capacity(MS_ROUNDS);
for &pivot in &pivots {
let t0 = std::time::Instant::now();
let (lo, hi) = tree.split(&pivot);
split_samples.push(t0.elapsed().as_nanos() as u64);
let t1 = std::time::Instant::now();
tree = SplittableTreap::merge(lo, hi);
merge_samples.push(t1.elapsed().as_nanos() as u64);
}
let stage = h.stage("split", split_samples.len());
for ns in split_samples {
stage.record(ns);
}
let stage = h.stage("merge", merge_samples.len());
for ns in merge_samples {
stage.record(ns);
}
}
#[cfg(feature = "concurrent-reads")]
{
use subms_treap::TreapSnapshot;
let mut t: Treap<u64, u64> = Treap::with_capacity(SEED, ENTRIES);
for &k in &key_set {
t.insert(k, k);
}
let stage = h.stage("snapshot", 32);
let mut snap = TreapSnapshot::from_treap(&t);
for _ in 0..32 {
snap = stage.time(|| TreapSnapshot::from_treap(&t));
}
let stage = h.stage("get_on_snapshot", ENTRIES);
for &k in &key_set {
stage.time(|| {
let _ = snap.get(&k);
});
}
}
let summary = summarize(&h);
let mut stdout = io::stdout();
summary_to_json(&summary, &mut stdout)?;
writeln!(stdout)?;
Ok(())
}