Search code examples
c++priority-queueevent-driven

Pool memory allocation in a priority queue


I am writing an event based simulator, in which each event calls a processing function (node) that can generate new events, and so on. A timestamp is associated to each events and they need to be processed in the order of increasing time (but the events are not necessarily created in that order). To this end, I use a simple priority_queue<Event*>, where Event is a class containing a pointer to the processing node that must be called and the timestamp.

So, everything works fine, but I get millions of events allocated and deallocated per second and this is clearly what is limiting the speed of my simulator (roughly 30% of the execution time is taken by memory allocation and deallocation of Event objects).

I found this question: Object pool vs. dynamic allocation and it seems like I could very much benefit from an object pool. Although I have seen that Boost is offering some way to do that, I am not sure to understand if this is practical for implementing a pool in a priority_queue. I am really lost when it comes to custom memory allocation.

So my question is: would it be practical / beneficial to use an object pool for my priority_queue, and if yes, is there a simple way to do it, with maybe some code example (or at least a starting point), preferably without immediately relying on Boost in a first time?

Actually some refs to understand how pool allocation works would also be welcome!

Thanks.


Solution

  • A quick and dirty example of an object pool

    EventPool.h

    #include <stack>
    class Event;
    
    class EventPool
    {
     public:
       explicit EventPool(const unsigned int initSize = 0);
       ~EventPool();
       Event* getEvent();
       void returnEvent(Event* e);
     private:
       std::stack<Event*> pool_;
    };
    

    EventPool.cxx

    #include <Event.h>
    #include <EventPool.h>
    
    EventPool::EventPool(const unsigned int initSize)
    {
       for(unsigned int i = 0; i < initSize; ++i)
       {
          pool_.push(new Event());
       }
    }
    
    EventPool::~EventPool()
    {
       while(!pool_.empty())
       {
          delete pool_.top();
          pool_.pop();
       }
    }
    
    Event* EventPool::getEvent()
    {
       if(pool_.empty())
       {
          return new Event();
       }
       Event* returnValue = pool_.top();
       pool_.pop();
       return returnValue;
    }
    
    void EventPool::returnEventToPool(Event* e)
    {
       pool_.push(e);
    }
    

    By doing this, you can allow the pool to control the size of itself. When another object grabs an event, it is up to the grabber to either give the event back or delete it.