Skip to content

Commit

Permalink
fix: make util::stack run in polynomial time
Browse files Browse the repository at this point in the history
Make it run in C*N time instead of N^C (where C is the number of
batches and N is the length of the batch).

This is hardly the most important code to optimize, but...
  • Loading branch information
Stebalien committed Jan 10, 2024
1 parent 1d85ec5 commit 68ff3e4
Showing 1 changed file with 24 additions and 23 deletions.
47 changes: 24 additions & 23 deletions runtime/src/util/batch_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,36 +104,37 @@ pub fn stack(batch_returns: &[BatchReturn]) -> BatchReturn {
if batch_returns.is_empty() {
return BatchReturn::empty();
}
let mut base = batch_returns[0].clone();
let total_size = batch_returns[0].size();
let mut success_count = batch_returns[0].success_count;
for nxt in &batch_returns[1..] {
assert_eq!(
base.success_count as usize,
success_count as usize,
nxt.size(),
"can't stack batch of {} on batch with {} successes",
nxt.size(),
base.success_count
success_count
);
let mut nxt_fail = nxt.fail_codes.iter().peekable();
let mut base_fail = base.fail_codes.iter().peekable();
let mut offset = 0;
let mut new_fail_codes = vec![];
while nxt_fail.peek().is_some() {
let nxt_fail = nxt_fail.next().unwrap();
while base_fail.peek().is_some()
&& base_fail.peek().unwrap().idx <= nxt_fail.idx + offset
{
base_fail.next();
offset += 1;
}
new_fail_codes.push(FailCode { idx: nxt_fail.idx + offset, code: nxt_fail.code })
}
base.fail_codes.extend(new_fail_codes);
base.fail_codes.sort_by(|a, b| a.idx.cmp(&b.idx));
base.success_count = nxt.success_count;
success_count = nxt.success_count;
}

let mut fail_codes = Vec::with_capacity(batch_returns.iter().map(|b| b.fail_codes.len()).sum());
let mut offsets = vec![0u32; batch_returns.len()];
let mut input: Vec<_> = batch_returns.iter().map(|b| b.fail_codes.iter().peekable()).collect();
while let Some((i, f)) = input
.iter_mut()
.zip(&offsets)
.enumerate()
.filter_map(|(i, (fc, &offset))| {
fc.peek().map(|&&FailCode { idx, code }| (i, FailCode { idx: idx + offset, code }))
})
.min_by_key(|(_, fc)| fc.idx)
{
input[i].next();
offsets[i + 1..].iter_mut().for_each(|c| *c += 1);
fail_codes.push(f)
}
assert_eq!(base.size(), batch_returns[0].size());
assert_eq!(base.success_count, batch_returns[batch_returns.len() - 1].success_count);
base
debug_assert_eq!(total_size, fail_codes.len() + success_count as usize);
BatchReturn { success_count, fail_codes }
}

pub struct BatchReturnGen {
Expand Down

0 comments on commit 68ff3e4

Please sign in to comment.