mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
Use $new instead of alloc
This commit is contained in:
parent
db109165f3
commit
831225f763
@ -26,7 +26,7 @@ namespace mem {
|
||||
class LIBIPC_EXPORT block_collector {
|
||||
public:
|
||||
virtual ~block_collector() noexcept = default;
|
||||
virtual void recycle(void *p) noexcept = 0;
|
||||
virtual void recycle(void */*p*/) noexcept {}
|
||||
};
|
||||
|
||||
#if defined(LIBIPC_CPP_17)
|
||||
@ -182,8 +182,7 @@ T *$new(A &&... args) noexcept {
|
||||
/// \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
|
||||
/// \note This function is thread-safe. If the pointer type passed in is different from `$new`,
|
||||
/// additional performance penalties may be incurred.
|
||||
template <typename T>
|
||||
void $delete(T *p) noexcept {
|
||||
inline void $delete(void *p) noexcept {
|
||||
if (p == nullptr) return;
|
||||
auto *b = reinterpret_cast<byte *>(p) - regular_head_size;
|
||||
auto *r = reinterpret_cast<recycle_t *>(b);
|
||||
|
||||
@ -1,103 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
#include "libipc/imp/export.h"
|
||||
#include "libipc/def.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
class LIBIPC_EXPORT pool_alloc {
|
||||
public:
|
||||
static void* alloc(std::size_t size) noexcept;
|
||||
static void free (void* p, std::size_t size) noexcept;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// construct/destruct an object
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct impl {
|
||||
template <typename... P>
|
||||
static T* construct(T* p, P&&... params) {
|
||||
::new (p) T(std::forward<P>(params)...);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void destruct(T* p) {
|
||||
reinterpret_cast<T*>(p)->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct impl<T[N]> {
|
||||
using type = T[N];
|
||||
|
||||
template <typename... P>
|
||||
static type* construct(type* p, P&&... params) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
impl<T>::construct(&((*p)[i]), std::forward<P>(params)...);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void destruct(type* p) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
impl<T>::destruct(&((*p)[i]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* construct(T* p, P&&... params) {
|
||||
return detail::impl<T>::construct(p, std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* construct(void* p, P&&... params) {
|
||||
return construct(static_cast<T*>(p), std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void destruct(T* p) {
|
||||
return detail::impl<T>::destruct(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void destruct(void* p) {
|
||||
destruct(static_cast<T*>(p));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// general alloc/free
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void* alloc(std::size_t size) {
|
||||
return pool_alloc::alloc(size);
|
||||
}
|
||||
|
||||
template <typename T, typename... P>
|
||||
T* alloc(P&&... params) {
|
||||
return construct<T>(pool_alloc::alloc(sizeof(T)), std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
inline void free(void* p, std::size_t size) {
|
||||
pool_alloc::free(p, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void free(T* p) {
|
||||
if (p == nullptr) return;
|
||||
destruct(p);
|
||||
pool_alloc::free(p, sizeof(T));
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -14,7 +14,6 @@
|
||||
#include "libipc/ipc.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/shm.h"
|
||||
#include "libipc/pool_alloc.h"
|
||||
#include "libipc/queue.h"
|
||||
#include "libipc/policy.h"
|
||||
#include "libipc/rw_lock.h"
|
||||
@ -26,6 +25,7 @@
|
||||
#include "libipc/utility/utility.h"
|
||||
|
||||
#include "libipc/mem/resource.h"
|
||||
#include "libipc/mem/new.h"
|
||||
#include "libipc/platform/detail.h"
|
||||
#include "libipc/circ/elem_array.h"
|
||||
|
||||
@ -65,9 +65,14 @@ struct msg_t : msg_t<0, AlignSize> {
|
||||
|
||||
template <typename T>
|
||||
ipc::buff_t make_cache(T &data, std::size_t size) {
|
||||
auto ptr = ipc::mem::alloc(size);
|
||||
auto *ptr = ipc::mem::$new<void>(size);
|
||||
std::memcpy(ptr, &data, (ipc::detail::min)(sizeof(data), size));
|
||||
return { ptr, size, ipc::mem::free };
|
||||
return {
|
||||
ptr, size,
|
||||
[](void *p, std::size_t) noexcept {
|
||||
ipc::mem::$delete(p);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
acc_t *cc_acc(std::string const &pref) {
|
||||
@ -259,8 +264,8 @@ chunk_info_t *chunk_storage_info(conn_info_head *inf, std::size_t chunk_size) {
|
||||
guard.unlock();
|
||||
LIBIPC_UNUSED std::lock_guard<ipc::rw_lock> guard {lock};
|
||||
it = storages.emplace(chunk_size, chunk_handle_ptr_t{
|
||||
ipc::mem::alloc<chunk_handle_t>(), [](chunk_handle_t *p) {
|
||||
ipc::mem::destruct(p);
|
||||
ipc::mem::$new<chunk_handle_t>(), [](chunk_handle_t *p) {
|
||||
ipc::mem::$delete(p);
|
||||
}}).first;
|
||||
}
|
||||
}
|
||||
@ -447,7 +452,7 @@ constexpr static queue_t* queue_of(ipc::handle_t h) noexcept {
|
||||
static bool connect(ipc::handle_t * ph, ipc::prefix pref, char const * name, bool start_to_recv) {
|
||||
assert(ph != nullptr);
|
||||
if (*ph == nullptr) {
|
||||
*ph = ipc::mem::alloc<conn_info_t>(pref.str, name);
|
||||
*ph = ipc::mem::$new<conn_info_t>(pref.str, name);
|
||||
}
|
||||
return reconnect(ph, start_to_recv);
|
||||
}
|
||||
@ -490,7 +495,7 @@ static bool reconnect(ipc::handle_t * ph, bool start_to_recv) {
|
||||
}
|
||||
|
||||
static void destroy(ipc::handle_t h) noexcept {
|
||||
ipc::mem::free(info_of(h));
|
||||
ipc::mem::$delete(info_of(h));
|
||||
}
|
||||
|
||||
static std::size_t recv_count(ipc::handle_t h) noexcept {
|
||||
@ -654,20 +659,20 @@ static ipc::buff_t recv(ipc::handle_t h, std::uint64_t tm) {
|
||||
conn_info_t * inf;
|
||||
ipc::circ::cc_t curr_conns;
|
||||
ipc::circ::cc_t conn_id;
|
||||
} *r_info = ipc::mem::alloc<recycle_t>(recycle_t{
|
||||
} *r_info = ipc::mem::$new<recycle_t>(recycle_t{
|
||||
buf_id,
|
||||
inf,
|
||||
que->elems()->connections(std::memory_order_relaxed),
|
||||
que->connected_id()
|
||||
});
|
||||
if (r_info == nullptr) {
|
||||
ipc::log("fail: ipc::mem::alloc<recycle_t>.\n");
|
||||
ipc::log("fail: ipc::mem::$new<recycle_t>.\n");
|
||||
return ipc::buff_t{buf, msg_size}; // no recycle
|
||||
} else {
|
||||
return ipc::buff_t{buf, msg_size, [](void* p_info, std::size_t size) {
|
||||
auto r_info = static_cast<recycle_t *>(p_info);
|
||||
LIBIPC_UNUSED auto finally = ipc::guard([r_info] {
|
||||
ipc::mem::free(r_info);
|
||||
ipc::mem::$delete(r_info);
|
||||
});
|
||||
recycle_storage<flag_t>(r_info->storage_id,
|
||||
r_info->inf,
|
||||
|
||||
@ -5,22 +5,10 @@
|
||||
#include <string>
|
||||
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/memory/alloc.h"
|
||||
#include "libipc/imp/fmt.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
//using async_pool_alloc = static_wrapper<variable_wrapper<async_wrapper<
|
||||
// detail::fixed_alloc<
|
||||
// variable_alloc <sizeof(void*) * 1024 * 256>,
|
||||
// fixed_expand_policy<sizeof(void*) * 1024, sizeof(void*) * 1024 * 256>
|
||||
// >,
|
||||
// default_recycler >>>;
|
||||
using async_pool_alloc = ipc::mem::static_alloc;
|
||||
|
||||
} // namespace mem
|
||||
|
||||
template <typename T>
|
||||
struct hash : public std::hash<T> {};
|
||||
|
||||
@ -1,423 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <cstdlib>
|
||||
#include <cassert> // assert
|
||||
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/rw_lock.h"
|
||||
|
||||
#include "libipc/utility/concept.h"
|
||||
#include "libipc/platform/detail.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
class static_alloc {
|
||||
public:
|
||||
static void swap(static_alloc&) noexcept {}
|
||||
|
||||
static void* alloc(std::size_t size) noexcept {
|
||||
return size ? std::malloc(size) : nullptr;
|
||||
}
|
||||
|
||||
static void free(void* p) noexcept {
|
||||
std::free(p);
|
||||
}
|
||||
|
||||
static void free(void* p, std::size_t /*size*/) noexcept {
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Scope allocation -- The destructor will release all allocated blocks.
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr std::size_t aligned(std::size_t size, size_t alignment) noexcept {
|
||||
return ( (size - 1) & ~(alignment - 1) ) + alignment;
|
||||
}
|
||||
|
||||
IPC_CONCEPT_(has_take, take(std::move(std::declval<Type>())));
|
||||
|
||||
class scope_alloc_base {
|
||||
protected:
|
||||
struct block_t {
|
||||
std::size_t size_;
|
||||
block_t * next_;
|
||||
} * head_ = nullptr, * tail_ = nullptr;
|
||||
|
||||
enum : std::size_t {
|
||||
aligned_block_size = aligned(sizeof(block_t), alignof(std::max_align_t))
|
||||
};
|
||||
|
||||
public:
|
||||
void swap(scope_alloc_base & rhs) {
|
||||
std::swap(head_, rhs.head_);
|
||||
std::swap(tail_, rhs.tail_);
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return head_ == nullptr;
|
||||
}
|
||||
|
||||
void take(scope_alloc_base && rhs) {
|
||||
if (rhs.empty()) return;
|
||||
if (empty()) swap(rhs);
|
||||
else {
|
||||
std::swap(tail_->next_, rhs.head_);
|
||||
// rhs.head_ should be nullptr here
|
||||
tail_ = rhs.tail_;
|
||||
rhs.tail_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void free(void* /*p*/) {}
|
||||
void free(void* /*p*/, std::size_t) {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename AllocP = static_alloc>
|
||||
class scope_alloc : public detail::scope_alloc_base {
|
||||
public:
|
||||
using base_t = detail::scope_alloc_base;
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
private:
|
||||
alloc_policy alloc_;
|
||||
|
||||
void free_all() {
|
||||
while (!empty()) {
|
||||
auto curr = head_;
|
||||
head_ = head_->next_;
|
||||
alloc_.free(curr, curr->size_);
|
||||
}
|
||||
// now head_ is nullptr
|
||||
}
|
||||
|
||||
public:
|
||||
scope_alloc() = default;
|
||||
|
||||
scope_alloc(scope_alloc && rhs) { swap(rhs); }
|
||||
scope_alloc& operator=(scope_alloc rhs) { swap(rhs); return (*this); }
|
||||
|
||||
~scope_alloc() { free_all(); }
|
||||
|
||||
void swap(scope_alloc& rhs) {
|
||||
alloc_.swap(rhs.alloc_);
|
||||
base_t::swap(rhs);
|
||||
}
|
||||
|
||||
template <typename A = AllocP>
|
||||
auto take(scope_alloc && rhs) -> ipc::require<detail::has_take<A>::value> {
|
||||
base_t::take(std::move(rhs));
|
||||
alloc_.take(std::move(rhs.alloc_));
|
||||
}
|
||||
|
||||
template <typename A = AllocP>
|
||||
auto take(scope_alloc && rhs) -> ipc::require<!detail::has_take<A>::value> {
|
||||
base_t::take(std::move(rhs));
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
std::size_t real_size = aligned_block_size + size;
|
||||
auto curr = static_cast<block_t*>(alloc_.alloc(real_size));
|
||||
curr->size_ = real_size;
|
||||
curr->next_ = head_;
|
||||
head_ = curr;
|
||||
if (tail_ == nullptr) {
|
||||
tail_ = curr;
|
||||
}
|
||||
return (reinterpret_cast<byte_t*>(curr) + aligned_block_size);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Fixed-size blocks allocation
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
class fixed_alloc_base {
|
||||
protected:
|
||||
std::size_t block_size_;
|
||||
std::size_t init_expand_;
|
||||
void * cursor_;
|
||||
|
||||
void init(std::size_t block_size, std::size_t init_expand) {
|
||||
block_size_ = block_size;
|
||||
init_expand_ = init_expand;
|
||||
cursor_ = nullptr;
|
||||
}
|
||||
|
||||
static void** node_p(void* node) {
|
||||
return reinterpret_cast<void**>(node);
|
||||
}
|
||||
|
||||
static auto& next(void* node) {
|
||||
return *node_p(node);
|
||||
}
|
||||
|
||||
public:
|
||||
bool operator<(fixed_alloc_base const & right) const {
|
||||
return init_expand_ < right.init_expand_;
|
||||
}
|
||||
|
||||
void set_block_size(std::size_t block_size) {
|
||||
block_size_ = block_size;
|
||||
}
|
||||
|
||||
void swap(fixed_alloc_base& rhs) {
|
||||
std::swap(block_size_ , rhs.block_size_);
|
||||
std::swap(init_expand_, rhs.init_expand_);
|
||||
std::swap(cursor_ , rhs.cursor_);
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return cursor_ == nullptr;
|
||||
}
|
||||
|
||||
void take(fixed_alloc_base && rhs) {
|
||||
assert(block_size_ == rhs.block_size_);
|
||||
init_expand_ = (ipc::detail::max)(init_expand_, rhs.init_expand_);
|
||||
if (rhs.empty()) return;
|
||||
auto curr = cursor_;
|
||||
if (curr != nullptr) while (1) {
|
||||
auto next_cur = next(curr);
|
||||
if (next_cur == nullptr) {
|
||||
std::swap(next(curr), rhs.cursor_);
|
||||
return;
|
||||
}
|
||||
// next_cur != nullptr
|
||||
else curr = next_cur;
|
||||
}
|
||||
// curr == nullptr, means cursor_ == nullptr
|
||||
else std::swap(cursor_, rhs.cursor_);
|
||||
// rhs.cursor_ must be nullptr
|
||||
}
|
||||
|
||||
void free(void* p) {
|
||||
if (p == nullptr) return;
|
||||
next(p) = cursor_;
|
||||
cursor_ = p;
|
||||
}
|
||||
|
||||
void free(void* p, std::size_t) {
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename AllocP, typename ExpandP>
|
||||
class fixed_alloc : public detail::fixed_alloc_base {
|
||||
public:
|
||||
using base_t = detail::fixed_alloc_base;
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
private:
|
||||
alloc_policy alloc_;
|
||||
|
||||
void* try_expand() {
|
||||
if (empty()) {
|
||||
auto size = ExpandP::next(block_size_, init_expand_);
|
||||
auto p = node_p(cursor_ = alloc_.alloc(size));
|
||||
for (std::size_t i = 0; i < (size / block_size_) - 1; ++i)
|
||||
p = node_p((*p) = reinterpret_cast<byte_t*>(p) + block_size_);
|
||||
(*p) = nullptr;
|
||||
}
|
||||
return cursor_;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit fixed_alloc(std::size_t block_size, std::size_t init_expand = 1) {
|
||||
init(block_size, init_expand);
|
||||
}
|
||||
|
||||
fixed_alloc(fixed_alloc && rhs) {
|
||||
init(0, 0);
|
||||
swap(rhs);
|
||||
}
|
||||
|
||||
fixed_alloc& operator=(fixed_alloc rhs) {
|
||||
swap(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void swap(fixed_alloc& rhs) {
|
||||
alloc_.swap(rhs.alloc_);
|
||||
base_t::swap(rhs);
|
||||
}
|
||||
|
||||
template <typename A = AllocP>
|
||||
auto take(fixed_alloc && rhs) -> ipc::require<detail::has_take<A>::value> {
|
||||
base_t::take(std::move(rhs));
|
||||
alloc_.take(std::move(rhs.alloc_));
|
||||
}
|
||||
|
||||
void* alloc() {
|
||||
void* p = try_expand();
|
||||
cursor_ = next(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* alloc(std::size_t) {
|
||||
return alloc();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <std::size_t BaseSize = sizeof(void*) * 1024,
|
||||
std::size_t LimitSize = (std::numeric_limits<std::uint32_t>::max)()>
|
||||
struct fixed_expand_policy {
|
||||
|
||||
enum : std::size_t {
|
||||
base_size = BaseSize,
|
||||
limit_size = LimitSize
|
||||
};
|
||||
|
||||
constexpr static std::size_t prev(std::size_t e) noexcept {
|
||||
return ((e / 2) == 0) ? 1 : (e / 2);
|
||||
}
|
||||
|
||||
constexpr static std::size_t next(std::size_t e) noexcept {
|
||||
return e * 2;
|
||||
}
|
||||
|
||||
static std::size_t next(std::size_t block_size, std::size_t & e) {
|
||||
auto n = ipc::detail::max<std::size_t>(block_size, base_size) * e;
|
||||
e = ipc::detail::min<std::size_t>(limit_size, next(e));
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t BlockSize,
|
||||
typename AllocP = scope_alloc<>,
|
||||
typename ExpandP = fixed_expand_policy<>>
|
||||
class fixed_alloc : public detail::fixed_alloc<AllocP, ExpandP> {
|
||||
public:
|
||||
using base_t = detail::fixed_alloc<AllocP, ExpandP>;
|
||||
|
||||
enum : std::size_t {
|
||||
block_size = ipc::detail::max<std::size_t>(BlockSize, sizeof(void*))
|
||||
};
|
||||
|
||||
public:
|
||||
explicit fixed_alloc(std::size_t init_expand)
|
||||
: base_t(block_size, init_expand) {
|
||||
}
|
||||
|
||||
fixed_alloc() : fixed_alloc(1) {}
|
||||
|
||||
fixed_alloc(fixed_alloc && rhs)
|
||||
: base_t(std::move(rhs)) {
|
||||
}
|
||||
|
||||
fixed_alloc& operator=(fixed_alloc rhs) {
|
||||
swap(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void swap(fixed_alloc& rhs) {
|
||||
base_t::swap(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Variable-size blocks allocation (without alignment)
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
class variable_alloc_base {
|
||||
protected:
|
||||
byte_t * head_ = nullptr, * tail_ = nullptr;
|
||||
|
||||
public:
|
||||
void swap(variable_alloc_base & rhs) {
|
||||
std::swap(head_, rhs.head_);
|
||||
std::swap(tail_, rhs.tail_);
|
||||
}
|
||||
|
||||
std::size_t remain() const noexcept {
|
||||
return static_cast<std::size_t>(tail_ - head_);
|
||||
}
|
||||
|
||||
bool empty() const noexcept {
|
||||
return remain() == 0;
|
||||
}
|
||||
|
||||
void take(variable_alloc_base && rhs) {
|
||||
if (remain() < rhs.remain()) {
|
||||
// replace this by rhs
|
||||
head_ = rhs.head_;
|
||||
tail_ = rhs.tail_;
|
||||
}
|
||||
// discard rhs
|
||||
rhs.head_ = rhs.tail_ = 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 alloc_policy = AllocP;
|
||||
|
||||
enum : std::size_t {
|
||||
aligned_chunk_size = detail::aligned(ChunkSize, alignof(std::max_align_t))
|
||||
};
|
||||
|
||||
private:
|
||||
alloc_policy alloc_;
|
||||
|
||||
public:
|
||||
variable_alloc() = default;
|
||||
|
||||
variable_alloc(variable_alloc && rhs) { swap(rhs); }
|
||||
variable_alloc& operator=(variable_alloc rhs) { swap(rhs); return (*this); }
|
||||
|
||||
void swap(variable_alloc& rhs) {
|
||||
alloc_.swap(rhs.alloc_);
|
||||
base_t::swap(rhs);
|
||||
}
|
||||
|
||||
template <typename A = AllocP>
|
||||
auto take(variable_alloc && rhs) -> ipc::require<detail::has_take<A>::value> {
|
||||
base_t::take(std::move(rhs));
|
||||
alloc_.take(std::move(rhs.alloc_));
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
/*
|
||||
* byte alignment is always alignof(std::max_align_t).
|
||||
*/
|
||||
size = detail::aligned(size, alignof(std::max_align_t));
|
||||
void* ptr;
|
||||
// size would never be 0 here
|
||||
if (remain() < size) {
|
||||
std::size_t chunk_size = ipc::detail::max<std::size_t>(aligned_chunk_size, size);
|
||||
ptr = alloc_.alloc(chunk_size);
|
||||
tail_ = static_cast<byte_t*>(ptr) + chunk_size;
|
||||
head_ = tail_ - (chunk_size - size);
|
||||
}
|
||||
else {
|
||||
ptr = head_;
|
||||
head_ += size;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -1,327 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <thread>
|
||||
#include <deque> // std::deque
|
||||
#include <functional> // std::function
|
||||
#include <utility> // std::forward
|
||||
#include <cstddef>
|
||||
#include <cassert> // assert
|
||||
#include <type_traits> // std::aligned_storage_t
|
||||
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/rw_lock.h"
|
||||
#include "libipc/pool_alloc.h"
|
||||
|
||||
#include "libipc/utility/concept.h"
|
||||
#include "libipc/memory/alloc.h"
|
||||
#include "libipc/platform/detail.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Thread-safe allocation wrapper
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
IPC_CONCEPT_(is_comparable, operator<(std::declval<Type>()));
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename AllocP, bool = detail::is_comparable<AllocP>::value>
|
||||
class limited_recycler;
|
||||
|
||||
template <typename AllocP>
|
||||
class limited_recycler<AllocP, true> {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
protected:
|
||||
std::deque<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:
|
||||
void try_recover(alloc_policy & alc) {
|
||||
LIBIPC_UNUSED auto guard = ipc::detail::unique_lock(master_lock_);
|
||||
if (master_allocs_.empty()) return;
|
||||
take_first_do([&alc](alloc_policy & first) { alc.swap(first); });
|
||||
}
|
||||
|
||||
void collect(alloc_policy && alc) {
|
||||
LIBIPC_UNUSED auto guard = ipc::detail::unique_lock(master_lock_);
|
||||
if (master_allocs_.size() >= 32) {
|
||||
take_first_do([](alloc_policy &) {}); // erase first
|
||||
}
|
||||
master_allocs_.emplace_back(std::move(alc));
|
||||
}
|
||||
|
||||
IPC_CONSTEXPR_ 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) {
|
||||
LIBIPC_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>
|
||||
auto try_replenish(alloc_policy & alc, std::size_t size)
|
||||
-> ipc::require<detail::has_take<A>::value && has_remain<A>::value> {
|
||||
if (alc.remain() >= size) return;
|
||||
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_remain<A>::value && has_empty<A>::value> {
|
||||
if (!alc.empty()) return;
|
||||
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>
|
||||
IPC_CONSTEXPR_ auto try_replenish(alloc_policy & /*alc*/, std::size_t /*size*/) noexcept
|
||||
-> ipc::require<(!detail::has_take<A>::value || !has_remain<A>::value) && !has_empty<A>::value> {
|
||||
// Do Nothing.
|
||||
}
|
||||
};
|
||||
|
||||
template <typename AllocP>
|
||||
class empty_recycler {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
IPC_CONSTEXPR_ void try_recover(alloc_policy&) noexcept {}
|
||||
IPC_CONSTEXPR_ auto try_replenish(alloc_policy&, std::size_t) noexcept {}
|
||||
IPC_CONSTEXPR_ void collect(alloc_policy&&) noexcept {}
|
||||
};
|
||||
|
||||
template <typename AllocP,
|
||||
template <typename> class RecyclerP = default_recycler>
|
||||
class async_wrapper {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
|
||||
private:
|
||||
RecyclerP<alloc_policy> recycler_;
|
||||
|
||||
class alloc_proxy : public AllocP {
|
||||
async_wrapper * w_ = nullptr;
|
||||
|
||||
public:
|
||||
alloc_proxy(alloc_proxy && rhs) = default;
|
||||
|
||||
template <typename ... P>
|
||||
alloc_proxy(async_wrapper* w, P && ... pars)
|
||||
: AllocP(std::forward<P>(pars) ...), w_(w) {
|
||||
assert(w_ != nullptr);
|
||||
w_->recycler_.try_recover(*this);
|
||||
}
|
||||
|
||||
~alloc_proxy() {
|
||||
w_->recycler_.collect(std::move(*this));
|
||||
}
|
||||
|
||||
auto alloc(std::size_t size) {
|
||||
w_->recycler_.try_replenish(*this, size);
|
||||
return AllocP::alloc(size);
|
||||
}
|
||||
};
|
||||
|
||||
friend class alloc_proxy;
|
||||
using ref_t = alloc_proxy&;
|
||||
|
||||
std::function<ref_t()> get_alloc_;
|
||||
|
||||
public:
|
||||
template <typename ... P>
|
||||
async_wrapper(P ... pars) {
|
||||
get_alloc_ = [this, pars ...]()->ref_t {
|
||||
thread_local alloc_proxy tls(pars ...);
|
||||
return tls;
|
||||
};
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
return get_alloc_().alloc(size);
|
||||
}
|
||||
|
||||
void free(void* p, std::size_t size) {
|
||||
get_alloc_().free(p, size);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Thread-safe allocation wrapper (with spin_lock)
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename AllocP, typename MutexT = ipc::spin_lock>
|
||||
class sync_wrapper {
|
||||
public:
|
||||
using alloc_policy = AllocP;
|
||||
using mutex_type = MutexT;
|
||||
|
||||
private:
|
||||
mutex_type lock_;
|
||||
alloc_policy alloc_;
|
||||
|
||||
public:
|
||||
template <typename ... P>
|
||||
sync_wrapper(P && ... pars)
|
||||
: alloc_(std::forward<P>(pars) ...)
|
||||
{}
|
||||
|
||||
void swap(sync_wrapper& rhs) {
|
||||
LIBIPC_UNUSED auto guard = ipc::detail::unique_lock(lock_);
|
||||
alloc_.swap(rhs.alloc_);
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
LIBIPC_UNUSED auto guard = ipc::detail::unique_lock(lock_);
|
||||
return alloc_.alloc(size);
|
||||
}
|
||||
|
||||
void free(void* p, std::size_t size) {
|
||||
LIBIPC_UNUSED auto guard = ipc::detail::unique_lock(lock_);
|
||||
alloc_.free(p, size);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// Variable memory allocation wrapper
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
template <std::size_t BaseSize = 0, std::size_t IterSize = sizeof(void*)>
|
||||
struct default_mapping_policy {
|
||||
|
||||
enum : std::size_t {
|
||||
base_size = BaseSize,
|
||||
iter_size = IterSize,
|
||||
classes_size = 64
|
||||
};
|
||||
|
||||
template <typename F, typename ... P>
|
||||
IPC_CONSTEXPR_ static void foreach(F && f, P && ... params) {
|
||||
for (std::size_t i = 0; i < classes_size; ++i) {
|
||||
f(i, std::forward<P>(params)...);
|
||||
}
|
||||
}
|
||||
|
||||
IPC_CONSTEXPR_ static std::size_t block_size(std::size_t id) noexcept {
|
||||
return (id < classes_size) ? (base_size + (id + 1) * iter_size) : 0;
|
||||
}
|
||||
|
||||
template <typename F, typename D, typename ... P>
|
||||
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;
|
||||
return (id < classes_size) ?
|
||||
f(id, size, std::forward<P>(params)...) :
|
||||
d(size, std::forward<P>(params)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FixedAlloc,
|
||||
typename DefaultAlloc = mem::static_alloc,
|
||||
typename MappingP = default_mapping_policy<>>
|
||||
class variable_wrapper {
|
||||
|
||||
struct initiator {
|
||||
|
||||
using falc_t = std::aligned_storage_t<sizeof(FixedAlloc), alignof(FixedAlloc)>;
|
||||
falc_t arr_[MappingP::classes_size];
|
||||
|
||||
initiator() {
|
||||
MappingP::foreach([](std::size_t id, falc_t * a) {
|
||||
ipc::mem::construct(&initiator::at(a, id), MappingP::block_size(id));
|
||||
}, arr_);
|
||||
}
|
||||
|
||||
~initiator() {
|
||||
MappingP::foreach([](std::size_t id, falc_t * a) {
|
||||
ipc::mem::destruct(&initiator::at(a, id));
|
||||
}, arr_);
|
||||
}
|
||||
|
||||
static FixedAlloc & at(falc_t * arr, std::size_t id) noexcept {
|
||||
return reinterpret_cast<FixedAlloc&>(arr[id]);
|
||||
}
|
||||
} init_;
|
||||
|
||||
using falc_t = typename initiator::falc_t;
|
||||
|
||||
public:
|
||||
void swap(variable_wrapper & other) {
|
||||
MappingP::foreach([](std::size_t id, falc_t * in, falc_t * ot) {
|
||||
initiator::at(in, id).swap(initiator::at(ot, id));
|
||||
}, init_.arr_, other.init_.arr_);
|
||||
}
|
||||
|
||||
void* alloc(std::size_t size) {
|
||||
return MappingP::classify([](std::size_t id, std::size_t size, falc_t * a) {
|
||||
return initiator::at(a, id).alloc(size);
|
||||
}, [](std::size_t size, falc_t *) {
|
||||
return DefaultAlloc::alloc(size);
|
||||
}, size, init_.arr_);
|
||||
}
|
||||
|
||||
void free(void* p, std::size_t size) {
|
||||
MappingP::classify([](std::size_t id, std::size_t size, void* p, falc_t * a) {
|
||||
initiator::at(a, id).free(p, size);
|
||||
}, [](std::size_t size, void* p, falc_t *) {
|
||||
DefaultAlloc::free(p, size);
|
||||
}, size, p, init_.arr_);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/// 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);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -13,10 +13,10 @@
|
||||
|
||||
#include "libipc/shm.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/pool_alloc.h"
|
||||
|
||||
#include "libipc/utility/log.h"
|
||||
#include "libipc/mem/resource.h"
|
||||
#include "libipc/mem/new.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -81,7 +81,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
||||
::fchmod(fd, S_IRUSR | S_IWUSR |
|
||||
S_IRGRP | S_IWGRP |
|
||||
S_IROTH | S_IWOTH);
|
||||
auto ii = mem::alloc<id_info_t>();
|
||||
auto ii = mem::$new<id_info_t>();
|
||||
ii->fd_ = fd;
|
||||
ii->size_ = size;
|
||||
ii->name_ = std::move(op_name);
|
||||
@ -177,7 +177,7 @@ std::int32_t release(id_t id) noexcept {
|
||||
}
|
||||
}
|
||||
else ::munmap(ii->mem_, ii->size_);
|
||||
mem::free(ii);
|
||||
mem::$delete(ii);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
|
||||
#include "libipc/shm.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/pool_alloc.h"
|
||||
|
||||
#include "libipc/utility/log.h"
|
||||
#include "libipc/mem/resource.h"
|
||||
#include "libipc/mem/new.h"
|
||||
|
||||
#include "to_tchar.h"
|
||||
#include "get_sa.h"
|
||||
@ -58,7 +58,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto ii = mem::alloc<id_info_t>();
|
||||
auto ii = mem::$new<id_info_t>();
|
||||
ii->h_ = h;
|
||||
ii->size_ = size;
|
||||
return ii;
|
||||
@ -116,7 +116,7 @@ std::int32_t release(id_t id) noexcept {
|
||||
ipc::error("fail release: invalid id (h = null)\n");
|
||||
}
|
||||
else ::CloseHandle(ii->h_);
|
||||
mem::free(ii);
|
||||
mem::$delete(ii);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
#include "libipc/pool_alloc.h"
|
||||
|
||||
#include "libipc/mem/resource.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
void* pool_alloc::alloc(std::size_t size) noexcept {
|
||||
return async_pool_alloc::alloc(size);
|
||||
}
|
||||
|
||||
void pool_alloc::free(void* p, std::size_t size) noexcept {
|
||||
async_pool_alloc::free(p, size);
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
#include "libipc/platform/detail.h"
|
||||
#include "libipc/utility/concept.h"
|
||||
#include "libipc/pool_alloc.h"
|
||||
#include "libipc/mem/new.h"
|
||||
|
||||
namespace ipc {
|
||||
|
||||
@ -36,12 +36,12 @@ IPC_CONSTEXPR_ auto clear_impl(T* p) -> IsImplComfortable<T, void> {
|
||||
|
||||
template <typename T, typename... P>
|
||||
IPC_CONSTEXPR_ auto make_impl(P&&... params) -> IsImplUncomfortable<T> {
|
||||
return mem::alloc<T>(std::forward<P>(params)...);
|
||||
return mem::$new<T>(std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
IPC_CONSTEXPR_ auto clear_impl(T* p) -> IsImplUncomfortable<T, void> {
|
||||
mem::free(p);
|
||||
mem::$delete(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -11,12 +11,12 @@
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
TEST(polymorphic_allocator, construct) {
|
||||
TEST(polymorphic_allocator, ctor) {
|
||||
ipc::mem::bytes_allocator alc;
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, construct_value_initialization) {
|
||||
TEST(polymorphic_allocator, ctor_value_initialization) {
|
||||
ipc::mem::bytes_allocator alc{};
|
||||
auto p = alc.allocate(128);
|
||||
EXPECT_NE(p, nullptr);
|
||||
@ -57,7 +57,7 @@ TEST(polymorphic_allocator, memory_resource_traits) {
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, construct_copy_move) {
|
||||
TEST(polymorphic_allocator, ctor_copy_move) {
|
||||
ipc::mem::new_delete_resource mem_res;
|
||||
dummy_resource dummy_res;
|
||||
ipc::mem::bytes_allocator alc1{&mem_res}, alc2{&dummy_res};
|
||||
|
||||
@ -12,16 +12,16 @@ TEST(central_cache_pool, ctor) {
|
||||
ASSERT_FALSE((std::is_copy_assignable<ipc::mem::central_cache_pool<ipc::mem::block<1>, 1>>::value));
|
||||
ASSERT_FALSE((std::is_move_assignable<ipc::mem::central_cache_pool<ipc::mem::block<1>, 1>>::value));
|
||||
{
|
||||
auto &pool = ipc::mem::central_cache_pool<ipc::mem::block<1>, 1>::instance();
|
||||
ipc::mem::block<1> *b1 = pool.aqueire();
|
||||
auto &pool = ipc::mem::central_cache_pool<ipc::mem::block<1024>, 1>::instance();
|
||||
ipc::mem::block<1024> *b1 = pool.aqueire();
|
||||
ASSERT_FALSE(nullptr == b1);
|
||||
ASSERT_TRUE (nullptr == b1->next);
|
||||
EXPECT_TRUE (nullptr == b1->next);
|
||||
pool.release(b1);
|
||||
ipc::mem::block<1> *b2 = pool.aqueire();
|
||||
ipc::mem::block<1024> *b2 = pool.aqueire();
|
||||
EXPECT_EQ(b1, b2);
|
||||
ipc::mem::block<1> *b3 = pool.aqueire();
|
||||
ipc::mem::block<1024> *b3 = pool.aqueire();
|
||||
ASSERT_FALSE(nullptr == b3);
|
||||
ASSERT_TRUE (nullptr == b3->next);
|
||||
EXPECT_TRUE (nullptr == b3->next);
|
||||
EXPECT_NE(b1, b3);
|
||||
}
|
||||
{
|
||||
@ -29,7 +29,7 @@ TEST(central_cache_pool, ctor) {
|
||||
ipc::mem::block<1> *b1 = pool.aqueire();
|
||||
ASSERT_FALSE(nullptr == b1);
|
||||
ASSERT_FALSE(nullptr == b1->next);
|
||||
ASSERT_TRUE (nullptr == b1->next->next);
|
||||
EXPECT_TRUE (nullptr == b1->next->next);
|
||||
pool.release(b1);
|
||||
ipc::mem::block<1> *b2 = pool.aqueire();
|
||||
EXPECT_EQ(b1, b2);
|
||||
@ -38,7 +38,7 @@ TEST(central_cache_pool, ctor) {
|
||||
ipc::mem::block<1> *b4 = pool.aqueire();
|
||||
ASSERT_FALSE(nullptr == b4);
|
||||
ASSERT_FALSE(nullptr == b4->next);
|
||||
ASSERT_TRUE (nullptr == b4->next->next);
|
||||
EXPECT_TRUE (nullptr == b4->next->next);
|
||||
EXPECT_NE(b1, b4);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
#include "libipc/ipc.h"
|
||||
#include "libipc/buffer.h"
|
||||
@ -84,18 +85,19 @@ void test_basic(char const * name) {
|
||||
}
|
||||
|
||||
class data_set {
|
||||
std::vector<rand_buf> datas_;
|
||||
alignas(rand_buf) char datas_[sizeof(rand_buf[LoopCount])];
|
||||
rand_buf *d_;
|
||||
|
||||
public:
|
||||
data_set() {
|
||||
datas_.resize(LoopCount);
|
||||
d_ = ::new(datas_) rand_buf[LoopCount];
|
||||
for (int i = 0; i < LoopCount; ++i) {
|
||||
datas_[i].set_id(i);
|
||||
d_[i].set_id(i);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rand_buf> const &get() const noexcept {
|
||||
return datas_;
|
||||
rand_buf const *get() const noexcept {
|
||||
return d_;
|
||||
}
|
||||
} const data_set__;
|
||||
|
||||
@ -112,7 +114,7 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
||||
Que que { name, ipc::sender };
|
||||
ASSERT_TRUE(que.wait_for_recv(r_cnt));
|
||||
sw.start();
|
||||
for (int i = 0; i < (int)data_set__.get().size(); ++i) {
|
||||
for (int i = 0; i < LoopCount; ++i) {
|
||||
ASSERT_TRUE(que.send(data_set__.get()[i]));
|
||||
}
|
||||
};
|
||||
@ -128,7 +130,7 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
||||
if (i == -1) {
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE((i >= 0) && (i < (int)data_set__.get().size()));
|
||||
ASSERT_TRUE((i >= 0) && (i < LoopCount));
|
||||
auto const &data_set = data_set__.get()[i];
|
||||
if (data_set != got) {
|
||||
printf("data_set__.get()[%d] != got, size = %zd/%zd\n",
|
||||
@ -146,7 +148,7 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
||||
que.send(rand_buf{msg_head{-1}});
|
||||
}
|
||||
ipc_ut::reader().wait_for_done();
|
||||
sw.print_elapsed<std::chrono::microseconds>(s_cnt, r_cnt, (int)data_set__.get().size(), name);
|
||||
sw.print_elapsed<std::chrono::microseconds>(s_cnt, r_cnt, LoopCount, name);
|
||||
}
|
||||
|
||||
} // internal-linkage
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user