forked from boostorg/unordered
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:
co-authored by
Peter Dimov
parent
a166a56401
commit
e3818afd45
@@ -41,7 +41,7 @@
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||
#include <boost/unordered/detail/cumulative_stats.hpp>
|
||||
#include <boost/unordered/detail/foa/cumulative_stats.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_DISABLE_SSE2)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/* Copyright 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)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP
|
||||
|
||||
#include <array>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mp11/tuple.hpp>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
#include <boost/unordered/detail/foa/rw_spinlock.hpp>
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
/* Cumulative one-pass calculation of the average, variance and deviation of
|
||||
* running sequences.
|
||||
*/
|
||||
|
||||
struct sequence_stats_data
|
||||
{
|
||||
double m=0.0;
|
||||
double m_prior=0.0;
|
||||
double s=0.0;
|
||||
};
|
||||
|
||||
struct welfords_algorithm /* 0-based */
|
||||
{
|
||||
template<typename T>
|
||||
int operator()(T&& x,sequence_stats_data& d)const noexcept
|
||||
{
|
||||
static_assert(
|
||||
noexcept(static_cast<double>(x)),
|
||||
"Argument conversion to double must not throw.");
|
||||
|
||||
d.m_prior=d.m;
|
||||
d.m+=(static_cast<double>(x)-d.m)/static_cast<double>(n);
|
||||
d.s+=(n!=1)*
|
||||
(static_cast<double>(x)-d.m_prior)*(static_cast<double>(x)-d.m);
|
||||
|
||||
return 0; /* mp11::tuple_transform requires that return type not be void */
|
||||
}
|
||||
|
||||
std::size_t n;
|
||||
};
|
||||
|
||||
struct sequence_stats_summary
|
||||
{
|
||||
double average;
|
||||
double variance;
|
||||
double deviation;
|
||||
};
|
||||
|
||||
/* Stats calculated jointly for N same-sized sequences to save the space
|
||||
* for count.
|
||||
*/
|
||||
|
||||
template<std::size_t N>
|
||||
class cumulative_stats
|
||||
{
|
||||
public:
|
||||
struct summary
|
||||
{
|
||||
std::size_t count;
|
||||
std::array<sequence_stats_summary,N> sequence_summary;
|
||||
};
|
||||
|
||||
void reset()noexcept{*this=cumulative_stats();}
|
||||
|
||||
template<typename... Ts>
|
||||
void add(Ts&&... xs)noexcept
|
||||
{
|
||||
static_assert(
|
||||
sizeof...(Ts)==N,"A sample must be provided for each sequence.");
|
||||
|
||||
if(BOOST_UNLIKELY(++n==0)){ /* wraparound */
|
||||
reset();
|
||||
n=1;
|
||||
}
|
||||
mp11::tuple_transform(
|
||||
welfords_algorithm{n},
|
||||
std::forward_as_tuple(std::forward<Ts>(xs)...),
|
||||
data);
|
||||
}
|
||||
|
||||
summary get_summary()const noexcept
|
||||
{
|
||||
summary res;
|
||||
res.count=n;
|
||||
for(std::size_t i=0;i<N;++i){
|
||||
double average=data[i].m,
|
||||
variance=n!=0?data[i].s/static_cast<double>(n):0.0, /* biased */
|
||||
deviation=std::sqrt(variance);
|
||||
res.sequence_summary[i]={average,variance,deviation};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t n=0;
|
||||
std::array<sequence_stats_data,N> data;
|
||||
};
|
||||
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
|
||||
template<std::size_t N>
|
||||
class concurrent_cumulative_stats:cumulative_stats<N>
|
||||
{
|
||||
using super=cumulative_stats<N>;
|
||||
using lock_guard=std::lock_guard<rw_spinlock>;
|
||||
|
||||
public:
|
||||
using summary=typename super::summary;
|
||||
|
||||
concurrent_cumulative_stats()noexcept:super{}{}
|
||||
concurrent_cumulative_stats(const concurrent_cumulative_stats& x)noexcept:
|
||||
concurrent_cumulative_stats{x,lock_guard{x.mut}}{}
|
||||
|
||||
concurrent_cumulative_stats&
|
||||
operator=(const concurrent_cumulative_stats& x)noexcept
|
||||
{
|
||||
auto x1=x;
|
||||
lock_guard lck{mut};
|
||||
static_cast<super&>(*this)=x1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset()noexcept
|
||||
{
|
||||
lock_guard lck{mut};
|
||||
super::reset();
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
void add(Ts&&... xs)noexcept
|
||||
{
|
||||
lock_guard lck{mut};
|
||||
super::add(std::forward<Ts>(xs)...);
|
||||
}
|
||||
|
||||
summary get_summary()const noexcept
|
||||
{
|
||||
lock_guard lck{mut};
|
||||
return super::get_summary();
|
||||
}
|
||||
|
||||
private:
|
||||
concurrent_cumulative_stats(const super& x,lock_guard&&):super{x}{}
|
||||
|
||||
mutable rw_spinlock mut;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template<std::size_t N>
|
||||
using concurrent_cumulative_stats=cumulative_stats<N>;
|
||||
|
||||
#endif
|
||||
|
||||
} /* namespace foa */
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user