mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
add: [concur] ut for prod-cons
This commit is contained in:
parent
4981ce7b9c
commit
8540de7797
@ -95,14 +95,14 @@ struct producer<trans::unicast, relation::single> {
|
||||
auto f_ct = elem.get_flag();
|
||||
/// @remark Verify index.
|
||||
if ((f_ct != state::invalid_value) &&
|
||||
(f_ct != static_cast<state::flag_t>(w_idx))) {
|
||||
(f_ct != w_idx)) {
|
||||
return false; // full
|
||||
}
|
||||
/// @remark Get a valid index and iterate backwards.
|
||||
ctx.w_idx += 1;
|
||||
/// @remark Set data & flag.
|
||||
elem.set_data(std::forward<U>(src));
|
||||
elem.set_flag(static_cast<state::flag_t>(~w_idx));
|
||||
elem.set_flag(static_cast<index_t>(~w_idx));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -131,12 +131,12 @@ struct producer<trans::unicast, relation::multi> {
|
||||
return false; // full
|
||||
}
|
||||
/// @remark Get a valid index and iterate backwards.
|
||||
if (!ctx.w_idx.compare_exchange_week(w_idx, w_idx + 1, std::memory_order_acq_rel)) {
|
||||
if (!ctx.w_idx.compare_exchange_weak(w_idx, w_idx + 1, std::memory_order_acq_rel)) {
|
||||
continue;
|
||||
}
|
||||
/// @remark Set data & flag.
|
||||
elem.set_data(std::forward<U>(src));
|
||||
elem.set_flag(~w_idx);
|
||||
elem.set_flag(static_cast<index_t>(~w_idx));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -160,7 +160,7 @@ struct consumer<trans::unicast, relation::single> {
|
||||
auto &elem = elems[r_cur];
|
||||
auto f_ct = elem.get_flag();
|
||||
/// @remark Verify index.
|
||||
if (f_ct != ~r_idx) {
|
||||
if (f_ct != static_cast<index_t>(~r_idx)) {
|
||||
return false; // empty
|
||||
}
|
||||
/// @remark Get a valid index and iterate backwards.
|
||||
@ -191,11 +191,11 @@ struct consumer<trans::unicast, relation::multi> {
|
||||
auto &elem = elems[r_cur];
|
||||
auto f_ct = elem.get_flag();
|
||||
/// @remark Verify index.
|
||||
if (f_ct != ~r_idx) {
|
||||
if (f_ct != static_cast<index_t>(~r_idx)) {
|
||||
return false; // empty
|
||||
}
|
||||
/// @remark Get a valid index and iterate backwards.
|
||||
if (!ctx.r_idx.compare_exchange_week(r_idx, r_idx + 1, std::memory_order_acq_rel)) {
|
||||
if (!ctx.r_idx.compare_exchange_weak(r_idx, r_idx + 1, std::memory_order_acq_rel)) {
|
||||
continue;
|
||||
}
|
||||
/// @remark Get data & set flag.
|
||||
@ -249,6 +249,10 @@ struct prod_cons : producer<TransModT, ProdModT>
|
||||
constexpr context(index_t cs) noexcept
|
||||
: circ_size(cs) {}
|
||||
|
||||
template <typename T>
|
||||
constexpr context(::LIBIMP_::span<element<T>> elems) noexcept
|
||||
: circ_size(static_cast<index_t>(elems.size())) {}
|
||||
|
||||
constexpr bool valid() const noexcept {
|
||||
/// @remark circ_size must be a power of two.
|
||||
return (circ_size > 1) && ((circ_size & (circ_size - 1)) == 0);
|
||||
|
||||
40
include/libimp/nameof.h
Normal file
40
include/libimp/nameof.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file libimp/nameof.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Gets the name string of a type.
|
||||
* @date 2022-11-26
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/span.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* @brief The conventional way to obtain demangled symbol name.
|
||||
* @see https://www.boost.org/doc/libs/1_80_0/libs/core/doc/html/core/demangle.html
|
||||
*
|
||||
* @param name the mangled name
|
||||
* @return std::string a human-readable demangled type name
|
||||
*/
|
||||
std::string demangle(span<char const> name) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Returns an implementation defined string containing the name of the type.
|
||||
* @see https://en.cppreference.com/w/cpp/types/type_info/name
|
||||
*
|
||||
* @tparam T a type
|
||||
* @return std::string a human-readable demangled type name
|
||||
*/
|
||||
template <typename T>
|
||||
std::string nameof() noexcept {
|
||||
auto c_str_name = typeid(T).name();
|
||||
return demangle({c_str_name, std::strlen(c_str_name)});
|
||||
}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
7
src/libimp/nameof.cpp
Normal file
7
src/libimp/nameof.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "libimp/detect_plat.h"
|
||||
#if defined(LIBIMP_CC_GNUC)
|
||||
# include "libimp/platform/gnuc/demangle.h"
|
||||
#else
|
||||
# include "libimp/platform/win/demangle.h"
|
||||
#endif
|
||||
41
src/libimp/platform/gnuc/demangle.h
Normal file
41
src/libimp/platform/gnuc/demangle.h
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file libimp/platform/gnuc/demangle.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cxxabi.h> // abi::__cxa_demangle
|
||||
|
||||
#include <cstdlib> // std::malloc
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/nameof.h"
|
||||
#include "libimp/log.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* @brief The conventional way to obtain demangled symbol name.
|
||||
* @see https://www.boost.org/doc/libs/1_80_0/libs/core/doc/html/core/demangle.html
|
||||
*
|
||||
* @param name the mangled name
|
||||
* @return std::string a human-readable demangled type name
|
||||
*/
|
||||
std::string demangle(span<char const> name) noexcept {
|
||||
LIBIMP_LOG_();
|
||||
/// @see https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html
|
||||
std::size_t sz = name.size() + 1;
|
||||
char *buffer = static_cast<char *>(std::malloc(sz));
|
||||
int status = 0;
|
||||
char *realname = abi::__cxa_demangle(name.data(), buffer, &sz, &status);
|
||||
if (realname == nullptr) {
|
||||
log.error("failed: abi::__cxa_demangle(sz = {}), status = {}", sz, status);
|
||||
std::free(buffer);
|
||||
return {};
|
||||
}
|
||||
std::string demangled(realname, sz);
|
||||
std::free(realname);
|
||||
return demangled;
|
||||
}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
16
src/libimp/platform/win/demangle.h
Normal file
16
src/libimp/platform/win/demangle.h
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @file libimp/platform/win/demangle.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/nameof.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
std::string demangle(span<char const> name) noexcept {
|
||||
return std::string(name.data(), name.size());
|
||||
}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
@ -1,12 +1,13 @@
|
||||
#include "libimp/detect_plat.h"
|
||||
#if defined(LIBIMP_OS_WIN)
|
||||
#include "libimp/platform/win/system.h"
|
||||
#else
|
||||
#include "libimp/platform/posix/system.h"
|
||||
#endif
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "libimp/detect_plat.h"
|
||||
#if defined(LIBIMP_OS_WIN)
|
||||
# include "libimp/platform/win/system.h"
|
||||
#else
|
||||
# include "libimp/platform/posix/system.h"
|
||||
#endif
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
namespace sys {
|
||||
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
|
||||
#include "libimp/detect_plat.h"
|
||||
#if defined(LIBIMP_OS_WIN)
|
||||
#include "libipc/platform/win/shm_impl.h"
|
||||
# include "libipc/platform/win/shm_impl.h"
|
||||
#else
|
||||
#include "libipc/platform/posix/shm_impl.h"
|
||||
# include "libipc/platform/posix/shm_impl.h"
|
||||
#endif
|
||||
|
||||
LIBIPC_NAMESPACE_BEG_
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <typeinfo>
|
||||
#include <cstddef>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libconcur/concurrent.h"
|
||||
#include "libimp/countof.h"
|
||||
#include "libimp/log.h"
|
||||
#include "libimp/nameof.h"
|
||||
|
||||
TEST(concurrent, cache_line_size) {
|
||||
std::cout << concur::cache_line_size << "\n";
|
||||
@ -80,3 +87,74 @@ TEST(concurrent, trunc_index) {
|
||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, 111), 111);
|
||||
EXPECT_EQ(concur::trunc_index(context{2147483648u}, -1), 2147483647);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename PC>
|
||||
void test_concur(std::size_t np, std::size_t nc, std::size_t k) {
|
||||
LIBIMP_LOG_();
|
||||
log.info("\n\tStart with: {}, {} producers, {} consumers...", imp::nameof<PC>(), np, nc);
|
||||
|
||||
constexpr static std::uint32_t loop_size = 100'0000;
|
||||
|
||||
concur::element<std::uint64_t> circ[32] {};
|
||||
PC pc;
|
||||
PC::context ctx {imp::make_span(circ)};
|
||||
ASSERT_TRUE(ctx.valid());
|
||||
|
||||
std::atomic<std::uint64_t> sum {0};
|
||||
std::atomic<std::size_t> running {np};
|
||||
|
||||
auto prod_call = [&](std::size_t n) {
|
||||
for (std::uint32_t i = 1; i <= loop_size; ++i) {
|
||||
std::this_thread::yield();
|
||||
while (!pc.enqueue(imp::make_span(circ), ctx, i)) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
if (i % (loop_size / 10) == 0) {
|
||||
log.info("[{}] put count: {}", n, i);
|
||||
}
|
||||
}
|
||||
--running;
|
||||
};
|
||||
auto cons_call = [&] {
|
||||
for (;;) {
|
||||
std::this_thread::yield();
|
||||
std::uint64_t i;
|
||||
while (!pc.dequeue(imp::make_span(circ), ctx, i)) {
|
||||
if (running == 0) return;
|
||||
std::this_thread::yield();
|
||||
}
|
||||
sum += i;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::thread> prods(np);
|
||||
for (std::size_t n = 0; n < np; ++n) prods[n] = std::thread(prod_call, n);
|
||||
std::vector<std::thread> conss(nc);
|
||||
for (auto &c : conss) c = std::thread(cons_call);
|
||||
|
||||
for (auto &p : prods) p.join();
|
||||
for (auto &c : conss) c.join();
|
||||
|
||||
EXPECT_EQ(sum, k * np * (loop_size * std::uint64_t(loop_size + 1)) / 2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(concurrent, prod_cons) {
|
||||
using namespace concur;
|
||||
|
||||
test_concur<prod_cons<trans::unicast, relation::single, relation::single>>(1, 1, 1);
|
||||
test_concur<prod_cons<trans::unicast, relation::single, relation::multi >>(1, 1, 1);
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::single>>(1, 1, 1);
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::multi >>(1, 1, 1);
|
||||
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::single>>(8, 1, 1);
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::multi >>(8, 1, 1);
|
||||
|
||||
test_concur<prod_cons<trans::unicast, relation::single, relation::multi >>(1, 8, 1);
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::multi >>(1, 8, 1);
|
||||
|
||||
test_concur<prod_cons<trans::unicast, relation::multi , relation::multi >>(8, 8, 1);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user