add: [concur] ut for prod-cons

This commit is contained in:
mutouyun 2022-11-26 17:48:18 +08:00
parent 4981ce7b9c
commit 8540de7797
8 changed files with 203 additions and 16 deletions

View File

@ -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
View 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
View 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

View 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_

View 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_

View File

@ -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 {

View File

@ -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_

View File

@ -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);
}