define locked_pool_alloc

This commit is contained in:
mutouyun 2019-01-21 12:02:38 +08:00
parent 4d2b47cbb7
commit 290b94902a
11 changed files with 245 additions and 201 deletions

View File

@ -27,6 +27,7 @@ HEADERS += \
../include/tls_pointer.h \
../include/pool_alloc.h \
../include/buffer.h \
../src/memory/detail.h \
../src/memory/alloc.hpp \
../src/memory/wrapper.hpp \
../src/memory/resource.hpp \

View File

@ -53,9 +53,9 @@ constexpr static queue_t* queue_of(ipc::handle_t h) {
}
static buff_t make_cache(void const * data, std::size_t size) {
auto ptr = mem::detail::pool_alloc::alloc(size);
auto ptr = mem::sync_pool_alloc::alloc(size);
std::memcpy(ptr, data, size);
return { ptr, size, mem::detail::pool_alloc::free };
return { ptr, size, mem::sync_pool_alloc::free };
}
struct cache_t {

View File

@ -264,5 +264,8 @@ using page_alloc = fixed_alloc<4096>;
template <std::size_t BlockSize>
using page_fixed_alloc = fixed_alloc<BlockSize, page_alloc>;
template <std::size_t BlockSize>
using locked_fixed_alloc = fixed_alloc<BlockSize, page_alloc, std::atomic, ipc::spin_lock>;
} // namespace mem
} // namespace ipc

81
src/memory/detail.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include <cstddef>
#include "memory/alloc.hpp"
#include "platform/detail.h"
namespace ipc {
namespace mem {
namespace detail {
enum : std::size_t {
base_size = sizeof(void*)
};
template <std::size_t Size, template <std::size_t> class FixedAlloc>
struct fixed {
static auto& pool() {
static FixedAlloc<Size> pool;
return pool;
}
};
#if __cplusplus >= 201703L
constexpr std::size_t classify(std::size_t size) {
constexpr std::size_t mapping[] = {
#else /*__cplusplus < 201703L*/
inline std::size_t classify(std::size_t size) {
static const std::size_t mapping[] = {
#endif/*__cplusplus < 201703L*/
/* 1 */
0 , 1 , 2 , 3 ,
/* 2 */
5 , 5 , 7 , 7 ,
9 , 9 , 11, 11,
13, 13, 15, 15,
/* 4 */
19, 19, 19, 19,
23, 23, 23, 23,
27, 27, 27, 27,
31, 31, 31, 31
};
size = (size - 1) / base_size;
#if __cplusplus >= 201703L
return (size < std::size(mapping)) ? mapping[size] : 32;
#else /*__cplusplus < 201703L*/
return (size < (sizeof(mapping) / sizeof(mapping[0]))) ? mapping[size] : 32;
#endif/*__cplusplus < 201703L*/
}
template <template <std::size_t> class Fixed, typename F>
decltype(auto) choose(std::size_t size, F&& f) {
return ipc::detail::static_switch(classify(size), std::make_index_sequence<32> {
}, [&f](auto index) {
return f(Fixed<(decltype(index)::value + 1) * base_size>::pool());
}, [&f] {
return f(static_alloc{});
});
}
template <template <std::size_t> class Fixed>
class pool_alloc {
public:
static void clear() {
ipc::detail::static_for(std::make_index_sequence<32> {}, [](auto index) {
Fixed<(decltype(index)::value + 1) * base_size>::pool().clear();
});
}
static void* alloc(std::size_t size) {
return choose<Fixed>(size, [size](auto&& fp) { return fp.alloc(size); });
}
static void free(void* p, std::size_t size) {
choose<Fixed>(size, [p](auto&& fp) { fp.free(p); });
}
};
} // namespace detail
} // namespace mem
} // namespace ipc

View File

@ -11,100 +11,22 @@
#include "memory/alloc.hpp"
#include "memory/wrapper.hpp"
#include "memory/detail.h"
#include "platform/detail.h"
namespace ipc {
namespace mem {
namespace detail {
template <typename F, typename D>
constexpr decltype(auto) static_switch(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) {
return def();
}
template <typename F, typename D, std::size_t N, std::size_t...I>
constexpr decltype(auto) static_switch(std::size_t i, std::index_sequence<N, I...>, F&& f, D&& def) {
return (i == N) ? f(std::integral_constant<size_t, N>{}) :
static_switch(i, std::index_sequence<I...>{}, f, def);
}
template <typename F, std::size_t...I>
#if __cplusplus >= 201703L
constexpr void static_for(std::index_sequence<I...>, F&& f) {
#else /*__cplusplus < 201703L*/
inline void static_for(std::index_sequence<I...>, F&& f) {
#endif/*__cplusplus < 201703L*/
IPC_UNUSED_ auto expand = { (f(std::integral_constant<size_t, I>{}), 0)... };
}
template <std::size_t Size>
using sync_fixed_alloc = synchronized<page_fixed_alloc<Size>>;
template <std::size_t Size>
auto& fixed() {
static synchronized<page_fixed_alloc<Size>> pool;
return pool;
}
using sync_fixed = mem::detail::fixed<Size, sync_fixed_alloc>;
enum : std::size_t {
base_size = sizeof(void*)
};
#if __cplusplus >= 201703L
constexpr std::size_t classify(std::size_t size) {
constexpr std::size_t mapping[] = {
#else /*__cplusplus < 201703L*/
inline std::size_t classify(std::size_t size) {
static const std::size_t mapping[] = {
#endif/*__cplusplus < 201703L*/
/* 1 */
0 , 1 , 2 , 3 ,
/* 2 */
5 , 5 , 7 , 7 ,
9 , 9 , 11, 11,
13, 13, 15, 15,
/* 4 */
19, 19, 19, 19,
23, 23, 23, 23,
27, 27, 27, 27,
31, 31, 31, 31
};
size = (size - 1) / base_size;
#if __cplusplus >= 201703L
return (size < std::size(mapping)) ? mapping[size] : 32;
#else /*__cplusplus < 201703L*/
return (size < (sizeof(mapping) / sizeof(mapping[0]))) ? mapping[size] : 32;
#endif/*__cplusplus < 201703L*/
}
template <typename F>
decltype(auto) choose(std::size_t size, F&& f) {
return detail::static_switch(classify(size), std::make_index_sequence<32> {
}, [&f](auto index) {
return f(fixed<(decltype(index)::value + 1) * base_size>());
}, [&f] {
return f(static_alloc{});
});
}
class pool_alloc {
public:
static void clear() {
static_for(std::make_index_sequence<32> {}, [](auto index) {
fixed<(decltype(index)::value + 1) * base_size>().clear();
});
}
static void* alloc(std::size_t size) {
return choose(size, [size](auto&& fp) { return fp.alloc(size); });
}
static void free(void* p, std::size_t size) {
choose(size, [p](auto&& fp) { fp.free(p); });
}
};
} // namespace detail
using sync_pool_alloc = detail::pool_alloc<sync_fixed>;
template <typename T>
using allocator = allocator_wrapper<T, detail::pool_alloc>;
using allocator = allocator_wrapper<T, sync_pool_alloc>;
template <typename Key, typename T>
using unordered_map = std::unordered_map<

View File

@ -15,100 +15,13 @@
#include "rw_lock.h"
#include "tls_pointer.h"
#include "memory/alloc.hpp"
#include "memory/detail.h"
#include "platform/detail.h"
namespace ipc {
namespace mem {
////////////////////////////////////////////////////////////////
/// Thread-safe allocation wrapper
////////////////////////////////////////////////////////////////
template <typename AllocP>
class synchronized {
public:
using alloc_policy = AllocP;
private:
spin_lock lc_;
std::multimap<std::size_t, alloc_policy*> allocs_;
struct alloc_t {
synchronized* t_;
std::size_t s_ = 0;
alloc_policy* a_ = nullptr;
alloc_t(synchronized* t)
: t_ { t } {
{
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(t_->lc_);
auto it = t_->allocs_.begin();
if (it != t_->allocs_.end()) {
std::tie(s_, a_) = *it;
t_->allocs_.erase(it);
}
}
if (a_ == nullptr) {
a_ = new alloc_policy;
}
}
~alloc_t() {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(t_->lc_);
t_->allocs_.emplace(s_, a_);
}
void* alloc(std::size_t size) {
void* p = a_->alloc(size);
if ((p != nullptr) && (s_ > 0)) {
--s_;
}
return p;
}
void free(void* p) {
a_->free(p);
++s_;
}
};
auto& alc_info() {
static tls::pointer<alloc_t> alc;
return *alc.create(this);
}
public:
~synchronized() {
for (auto& pair : allocs_) {
delete pair.second;
}
}
void clear() {
auto guard = ipc::detail::unique_lock(lc_);
std::vector<alloc_policy*> vec(allocs_.size());
std::size_t i = 0;
for (auto& pair : allocs_) {
vec[i++] = pair.second;
}
allocs_.clear();
guard.unlock();
for (auto alc : vec) delete alc;
}
void* alloc(std::size_t size) {
return alc_info().alloc(size);
}
void free(void* p) {
alc_info().free(p);
}
void free(void* p, std::size_t /*size*/) {
free(p);
}
};
////////////////////////////////////////////////////////////////
/// The allocator wrapper class for STL
////////////////////////////////////////////////////////////////
@ -208,5 +121,105 @@ constexpr bool operator!=(const allocator_wrapper<T, AllocP>&, const allocator_w
return false;
}
////////////////////////////////////////////////////////////////
/// Thread-safe allocation wrapper
////////////////////////////////////////////////////////////////
template <std::size_t BlockSize>
using locked_fixed = ipc::mem::detail::fixed<BlockSize, locked_fixed_alloc>;
using locked_pool_alloc = detail::pool_alloc<locked_fixed>;
template <typename T>
using locked_allocator = allocator_wrapper<T, locked_pool_alloc>;
template <typename AllocP>
class synchronized {
public:
using alloc_policy = AllocP;
private:
spin_lock lc_;
std::multimap<std::size_t, alloc_policy*, std::less<std::size_t>,
locked_allocator<std::pair<const std::size_t, alloc_policy*>>> allocs_;
struct alloc_t {
synchronized* t_;
std::size_t s_ = 0;
alloc_policy* a_ = nullptr;
alloc_t(synchronized* t)
: t_ { t } {
{
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(t_->lc_);
auto it = t_->allocs_.begin();
if (it != t_->allocs_.end()) {
std::tie(s_, a_) = *it;
t_->allocs_.erase(it);
}
}
if (a_ == nullptr) {
a_ = static_cast<alloc_policy*>(locked_pool_alloc::alloc(sizeof(alloc_policy)));
::new (a_) alloc_policy;
}
}
~alloc_t() {
IPC_UNUSED_ auto guard = ipc::detail::unique_lock(t_->lc_);
t_->allocs_.emplace(s_, a_);
}
void* alloc(std::size_t size) {
void* p = a_->alloc(size);
if ((p != nullptr) && (s_ > 0)) {
--s_;
}
return p;
}
void free(void* p) {
a_->free(p);
++s_;
}
};
auto& alc_info() {
static tls::pointer<alloc_t> alc;
return *alc.create(this);
}
public:
~synchronized() {
for (auto& pair : allocs_) {
pair.second->~AllocP();
locked_pool_alloc::free(pair.second, sizeof(alloc_policy));
}
}
void clear() {
auto guard = ipc::detail::unique_lock(lc_);
std::vector<alloc_policy*> vec(allocs_.size());
std::size_t i = 0;
for (auto& pair : allocs_) {
vec[i++] = pair.second;
}
allocs_.clear();
guard.unlock();
for (auto alc : vec) delete alc;
}
void* alloc(std::size_t size) {
return alc_info().alloc(size);
}
void free(void* p) {
alc_info().free(p);
}
void free(void* p, std::size_t /*size*/) {
free(p);
}
};
} // namespace mem
} // namespace ipc

View File

@ -39,5 +39,25 @@ constexpr auto unique_lock(T&& lc) {
#endif/*__cplusplus < 201703L*/
template <typename F, typename D>
constexpr decltype(auto) static_switch(std::size_t /*i*/, std::index_sequence<>, F&& /*f*/, D&& def) {
return def();
}
template <typename F, typename D, std::size_t N, std::size_t...I>
constexpr decltype(auto) static_switch(std::size_t i, std::index_sequence<N, I...>, F&& f, D&& def) {
return (i == N) ? f(std::integral_constant<size_t, N>{}) :
static_switch(i, std::index_sequence<I...>{}, f, def);
}
template <typename F, std::size_t...I>
#if __cplusplus >= 201703L
constexpr void static_for(std::index_sequence<I...>, F&& f) {
#else /*__cplusplus < 201703L*/
inline void static_for(std::index_sequence<I...>, F&& f) {
#endif/*__cplusplus < 201703L*/
IPC_UNUSED_ auto expand = { (f(std::integral_constant<size_t, I>{}), 0)... };
}
} // namespace detail
} // namespace ipc

View File

@ -6,15 +6,15 @@ namespace ipc {
namespace mem {
void pool_alloc::clear() {
detail::pool_alloc::clear();
sync_pool_alloc::clear();
}
void* pool_alloc::alloc(std::size_t size) {
return detail::pool_alloc::alloc(size);
return sync_pool_alloc::alloc(size);
}
void pool_alloc::free(void* p, std::size_t size) {
detail::pool_alloc::free(p, size);
sync_pool_alloc::free(p, size);
}
} // namespace mem

View File

@ -340,11 +340,11 @@ void Unit::test_prod_cons_performance() {
ipc::relat::multi,
ipc::trans::unicast>
> el_arr_smu;
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_smu](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_smu](auto index) {
benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount, void>(&el_arr_smu);
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
test_prod_cons<1, decltype(index)::value + 1, false>();
});
test_prod_cons<1, 10>(); // test & verify
@ -355,13 +355,13 @@ void Unit::test_prod_cons_performance() {
ipc::relat::multi,
ipc::trans::unicast>
> el_arr_mmu;
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount, void>(&el_arr_mmu);
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
benchmark_prod_cons<decltype(index)::value + 1, 1, LoopCount, void>(&el_arr_mmu);
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmu](auto index) {
benchmark_prod_cons<decltype(index)::value + 1, decltype(index)::value + 1, LoopCount, void>(&el_arr_mmu);
});
@ -371,13 +371,13 @@ void Unit::test_prod_cons_performance() {
ipc::relat::multi,
ipc::trans::broadcast>
> el_arr_mmb;
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount, void>(&el_arr_mmb);
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
benchmark_prod_cons<decltype(index)::value + 1, 1, LoopCount, void>(&el_arr_mmb);
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [&el_arr_mmb](auto index) {
benchmark_prod_cons<decltype(index)::value + 1, decltype(index)::value + 1, LoopCount, void>(&el_arr_mmb);
});
}
@ -392,7 +392,7 @@ void Unit::test_queue() {
queue.attach(cq);
QVERIFY(queue.detach() != nullptr);
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
benchmark_prod_cons<1, decltype(index)::value + 1, LoopCount>((ipc::queue<msg_t>*)nullptr);
});
}

View File

@ -403,7 +403,7 @@ void Unit::test_route_rtt() {
}
void Unit::test_route_performance() {
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
test_prod_cons<ipc::route, 1, decltype(index)::value + 1, false>();
});
test_prod_cons<ipc::route, 1, 10>(); // test & verify
@ -471,13 +471,13 @@ void Unit::test_channel_rtt() {
}
void Unit::test_channel_performance() {
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
test_prod_cons<ipc::channel, 1, decltype(index)::value + 1, false>();
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
test_prod_cons<ipc::channel, decltype(index)::value + 1, 1, false>();
});
ipc::mem::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
ipc::detail::static_for(std::make_index_sequence<10>{}, [](auto index) {
test_prod_cons<ipc::channel, decltype(index)::value + 1,
decltype(index)::value + 1, false>();
});

View File

@ -111,7 +111,8 @@ void benchmark_alloc() {
void Unit::test_alloc_free() {
benchmark_alloc<ipc::mem::static_alloc>();
benchmark_alloc<ipc::mem::detail::pool_alloc>();
benchmark_alloc<ipc::mem::sync_pool_alloc>();
benchmark_alloc<ipc::mem::locked_pool_alloc>();
}
template <typename AllocT, typename ModeT, int ThreadsN>
@ -176,14 +177,17 @@ struct test_performance<AllocT, ModeT, 1> {
};
void Unit::test_linear() {
// malloc
test_performance<ipc::mem::static_alloc, alloc_random, 8>::start();
test_performance<ipc::mem::static_alloc, alloc_LIFO , 8>::start();
test_performance<ipc::mem::static_alloc, alloc_FIFO , 8>::start();
// pool-alloc
test_performance<ipc::mem::pool_alloc , alloc_random, 8>::start();
test_performance<ipc::mem::pool_alloc , alloc_LIFO , 8>::start();
test_performance<ipc::mem::pool_alloc , alloc_FIFO , 8>::start();
test_performance<ipc::mem::static_alloc , alloc_random, 8>::start();
test_performance<ipc::mem::pool_alloc , alloc_random, 8>::start();
test_performance<ipc::mem::locked_pool_alloc, alloc_random, 8>::start();
test_performance<ipc::mem::static_alloc , alloc_LIFO , 8>::start();
test_performance<ipc::mem::pool_alloc , alloc_LIFO , 8>::start();
test_performance<ipc::mem::locked_pool_alloc, alloc_LIFO , 8>::start();
test_performance<ipc::mem::static_alloc , alloc_FIFO , 8>::start();
test_performance<ipc::mem::pool_alloc , alloc_FIFO , 8>::start();
test_performance<ipc::mem::locked_pool_alloc, alloc_FIFO , 8>::start();
}
} // internal-linkage