c++ - Alternative for std::set without memory reallocation? -
in application generate lot of subproblems exhaustively , solve them using "std::set" operations. need "insert" , "find" elements , "iterate" on sorted list.
the problem each of millions of subproblems "std::set" implementation allocates new memory each time insert element in set makes whole application slow:
{ // allocate non-value node _nodeptr _pnode = this->_getal().allocate(1); // <- bottleneck of program
is there stl-structure allows me to above operations in "o(log(n))" while not reallocating memory?
using custom allocator seems way reduce amount of time spent building , releasing std::set<...>
. below complete demo of simple allocator program profiling resulting times.
#include <algorithm> #include <chrono> #include <cstdlib> #include <iostream> #include <iterator> #include <memory> #include <set> #include <vector> // ---------------------------------------------------------------------------- template <typename t, std::size_t pool_size = 1024> class pool_allocator { private: std::vector<t*> d_pools; t* d_next; t* d_end; public: template <typename o> struct rebind { typedef pool_allocator<o, pool_size> other; }; pool_allocator(): d_next(), d_end() {} ~pool_allocator() { std::for_each(this->d_pools.rbegin(), this->d_pools.rend(), [](t* memory){ operator delete(memory); }); } typedef t value_type; t* allocate(std::size_t n) { if (std::size_t(this->d_end - this->d_next) < n) { if (pool_size < n) { // custom allocation bigger number of objects this->d_pools.push_back(static_cast<t*>(operator new(sizeof(t) * n))); return this->d_pools.back(); } this->d_pools.push_back(static_cast<t*>(operator new(sizeof(t) * pool_size))); this->d_next = this->d_pools.back(); this->d_end = this->d_next + pool_size; } t* rc(this->d_next); this->d_next += n; return rc; } void deallocate(t*, std::size_t) { // try recycle buffers } }; // ---------------------------------------------------------------------------- template <typename allocator> void time(char const* name, std::vector<int> const& random) { std::cout << "running " << name << std::flush; using namespace std::chrono; high_resolution_clock::time_point start(high_resolution_clock::now()); std::size_t size(0); { std::set<int, std::less<int>, allocator> values; (int value: random) { values.insert(value); } size = values.size(); } high_resolution_clock::time_point end(high_resolution_clock::now()); std::cout << ": size=" << size << " time=" << duration_cast<milliseconds>(end - start).count() << "ms\n"; } // ---------------------------------------------------------------------------- int main() { std::cout << "preparing..." << std::flush; std::size_t count(10000000); std::vector<int> random; random.reserve(count); std::generate_n(std::back_inserter(random), count, [](){ return std::rand(); }); std::cout << "done\n"; time<std::allocator<int>>("default allocator ", random); time<pool_allocator<int, 32>>("custom allocator (32) ", random); time<pool_allocator<int, 256>>("custom allocator (256) ", random); time<pool_allocator<int, 1024>>("custom allocator (1024)", random); time<pool_allocator<int, 2048>>("custom allocator (2048)", random); time<pool_allocator<int, 4096>>("custom allocator (4096)", random); time<std::allocator<int>>("default allocator ", random); } // results clang/libc++: // preparing...done // running default allocator : size=10000000 time=13927ms // running custom allocator (32) : size=10000000 time=9260ms // running custom allocator (256) : size=10000000 time=9511ms // running custom allocator (1024): size=10000000 time=9172ms // running custom allocator (2048): size=10000000 time=9153ms // running custom allocator (4096): size=10000000 time=9599ms // running default allocator : size=10000000 time=13730ms // results gcc/libstdc++: // preparing...done // running default allocator : size=10000000 time=15814ms // running custom allocator (32) : size=10000000 time=10868ms // running custom allocator (256) : size=10000000 time=10229ms // running custom allocator (1024): size=10000000 time=10556ms // running custom allocator (2048): size=10000000 time=10392ms // running custom allocator (4096): size=10000000 time=10664ms // running default allocator : size=10000000 time=17941ms
Comments
Post a Comment