mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-09 23:23:59 +00:00
test interprocess concurrency (#258)
* added cfoa_interprocess_concurrency_tests * avoided C++14 digit separators * stopped using exit codes to pass numerical info to parent * Reorder includes to make msvc-14.0 happy * made cumulative_stats interprocess concurrency safe * disabled interprocess_concurrency_tests for Clang 3.5-8 (Boost.Process compile error) * made test names shorter for the benefit of MINGW32 --------- Co-authored-by: Peter Dimov <pdimov@gmail.com>
This commit is contained in:
parent
a166a56401
commit
e3818afd45
@ -170,7 +170,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</Expand>
|
</Expand>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
<Type Name="boost::unordered::detail::cumulative_stats<*>" Inheritable="true">
|
<Type Name="boost::unordered::detail::foa::cumulative_stats<*>" Inheritable="true">
|
||||||
<Intrinsic Name="bit_cast_to_double" Expression="*reinterpret_cast<double*>(&i)">
|
<Intrinsic Name="bit_cast_to_double" Expression="*reinterpret_cast<double*>(&i)">
|
||||||
<Parameter Name="i" Type="uint64_t" />
|
<Parameter Name="i" Type="uint64_t" />
|
||||||
</Intrinsic>
|
</Intrinsic>
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||||
#include <boost/unordered/detail/cumulative_stats.hpp>
|
#include <boost/unordered/detail/foa/cumulative_stats.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_DISABLE_SSE2)
|
#if !defined(BOOST_UNORDERED_DISABLE_SSE2)
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
* See https://www.boost.org/libs/unordered for library home page.
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_CUMULATIVE_STATS_HPP
|
#ifndef BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
|
||||||
#define BOOST_UNORDERED_DETAIL_CUMULATIVE_STATS_HPP
|
#define BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
@ -16,12 +16,14 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#if defined(BOOST_HAS_THREADS)
|
#if defined(BOOST_HAS_THREADS)
|
||||||
|
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
namespace unordered{
|
namespace unordered{
|
||||||
namespace detail{
|
namespace detail{
|
||||||
|
namespace foa{
|
||||||
|
|
||||||
/* Cumulative one-pass calculation of the average, variance and deviation of
|
/* Cumulative one-pass calculation of the average, variance and deviation of
|
||||||
* running sequences.
|
* running sequences.
|
||||||
@ -117,7 +119,7 @@ template<std::size_t N>
|
|||||||
class concurrent_cumulative_stats:cumulative_stats<N>
|
class concurrent_cumulative_stats:cumulative_stats<N>
|
||||||
{
|
{
|
||||||
using super=cumulative_stats<N>;
|
using super=cumulative_stats<N>;
|
||||||
using lock_guard=std::lock_guard<std::mutex>;
|
using lock_guard=std::lock_guard<rw_spinlock>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using summary=typename super::summary;
|
using summary=typename super::summary;
|
||||||
@ -157,7 +159,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
concurrent_cumulative_stats(const super& x,lock_guard&&):super{x}{}
|
concurrent_cumulative_stats(const super& x,lock_guard&&):super{x}{}
|
||||||
|
|
||||||
mutable std::mutex mut;
|
mutable rw_spinlock mut;
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -167,6 +169,7 @@ using concurrent_cumulative_stats=cumulative_stats<N>;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
} /* namespace foa */
|
||||||
} /* namespace detail */
|
} /* namespace detail */
|
||||||
} /* namespace unordered */
|
} /* namespace unordered */
|
||||||
} /* namespace boost */
|
} /* namespace boost */
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
# Copyright 2006-2008 Daniel James.
|
# Copyright 2006-2008 Daniel James.
|
||||||
# Copyright 2022-2023 Christian Mazakas
|
# Copyright 2022-2023 Christian Mazakas
|
||||||
|
# Copyright 2024 Joaquin M Lopez Munoz
|
||||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -359,6 +360,27 @@ run cfoa/serialization_tests.cpp
|
|||||||
<library>/boost//serialization/<warnings>off
|
<library>/boost//serialization/<warnings>off
|
||||||
: cfoa_serialization_tests ;
|
: cfoa_serialization_tests ;
|
||||||
|
|
||||||
|
rule make_cfoa_interprocess_concurrency_tests ( name : defines ? )
|
||||||
|
{
|
||||||
|
run cfoa/interprocess_concurrency_tests.cpp /boost/filesystem//boost_filesystem : :
|
||||||
|
: <define>$(defines)
|
||||||
|
<warnings>off
|
||||||
|
<link>static
|
||||||
|
<toolset>clang-3.5:<build>no # Boost.Process does not compile
|
||||||
|
<toolset>clang-3.6:<build>no # idem
|
||||||
|
<toolset>clang-3.7:<build>no # idem
|
||||||
|
<toolset>clang-3.8:<build>no # idem
|
||||||
|
<target-os>cygwin:<build>no
|
||||||
|
: $(name) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
make_cfoa_interprocess_concurrency_tests cfoa_interproc_conc_tests ;
|
||||||
|
|
||||||
|
make_cfoa_interprocess_concurrency_tests cfoa_interproc_conc_tests_stats
|
||||||
|
: BOOST_UNORDERED_ENABLE_STATS ;
|
||||||
|
|
||||||
alias cfoa_tests :
|
alias cfoa_tests :
|
||||||
cfoa_$(CFOA_TESTS)
|
cfoa_$(CFOA_TESTS)
|
||||||
cfoa_serialization_tests ;
|
cfoa_serialization_tests
|
||||||
|
cfoa_interproc_conc_tests
|
||||||
|
cfoa_interproc_conc_tests_stats ;
|
||||||
|
114
test/cfoa/interprocess_concurrency_tests.cpp
Normal file
114
test/cfoa/interprocess_concurrency_tests.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright (C) 2024 Joaquin M Lopez Munoz
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
|
#include <atomic>
|
||||||
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
#include <boost/interprocess/allocators/allocator.hpp>
|
||||||
|
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||||
|
#include <boost/process/child.hpp>
|
||||||
|
#include <boost/uuid/random_generator.hpp>
|
||||||
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace bip=boost::interprocess;
|
||||||
|
|
||||||
|
static char const* container_name = "shared_map";
|
||||||
|
static char const* start_name = "shared_start";
|
||||||
|
static constexpr int NUM_OPS_PER_CHILD = 10000;
|
||||||
|
|
||||||
|
using value_type = std::pair<const int, int>;
|
||||||
|
using allocator = bip::allocator<
|
||||||
|
value_type, bip::managed_shared_memory::segment_manager>;
|
||||||
|
using container = boost::concurrent_flat_map<
|
||||||
|
int, int, boost::hash<int>, std::equal_to<int>, allocator>;
|
||||||
|
|
||||||
|
int parent(const char* exe_name)
|
||||||
|
{
|
||||||
|
static constexpr int NUM_CHILDS = 10;
|
||||||
|
static constexpr std::size_t SEGMENT_SIZE = 64*1024;
|
||||||
|
|
||||||
|
std::string segment_name_str = to_string(boost::uuids::random_generator()());
|
||||||
|
auto* segment_name = segment_name_str.c_str();
|
||||||
|
|
||||||
|
struct segment_remover
|
||||||
|
{
|
||||||
|
char const* name;
|
||||||
|
|
||||||
|
segment_remover(char const* name_) : name(name_)
|
||||||
|
{
|
||||||
|
bip::shared_memory_object::remove(name);
|
||||||
|
}
|
||||||
|
~segment_remover()
|
||||||
|
{
|
||||||
|
bip::shared_memory_object::remove(name);
|
||||||
|
}
|
||||||
|
} remover(segment_name);
|
||||||
|
|
||||||
|
bip::managed_shared_memory segment(
|
||||||
|
bip::create_only, segment_name, SEGMENT_SIZE);
|
||||||
|
container& c = *segment.construct<container>(container_name)(
|
||||||
|
allocator(segment.get_segment_manager()));
|
||||||
|
std::atomic_int& start = *segment.construct<std::atomic_int>(start_name)(0);
|
||||||
|
|
||||||
|
std::vector<boost::process::child> children;
|
||||||
|
for (int i = 0; i < NUM_CHILDS; ++i) {
|
||||||
|
children.emplace_back(exe_name, std::to_string(i), segment_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
start.store(1);
|
||||||
|
|
||||||
|
for (auto& child : children) {
|
||||||
|
child.wait();
|
||||||
|
BOOST_TEST_EQ(child.exit_code(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_ops = 0;
|
||||||
|
c.cvisit_all([&](const value_type& x) {
|
||||||
|
num_ops += x.second;
|
||||||
|
});
|
||||||
|
BOOST_TEST_EQ(num_ops, NUM_CHILDS * NUM_OPS_PER_CHILD);
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
int child(int id,const char* segment_name)
|
||||||
|
{
|
||||||
|
bip::managed_shared_memory segment(bip::open_only, segment_name);
|
||||||
|
container& c = *segment.find<container>(container_name).first;
|
||||||
|
std::atomic_int& start = *segment.find<std::atomic_int>(start_name).first;
|
||||||
|
|
||||||
|
while(!start.load()){
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mt19937 rnd((unsigned int) id);
|
||||||
|
std::geometric_distribution<int> d(0.15);
|
||||||
|
|
||||||
|
for(int i = 0; i < NUM_OPS_PER_CHILD; ++i) {
|
||||||
|
c.emplace_or_visit(d(rnd), 1, [&](value_type& x) {
|
||||||
|
++x.second;
|
||||||
|
|
||||||
|
// artificially increase contention
|
||||||
|
volatile unsigned int n = 10000;
|
||||||
|
while(n--) ;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
if (argc == 1) {
|
||||||
|
return parent(argv[0]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return child(std::atoi(argv[1]),argv[2]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user