Open
Description
Background
To use rayon in game engine code, I was investigating why ThreadPool::install
was allocating every invocation. It turned out there are two sources of allocation,
- One was a
LockLatch
, that was allocating aMutex
and aCondvar
every call. - Then there was a larger, intermittent allocation happening every 32 frames. I traced this back to
SegQueue
.
Observation
If i run this simple test app:
let x: SegQueue<u32> = SegQueue::new();
for i in 0..100 {
measure("push_pop", || {
x.push(1);
x.pop();
});
}
I receive the following allocation events:
"push_pop" -- Events: 1, Bytes: 504
"push_pop" -- Events: 0, Bytes: 0
...
... 32 invocations later ...
...
"push_pop" -- Events: 0, Bytes: 0
"push_pop" -- Events: 1, Bytes: 504
The allocation is caused by these lines:
if offset + 1 == BLOCK_CAP && next_block.is_none() {
next_block = Some(Box::new(Block::<T>::new()));
}
Which, in turn is caused by the tail just growing:
offset 0 ... tail 0
offset 1 ... tail 2
offset 2 ... tail 4
offset 3 ... tail 6
[...]
offset 29 ... tail 58
offset 30 ... tail 60
offset 0 ... tail 64
Issue
I have to admit that I'm not 100% if this is really a bug, or just a "feature" of the algorithm, but
I would naively expect that a loop of q.push(x); q.pop();
would not cause the SegQueue
to reallocate.