optimize the memory allocator

This commit is contained in:
mutouyun 2019-10-07 11:23:31 +00:00
parent 45bf1a7b38
commit 448a4883f6
8 changed files with 315 additions and 219 deletions

1
build/CMakeLists.txt Normal file → Executable file
View File

@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.10)
project(cpp-ipc) project(cpp-ipc)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG")
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
endif() endif()

0
build/ipc/CMakeLists.txt Normal file → Executable file
View File

Binary file not shown.

View File

@ -5,11 +5,13 @@
#include <cstdlib> #include <cstdlib>
#include <map> #include <map>
#include <iterator> #include <iterator>
#include <cassert> // assert
#include "def.h" #include "def.h"
#include "rw_lock.h" #include "rw_lock.h"
#include "concept.h" #include "concept.h"
#include "memory/allocator_wrapper.h"
#include "platform/detail.h" #include "platform/detail.h"
namespace ipc { namespace ipc {
@ -42,7 +44,7 @@ constexpr std::size_t aligned(std::size_t size, size_t alignment) noexcept {
return ((size - 1) & ~(alignment - 1)) + alignment; return ((size - 1) & ~(alignment - 1)) + alignment;
} }
IPC_CONCEPT_(has_take, take(Type{})); IPC_CONCEPT_(has_take, take(std::move(std::declval<Type>())));
class scope_alloc_base { class scope_alloc_base {
protected: protected:
@ -163,6 +165,10 @@ protected:
} }
public: public:
bool operator<(fixed_alloc_base const & right) const {
return init_expand_ < right.init_expand_;
}
void set_block_size(std::size_t block_size) { void set_block_size(std::size_t block_size) {
block_size_ = block_size; block_size_ = block_size;
} }
@ -178,6 +184,7 @@ public:
} }
void take(fixed_alloc_base && rhs) { void take(fixed_alloc_base && rhs) {
assert(block_size_ == rhs.block_size_);
init_expand_ = (ipc::detail::max)(init_expand_, rhs.init_expand_); init_expand_ = (ipc::detail::max)(init_expand_, rhs.init_expand_);
if (rhs.empty()) return; if (rhs.empty()) return;
auto curr = cursor_; auto curr = cursor_;
@ -265,10 +272,11 @@ public:
} // namespace detail } // namespace detail
template <std::size_t BaseSize = sizeof(void*) * 1024>
struct fixed_expand_policy { struct fixed_expand_policy {
enum : std::size_t { enum : std::size_t {
base_size = sizeof(void*) * 1024 base_size = BaseSize
}; };
constexpr static std::size_t prev(std::size_t e) noexcept { constexpr static std::size_t prev(std::size_t e) noexcept {
@ -288,7 +296,7 @@ struct fixed_expand_policy {
template <std::size_t BlockSize, template <std::size_t BlockSize,
typename AllocP = scope_alloc<>, typename AllocP = scope_alloc<>,
typename ExpandP = fixed_expand_policy> typename ExpandP = fixed_expand_policy<>>
class fixed_alloc : public detail::fixed_alloc<AllocP, ExpandP> { class fixed_alloc : public detail::fixed_alloc<AllocP, ExpandP> {
public: public:
using base_t = detail::fixed_alloc<AllocP, ExpandP>; using base_t = detail::fixed_alloc<AllocP, ExpandP>;
@ -298,10 +306,12 @@ public:
}; };
public: public:
explicit fixed_alloc(std::size_t init_expand = 1) explicit fixed_alloc(std::size_t init_expand)
: base_t(block_size) { : base_t(block_size, init_expand) {
} }
fixed_alloc() : fixed_alloc(1) {}
fixed_alloc(fixed_alloc && rhs) fixed_alloc(fixed_alloc && rhs)
: base_t(std::move(rhs)) { : base_t(std::move(rhs)) {
} }
@ -328,8 +338,6 @@ protected:
std::size_t free_; std::size_t free_;
} * head_ = nullptr; } * head_ = nullptr;
std::map<std::size_t, head_t*, std::greater<std::size_t>> reserves_;
enum : std::size_t { enum : std::size_t {
aligned_head_size = aligned(sizeof(head_t), alignof(std::max_align_t)) aligned_head_size = aligned(sizeof(head_t), alignof(std::max_align_t))
}; };
@ -339,6 +347,10 @@ protected:
} }
public: public:
bool operator<(variable_alloc_base const & right) const {
return remain() < right.remain();
}
void swap(variable_alloc_base& rhs) { void swap(variable_alloc_base& rhs) {
std::swap(head_, rhs.head_); std::swap(head_, rhs.head_);
} }
@ -351,7 +363,33 @@ public:
return remain() == 0; return remain() == 0;
} }
void take(variable_alloc_base && rhs) { void free(void* /*p*/) {}
void free(void* /*p*/, std::size_t) {}
};
} // namespace detail
template <std::size_t ChunkSize = (sizeof(void*) * 1024), typename AllocP = scope_alloc<>>
class variable_alloc : public detail::variable_alloc_base {
public:
using base_t = detail::variable_alloc_base;
using head_t = base_t::head_t;
using alloc_policy = AllocP;
private:
template <typename T>
struct fixed_alloc_t : public fixed_alloc<sizeof(T), alloc_policy> {};
template <typename T>
using allocator = allocator_wrapper<T, fixed_alloc_t<T>>;
std::map<std::size_t, head_t*, std::greater<std::size_t>,
allocator<std::pair<const std::size_t, head_t*>>
> reserves_;
alloc_policy alloc_;
void take_base(variable_alloc && rhs) {
if (rhs.remain() > remain()) { if (rhs.remain() > remain()) {
if (!empty()) { if (!empty()) {
reserves_.emplace(head_->free_, head_); reserves_.emplace(head_->free_, head_);
@ -364,22 +402,6 @@ public:
rhs.head_ = nullptr; rhs.head_ = nullptr;
} }
void free(void* /*p*/) {}
void free(void* /*p*/, std::size_t) {}
};
} // namespace detail
template <std::size_t ChunkSize = (sizeof(void*) * 1024), typename AllocP = scope_alloc<>>
class variable_alloc : public detail::variable_alloc_base {
public:
using base_t = detail::variable_alloc_base;
using head_t = base_t::head_t;
using alloc_policy = AllocP;
private:
alloc_policy alloc_;
public: public:
variable_alloc() = default; variable_alloc() = default;
@ -393,13 +415,13 @@ public:
template <typename A = AllocP> template <typename A = AllocP>
auto take(variable_alloc && rhs) -> ipc::require<detail::has_take<A>::value> { auto take(variable_alloc && rhs) -> ipc::require<detail::has_take<A>::value> {
base_t::take(std::move(rhs)); take_base(std::move(rhs));
alloc_.take(std::move(rhs.alloc_)); alloc_.take(std::move(rhs.alloc_));
} }
template <typename A = AllocP> template <typename A = AllocP>
auto take(variable_alloc && rhs) -> ipc::require<!detail::has_take<A>::value> { auto take(variable_alloc && rhs) -> ipc::require<!detail::has_take<A>::value> {
base_t::take(std::move(rhs)); take_base(std::move(rhs));
} }
void* alloc(std::size_t size) { void* alloc(std::size_t size) {

133
src/memory/allocator_wrapper.h Executable file
View File

@ -0,0 +1,133 @@
#pragma once
#include <limits> // std::numeric_limits
#include <utility> // std::forward
#include <cstddef>
#include <new> // ::new
namespace ipc {
namespace mem {
////////////////////////////////////////////////////////////////
/// The allocator wrapper class for STL
////////////////////////////////////////////////////////////////
namespace detail {
template <typename T, typename AllocP>
struct rebind {
template <typename U>
using alloc_t = AllocP;
};
template <template <typename U> class AllocT, typename T>
struct rebind<T, AllocT<T>> {
template <typename U>
using alloc_t = AllocT<U>;
};
} // namespace detail
template <typename T, typename AllocP>
class allocator_wrapper {
template <typename U, typename AllocU>
friend class allocator_wrapper;
public:
// type definitions
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef AllocP alloc_policy;
private:
alloc_policy alloc_;
public:
allocator_wrapper() noexcept {}
allocator_wrapper(const allocator_wrapper<T, AllocP>& rhs) noexcept
: alloc_(rhs.alloc_)
{}
template <typename U>
allocator_wrapper(const allocator_wrapper<U, AllocP>& rhs) noexcept
: alloc_(rhs.alloc_)
{}
allocator_wrapper(allocator_wrapper<T, AllocP>&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
{}
template <typename U>
allocator_wrapper(allocator_wrapper<U, AllocP>&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
{}
allocator_wrapper(const AllocP& rhs) noexcept
: alloc_(rhs)
{}
allocator_wrapper(AllocP&& rhs) noexcept
: alloc_(std::move(rhs))
{}
public:
// the other type of std_allocator
template <typename U>
struct rebind { typedef allocator_wrapper< U, typename detail::rebind<T, AllocP>::template alloc_t<U> > other; };
constexpr size_type max_size(void) const noexcept {
return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
}
public:
pointer allocate(size_type count) noexcept {
if (count == 0) return nullptr;
if (count > this->max_size()) return nullptr;
return static_cast<pointer>(alloc_.alloc(count * sizeof(value_type)));
}
void deallocate(pointer p, size_type count) noexcept {
alloc_.free(p, count * sizeof(value_type));
}
template <typename... P>
static void construct(pointer p, P && ... params) {
::new (static_cast<void*>(p)) value_type(std::forward<P>(params) ...);
}
static void destroy(pointer p) {
p->~value_type();
}
};
template <class AllocP>
class allocator_wrapper<void, AllocP> {
public:
// type definitions
typedef void value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef AllocP alloc_policy;
};
template <typename T, typename U, class AllocP>
constexpr bool operator==(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
return true;
}
template <typename T, typename U, class AllocP>
constexpr bool operator!=(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
return false;
}
} // namespace mem
} // namespace ipc

View File

@ -17,13 +17,9 @@
namespace ipc { namespace ipc {
namespace mem { namespace mem {
using chunk_variable_alloc =
static_wrapper<async_wrapper<variable_alloc<
sizeof(void*) * 1024 * 256 /* 2MB(x64) */ >>>;
using async_pool_alloc = using async_pool_alloc =
static_variable_wrapper<async_wrapper<detail::fixed_alloc< static_wrapper<variable_wrapper<async_wrapper<detail::fixed_alloc<
chunk_variable_alloc, fixed_expand_policy>>>; scope_alloc<>, fixed_expand_policy<> >>>>;
template <typename T> template <typename T>
using allocator = allocator_wrapper<T, async_pool_alloc>; using allocator = allocator_wrapper<T, async_pool_alloc>;

View File

@ -1,15 +1,14 @@
#pragma once #pragma once
#include <limits>
#include <new> // ::new
#include <tuple> #include <tuple>
#include <thread> #include <thread>
#include <vector> #include <set> // std::set
#include <functional> // std::function #include <functional> // std::function
#include <utility> // std::forward #include <utility> // std::forward
#include <cstddef> #include <cstddef>
#include <cassert> // assert #include <cassert> // assert
#include <type_traits> // std::aligned_storage_t #include <type_traits> // std::aligned_storage_t
#include <new> // ::new
#include "def.h" #include "def.h"
#include "rw_lock.h" #include "rw_lock.h"
@ -22,157 +21,96 @@
namespace ipc { namespace ipc {
namespace mem { namespace mem {
////////////////////////////////////////////////////////////////
/// The allocator wrapper class for STL
////////////////////////////////////////////////////////////////
template <typename T, typename AllocP>
class allocator_wrapper {
template <typename U, typename AllocU>
friend class allocator_wrapper;
public:
// type definitions
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef AllocP alloc_policy;
private:
alloc_policy alloc_;
public:
allocator_wrapper(void) noexcept = default;
allocator_wrapper(const allocator_wrapper<T, AllocP>& rhs) noexcept
: alloc_(rhs.alloc_)
{}
template <typename U>
allocator_wrapper(const allocator_wrapper<U, AllocP>& rhs) noexcept
: alloc_(rhs.alloc_)
{}
allocator_wrapper(allocator_wrapper<T, AllocP>&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
{}
template <typename U>
allocator_wrapper(allocator_wrapper<U, AllocP>&& rhs) noexcept
: alloc_(std::move(rhs.alloc_))
{}
allocator_wrapper(const AllocP& rhs) noexcept
: alloc_(rhs)
{}
allocator_wrapper(AllocP&& rhs) noexcept
: alloc_(std::move(rhs))
{}
public:
// the other type of std_allocator
template <typename U>
struct rebind { typedef allocator_wrapper<U, AllocP> other; };
constexpr size_type max_size(void) const noexcept {
return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
}
public:
pointer allocate(size_type count) noexcept {
if (count == 0) return nullptr;
if (count > this->max_size()) return nullptr;
return static_cast<pointer>(alloc_.alloc(count * sizeof(value_type)));
}
void deallocate(pointer p, size_type count) noexcept {
alloc_.free(p, count * sizeof(value_type));
}
template <typename... P>
static void construct(pointer p, P && ... params) {
::new (static_cast<void*>(p)) value_type(std::forward<P>(params) ...);
}
static void destroy(pointer p) {
p->~value_type();
}
};
template <class AllocP>
class allocator_wrapper<void, AllocP> {
public:
// type definitions
typedef void value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef AllocP alloc_policy;
};
template <typename T, typename U, class AllocP>
constexpr bool operator==(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
return true;
}
template <typename T, typename U, class AllocP>
constexpr bool operator!=(const allocator_wrapper<T, AllocP>&, const allocator_wrapper<U, AllocP>&) noexcept {
return false;
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// Thread-safe allocation wrapper /// Thread-safe allocation wrapper
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
template <typename AllocP> template <typename AllocP>
class default_alloc_recycler { class limited_recycler {
public: public:
using alloc_policy = AllocP; using alloc_policy = AllocP;
private: protected:
ipc::spin_lock master_lock_; template <typename T>
std::vector<alloc_policy> master_allocs_; struct fixed_alloc_t : public fixed_alloc<sizeof(T)> {};
IPC_CONCEPT_(has_remain, remain()); template <typename T>
IPC_CONCEPT_(has_empty , empty()); using allocator = allocator_wrapper<T, fixed_alloc_t<T>>;
std::set<alloc_policy, std::less<alloc_policy>,
allocator<alloc_policy>
> master_allocs_;
ipc::spin_lock master_lock_;
template <typename F>
void take_first_do(F && pred) {
auto it = master_allocs_.begin();
pred(const_cast<alloc_policy&>(*it));
master_allocs_.erase(it);
}
public: public:
void swap(default_alloc_recycler& rhs) { void swap(limited_recycler & rhs) {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_); IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
master_allocs_.swap(rhs.master_allocs_); master_allocs_.swap(rhs.master_allocs_);
} }
void try_recover(alloc_policy & alc) { void try_recover(alloc_policy & alc) {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_); IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
if (!master_allocs_.empty()) { if (master_allocs_.empty()) return;
alc.swap(master_allocs_.back()); take_first_do([&alc](alloc_policy & first) { alc.swap(first); });
master_allocs_.pop_back();
}
} }
void collect(alloc_policy && alc) {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
auto it = master_allocs_.find(alc);
if (it == master_allocs_.end()) {
master_allocs_.emplace(std::move(alc));
}
else const_cast<alloc_policy&>(*it).swap(alc);
if (master_allocs_.size() <= 32) return;
take_first_do([](alloc_policy &) {}); // erase first
}
constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {}
};
template <typename AllocP>
class default_recycler : public limited_recycler<AllocP> {
IPC_CONCEPT_(has_remain, remain());
IPC_CONCEPT_(has_empty , empty());
template <typename A>
void try_fill(A & alc) {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(this->master_lock_);
if (this->master_allocs_.empty()) return;
this->take_first_do([&alc](alloc_policy & first) { alc.take(std::move(first)); });
}
public:
using alloc_policy = typename limited_recycler<AllocP>::alloc_policy;
template <typename A = AllocP> template <typename A = AllocP>
auto try_replenish(alloc_policy & alc, std::size_t size) auto try_replenish(alloc_policy & alc, std::size_t size)
-> ipc::require<detail::has_take<A>::value && has_remain<A>::value> { -> ipc::require<detail::has_take<A>::value && has_remain<A>::value> {
if (alc.remain() >= size) return; if (alc.remain() >= size) return;
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_); this->try_fill(alc);
if (!master_allocs_.empty()) {
alc.take(std::move(master_allocs_.back()));
master_allocs_.pop_back();
}
} }
template <typename A = AllocP> template <typename A = AllocP>
auto try_replenish(alloc_policy & alc, std::size_t /*size*/) auto try_replenish(alloc_policy & alc, std::size_t /*size*/)
-> ipc::require<(!detail::has_take<A>::value || !has_remain<A>::value) && has_empty<A>::value> { -> ipc::require<detail::has_take<A>::value && !has_remain<A>::value && has_empty<A>::value> {
if (!alc.empty()) return; if (!alc.empty()) return;
try_recover(alc); this->try_fill(alc);
}
template <typename A = AllocP>
auto try_replenish(alloc_policy & alc, std::size_t /*size*/)
-> ipc::require<!detail::has_take<A>::value && has_empty<A>::value> {
if (!alc.empty()) return;
this->try_recover(alc);
} }
template <typename A = AllocP> template <typename A = AllocP>
@ -180,26 +118,21 @@ public:
-> ipc::require<(!detail::has_take<A>::value || !has_remain<A>::value) && !has_empty<A>::value> { -> ipc::require<(!detail::has_take<A>::value || !has_remain<A>::value) && !has_empty<A>::value> {
// Do Nothing. // Do Nothing.
} }
void collect(alloc_policy && alc) {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(master_lock_);
master_allocs_.emplace_back(std::move(alc));
}
}; };
template <typename AllocP> template <typename AllocP>
class empty_alloc_recycler { class empty_recycler {
public: public:
using alloc_policy = AllocP; using alloc_policy = AllocP;
constexpr static void swap(empty_alloc_recycler&) noexcept {} constexpr static void swap(empty_recycler&) noexcept {}
constexpr static void try_recover(alloc_policy&) noexcept {} constexpr static void try_recover(alloc_policy&) noexcept {}
constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {} constexpr static auto try_replenish(alloc_policy&, std::size_t) noexcept {}
constexpr static void collect(alloc_policy&&) noexcept {} constexpr static void collect(alloc_policy&&) noexcept {}
}; };
template <typename AllocP, template <typename AllocP,
template <typename> class RecyclerP = default_alloc_recycler> template <typename> class RecyclerP = default_recycler>
class async_wrapper { class async_wrapper {
public: public:
using alloc_policy = AllocP; using alloc_policy = AllocP;
@ -291,31 +224,6 @@ public:
} }
}; };
////////////////////////////////////////////////////////////////
/// Static allocation wrapper
////////////////////////////////////////////////////////////////
template <typename AllocP>
class static_wrapper {
public:
using alloc_policy = AllocP;
static alloc_policy& instance() {
static alloc_policy alloc;
return alloc;
}
static void swap(static_wrapper&) {}
static void* alloc(std::size_t size) {
return instance().alloc(size);
}
static void free(void* p, std::size_t size) {
instance().free(p, size);
}
};
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
/// Variable memory allocation wrapper /// Variable memory allocation wrapper
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -341,41 +249,77 @@ struct default_mapping_policy {
template <typename F, typename D, typename ... P> template <typename F, typename D, typename ... P>
IPC_CONSTEXPR_ static auto classify(F f, D d, std::size_t size, P ... params) { IPC_CONSTEXPR_ static auto classify(F f, D d, std::size_t size, P ... params) {
std::size_t id = (size - base_size - 1) / iter_size; std::size_t id = (size - base_size - 1) / iter_size;
return (id < classes_size) ? f(id, params..., size) : d(params..., size); return (id < classes_size) ? f(id, size, params...) : d(size, params...);
} }
}; };
template <typename FixedAlloc, template <typename FixedAlloc,
typename DefaultAlloc = mem::static_alloc, typename DefaultAlloc = mem::static_alloc,
typename MappingP = default_mapping_policy<>> typename MappingP = default_mapping_policy<>>
class static_variable_wrapper { class variable_wrapper {
private:
static FixedAlloc& instance(std::size_t id) { struct initiator {
static struct initiator {
std::aligned_storage_t<sizeof (FixedAlloc), std::aligned_storage_t< sizeof(FixedAlloc),
alignof(FixedAlloc)> arr_[MappingP::classes_size]; alignof(FixedAlloc)> arr_[MappingP::classes_size];
initiator() {
MappingP::foreach([](std::size_t id, initiator* t) { initiator() {
::new (&(t->arr_[id])) FixedAlloc(MappingP::block_size(id)); MappingP::foreach([](std::size_t id, initiator* t) {
}, this); ::new (&(t->arr_[id])) FixedAlloc(MappingP::block_size(id));
} }, this);
} init__; }
return reinterpret_cast<FixedAlloc&>(init__.arr_[id]);
} FixedAlloc& at(std::size_t id) {
return reinterpret_cast<FixedAlloc&>(arr_[id]);
}
} init_;
public: public:
static void swap(static_variable_wrapper&) {} void swap(variable_wrapper & other) {
MappingP::foreach([](std::size_t id, initiator* t, initiator* o) {
t->at(id).swap(o->at(id));
}, &init_, &other.init_);
}
void* alloc(std::size_t size) {
return MappingP::classify([](std::size_t id, std::size_t size, initiator* t) {
return t->at(id).alloc(size);
}, [](std::size_t size, initiator*) {
return DefaultAlloc::alloc(size);
}, size, &init_);
}
void free(void* p, std::size_t size) {
MappingP::classify([](std::size_t id, std::size_t size, void* p, initiator* t) {
t->at(id).free(p, size);
}, [](std::size_t size, void* p, initiator*) {
DefaultAlloc::free(p, size);
}, size, p, &init_);
}
};
////////////////////////////////////////////////////////////////
/// Static allocation wrapper
////////////////////////////////////////////////////////////////
template <typename AllocP>
class static_wrapper {
public:
using alloc_policy = AllocP;
static alloc_policy& instance() {
static alloc_policy alloc;
return alloc;
}
static void swap(static_wrapper&) {}
static void* alloc(std::size_t size) { static void* alloc(std::size_t size) {
return MappingP::classify([](std::size_t id, std::size_t size) { return instance().alloc(size);
return instance(id).alloc(size);
}, DefaultAlloc::alloc, size);
} }
static void free(void* p, std::size_t size) { static void free(void* p, std::size_t size) {
MappingP::classify([](std::size_t id, void* p, std::size_t size) { instance().free(p, size);
instance(id).free(p, size);
}, static_cast<void(*)(void*, std::size_t)>(DefaultAlloc::free), size, p);
} }
}; };

View File

@ -33,13 +33,13 @@ private slots:
#include "test_mem.moc" #include "test_mem.moc"
constexpr int DataMin = 4; // constexpr int DataMin = 4;
constexpr int DataMax = 256; // constexpr int DataMax = 256;
constexpr int LoopCount = 4194304; // constexpr int LoopCount = 4194304;
// constexpr int DataMin = 256; constexpr int DataMin = 256;
// constexpr int DataMax = 512; constexpr int DataMax = 512;
// constexpr int LoopCount = 2097152; constexpr int LoopCount = 2097152;
std::vector<std::size_t> sizes__; std::vector<std::size_t> sizes__;