Skip to content

SegQueue::push() ... pop() keeps allocating.  #398

Open
@ralfbiedert

Description

@ralfbiedert

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 a Mutex and a Condvar 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions