mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
try pool_alloc (TBD)
This commit is contained in:
parent
47236c9f24
commit
02a5920697
@ -26,7 +26,10 @@ HEADERS += \
|
||||
../include/tls_pointer.h \
|
||||
../src/channel.inc \
|
||||
../src/route.inc \
|
||||
../src/id_pool.inc
|
||||
../src/id_pool.inc \
|
||||
../src/memory/alloc.hpp \
|
||||
../src/memory/wrapper.hpp \
|
||||
../src/memory/resource.hpp
|
||||
|
||||
SOURCES += \
|
||||
../src/shm.cpp \
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
#include <atomic>
|
||||
#include <tuple>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "def.h"
|
||||
#include "circ_elem_array.h"
|
||||
@ -98,7 +97,7 @@ public:
|
||||
|
||||
template <typename F>
|
||||
static queue* multi_wait_for(F&& upd) noexcept {
|
||||
for (unsigned k = 0;; ++k) {
|
||||
while (1) {
|
||||
auto [ques, size] = upd();
|
||||
for (std::size_t i = 0; i < static_cast<std::size_t>(size); ++i) {
|
||||
queue* que = ques[i];
|
||||
@ -108,9 +107,7 @@ public:
|
||||
return que;
|
||||
}
|
||||
}
|
||||
if (k < 1024) std::this_thread::yield();
|
||||
// yielding => sleeping
|
||||
else std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "ipc.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <type_traits>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
@ -12,6 +11,8 @@
|
||||
#include "shm.h"
|
||||
#include "tls_pointer.h"
|
||||
|
||||
#include "memory/resource.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace ipc;
|
||||
@ -55,7 +56,7 @@ inline auto& recv_cache() {
|
||||
https://developercommunity.visualstudio.com/content/problem/124121/thread-local-variables-fail-to-be-initialized-when.html
|
||||
https://software.intel.com/en-us/forums/intel-c-compiler/topic/684827
|
||||
*/
|
||||
static tls::pointer<std::unordered_map<msg_id_t, buff_t>> rc;
|
||||
static tls::pointer<memory::unordered_map<msg_id_t, buff_t>> rc;
|
||||
return *rc.create();
|
||||
}
|
||||
|
||||
|
||||
171
src/memory/alloc.hpp
Normal file
171
src/memory/alloc.hpp
Normal file
@ -0,0 +1,171 @@
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "def.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace memory {
|
||||
|
||||
struct static_alloc {
|
||||
static constexpr std::size_t remain() {
|
||||
return (std::numeric_limits<std::size_t>::max)();
|
||||
}
|
||||
|
||||
static constexpr void clear() {}
|
||||
|
||||
static void* alloc(std::size_t size) {
|
||||
return size ? std::malloc(size) : nullptr;
|
||||
}
|
||||
|
||||
static void free(void* p) {
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
static void free(void* p, std::size_t /*size*/) {
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Scope allocation -- The destructor will release all allocated blocks.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename AllocP = static_alloc>
|
||||
class scope_alloc {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
private:
|
||||
alloc_policy alloc_;
|
||||
|
||||
struct block_t {
|
||||
block_t* next_;
|
||||
};
|
||||
block_t* list_ = nullptr;
|
||||
|
||||
public:
|
||||
scope_alloc() = default;
|
||||
|
||||
scope_alloc(scope_alloc&& rhs) { this->swap(rhs); }
|
||||
scope_alloc& operator=(scope_alloc&& rhs) { this->swap(rhs); return (*this); }
|
||||
|
||||
~scope_alloc() { clear(); }
|
||||
|
||||
public:
|
||||
void swap(scope_alloc& rhs) {
|
||||
std::swap(this->alloc_, rhs.alloc_);
|
||||
std::swap(this->list_ , rhs.list_);
|
||||
}
|
||||
|
||||
std::size_t remain() const {
|
||||
std::size_t c = 0;
|
||||
auto curr = list_;
|
||||
while (curr != nullptr) {
|
||||
++c;
|
||||
curr = curr->next_;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
while (list_ != nullptr) {
|
||||
auto curr = list_;
|
||||
list_ = list_->next_;
|
||||
alloc_.free(curr);
|
||||
}
|
||||
// now list_ is nullptr
|
||||
alloc_.clear();
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
auto curr = static_cast<block_t*>(alloc_.alloc(sizeof(block_t) + size));
|
||||
curr->next_ = list_;
|
||||
return ((list_ = curr) + 1);
|
||||
}
|
||||
|
||||
void free(void* /*p*/) {}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Fixed-size blocks allocation
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
template <std::size_t BlockSize, typename AllocP = scope_alloc<>>
|
||||
class fixed_pool {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
enum : std::size_t {
|
||||
block_size = (std::max)(BlockSize, sizeof(void*))
|
||||
};
|
||||
|
||||
private:
|
||||
alloc_policy alloc_;
|
||||
std::size_t init_expand_, iter_;
|
||||
void* cursor_;
|
||||
|
||||
void expand() {
|
||||
void** p = reinterpret_cast<void**>(cursor_ = alloc_.alloc(block_size * iter_));
|
||||
for (std::size_t i = 0; i < iter_ - 1; ++i)
|
||||
p = reinterpret_cast<void**>((*p) = reinterpret_cast<byte_t*>(p) + block_size);
|
||||
(*p) = nullptr;
|
||||
iter_ *= 2;
|
||||
}
|
||||
|
||||
void init(std::size_t init_expand) {
|
||||
iter_ = init_expand_ = init_expand;
|
||||
cursor_ = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit fixed_pool(std::size_t init_expand = 1) {
|
||||
init(init_expand);
|
||||
}
|
||||
|
||||
fixed_pool(fixed_pool&& rhs) { this->swap(rhs); }
|
||||
fixed_pool& operator=(fixed_pool&& rhs) { this->swap(rhs); return (*this); }
|
||||
|
||||
~fixed_pool() { clear(); }
|
||||
|
||||
public:
|
||||
void swap(fixed_pool& rhs) {
|
||||
std::swap(this->alloc_ , rhs.alloc_);
|
||||
std::swap(this->init_expand_, rhs.init_expand_);
|
||||
std::swap(this->iter_ , rhs.iter_);
|
||||
std::swap(this->cursor_ , rhs.cursor_);
|
||||
}
|
||||
|
||||
std::size_t remain() const {
|
||||
std::size_t c = 0;
|
||||
void* curr = cursor_;
|
||||
while (curr != nullptr) {
|
||||
++c;
|
||||
curr = *reinterpret_cast<void**>(curr); // curr = next
|
||||
}
|
||||
return c * block_size;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
alloc_.clear();
|
||||
init(init_expand_);
|
||||
}
|
||||
|
||||
void* alloc() {
|
||||
if (cursor_ == nullptr) expand();
|
||||
void* p = cursor_;
|
||||
cursor_ = *reinterpret_cast<void**>(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void free(void* p) {
|
||||
if (p == nullptr) return;
|
||||
*reinterpret_cast<void**>(p) = cursor_;
|
||||
cursor_ = p;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace memory
|
||||
} // namespace ipc
|
||||
85
src/memory/resource.hpp
Normal file
85
src/memory/resource.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "tls_pointer.h"
|
||||
|
||||
#include "memory/alloc.hpp"
|
||||
#include "memory/wrapper.hpp"
|
||||
|
||||
namespace ipc {
|
||||
namespace memory {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Comp, typename F, std::size_t...I>
|
||||
void switch_constexpr(std::size_t i, std::index_sequence<I...>, F&& f) {
|
||||
[[maybe_unused]] std::initializer_list<int> expand {
|
||||
(Comp{}(i, I) && (f(std::integral_constant<size_t, I>{}), 0))...
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class pool_alloc {
|
||||
private:
|
||||
template <std::size_t Size>
|
||||
static auto& fixed() {
|
||||
static tls::pointer<fixed_pool<Size>> fp;
|
||||
return *fp.create();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
static void choose(std::size_t size, F&& f) {
|
||||
enum : std::size_t { base_size = sizeof(void*) };
|
||||
detail::switch_constexpr<std::less_equal<std::size_t>>(size, std::index_sequence<
|
||||
base_size , base_size * 2 ,
|
||||
base_size * 4 , base_size * 6 ,
|
||||
base_size * 8 , base_size * 12,
|
||||
base_size * 16, base_size * 20,
|
||||
base_size * 24, base_size * 28,
|
||||
base_size * 32, base_size * 40,
|
||||
base_size * 48, base_size * 56,
|
||||
base_size * 64
|
||||
>{}, [&f](auto index) { f(fixed<decltype(index)::value>()); });
|
||||
}
|
||||
|
||||
public:
|
||||
pool_alloc() = default;
|
||||
pool_alloc(const pool_alloc&) = default;
|
||||
pool_alloc& operator=(const pool_alloc&) = default;
|
||||
pool_alloc(pool_alloc&&) = default;
|
||||
pool_alloc& operator=(pool_alloc&&) = default;
|
||||
|
||||
static constexpr std::size_t remain() {
|
||||
return (std::numeric_limits<std::size_t>::max)();
|
||||
}
|
||||
|
||||
static constexpr void clear() {}
|
||||
|
||||
static void* alloc(std::size_t size) {
|
||||
void* p;
|
||||
choose(size, [&p](auto& fp) { p = fp.alloc(); });
|
||||
return p;
|
||||
}
|
||||
|
||||
static void free(void* p, std::size_t size) {
|
||||
choose(size, [p](auto& fp) { fp.free(p); });
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using allocator = allocator_wrapper<T, pool_alloc>;
|
||||
|
||||
template<typename Key, typename T>
|
||||
using unordered_map = std::unordered_map<
|
||||
Key, T//, std::hash<Key>, std::equal_to<Key>, allocator<std::pair<const Key, T>>
|
||||
>;
|
||||
|
||||
} // namespace memory
|
||||
} // namespace ipc
|
||||
110
src/memory/wrapper.hpp
Normal file
110
src/memory/wrapper.hpp
Normal file
@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
#include <new>
|
||||
|
||||
namespace ipc {
|
||||
namespace memory {
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// The allocator wrapper class
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
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 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(T);
|
||||
}
|
||||
|
||||
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(T)));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type count) {
|
||||
alloc_.free(p, count * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
static void construct(pointer p, P&&... params) {
|
||||
::new (static_cast<void*>(p)) T(std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
static void destroy(pointer p) {
|
||||
p->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template <class AllocP>
|
||||
class allocator_wrapper<void, AllocP> {
|
||||
public:
|
||||
typedef void value_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 memory
|
||||
} // namespace ipc
|
||||
@ -6,11 +6,11 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include "tls_pointer.h"
|
||||
#include "memory/resource.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -25,7 +25,7 @@ constexpr void* mem_of(void* mem) {
|
||||
}
|
||||
|
||||
inline auto& m2h() {
|
||||
static ipc::tls::pointer<std::unordered_map<void*, std::string>> cache;
|
||||
static ipc::tls::pointer<ipc::memory::unordered_map<void*, std::string>> cache;
|
||||
return *cache.create();
|
||||
}
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "def.h"
|
||||
#include "tls_pointer.h"
|
||||
#include "memory/resource.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -28,7 +28,7 @@ constexpr auto to_tchar(std::string && str) -> IsSame<T, std::wstring> {
|
||||
}
|
||||
|
||||
inline auto& m2h() {
|
||||
static ipc::tls::pointer<std::unordered_map<void*, HANDLE>> cache;
|
||||
static ipc::tls::pointer<ipc::memory::unordered_map<void*, HANDLE>> cache;
|
||||
return *cache.create();
|
||||
}
|
||||
|
||||
|
||||
@ -304,10 +304,10 @@ void test_lock_performance() {
|
||||
}
|
||||
|
||||
void Unit::test_rw_lock() {
|
||||
test_lock_performance<1, 1>();
|
||||
test_lock_performance<4, 4>();
|
||||
test_lock_performance<1, 8>();
|
||||
test_lock_performance<8, 1>();
|
||||
// test_lock_performance<1, 1>();
|
||||
// test_lock_performance<4, 4>();
|
||||
// test_lock_performance<1, 8>();
|
||||
// test_lock_performance<8, 1>();
|
||||
}
|
||||
|
||||
void Unit::test_send_recv() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user