24#include <boost/core/noncopyable.hpp>
74#define FLOW_UTIL_STAT_DECLARE(ARG_m_stat, ARG_stat_type) \
75 FLOW_UTIL_SEMICOLON_SAFE \
77 using Stat_type = ::flow::util::stat::Stat_type; \
78 using Member_ptr_type = decltype(&target_stats->ARG_m_stat); \
79 constexpr auto FLOW_UTIL_STAT_DECLARE_stat_type = Stat_type::S_##ARG_stat_type; \
80 static_assert(FLOW_UTIL_STAT_DECLARE_stat_type != Stat_type::S_HI_WMARK, \
81 "To declare HI_WMARK stat please use FLOW_UTIL_STAT_DECLARE_HI_WMARK()."); \
82 visitor(src_stats ? &src_stats->ARG_m_stat : nullptr, \
83 target_stats ? &target_stats->ARG_m_stat : nullptr, \
84 static_cast<Member_ptr_type>(nullptr), \
85 std::integral_constant<Stat_type, FLOW_UTIL_STAT_DECLARE_stat_type>{}, \
86 ::flow::util::stat::Stat_name{name_prefix, #ARG_m_stat, \
87 ::flow::util::stat::Stat_name::Fragment_kind::S_MEMBER_ID}); \
126#define FLOW_UTIL_STAT_DECLARE_HI_WMARK(ARG_m_stat, ARG_m_gauged_stat) \
127 FLOW_UTIL_SEMICOLON_SAFE \
129 using Stat_type = ::flow::util::stat::Stat_type; \
130 static_assert(std::is_same_v<decltype(&target_stats->ARG_m_stat), \
131 decltype(&target_stats->ARG_m_gauged_stat)>, \
132 "The HI_WMARK stat must be the same C++ type as the GAUGEd stat."); \
133 visitor(src_stats ? &src_stats->ARG_m_stat : nullptr, \
134 target_stats ? &target_stats->ARG_m_stat : nullptr, \
135 target_stats ? &target_stats->ARG_m_gauged_stat : nullptr, \
136 std::integral_constant<Stat_type, Stat_type::S_HI_WMARK>{}, \
137 ::flow::util::stat::Stat_name{name_prefix, #ARG_m_stat, \
138 ::flow::util::stat::Stat_name::Fragment_kind::S_MEMBER_ID}); \
155template<
typename Stat_set>
298 void append_to(std::string* target)
const;
314 std::string
str()
const;
338T
load(
const std::atomic<T>& val)
340 return val.load(std::memory_order_relaxed);
344void store(T* target_val,
const boost::type_identity_t<T>& val)
350void store(std::atomic<T>* target_val, boost::type_identity_t<T> val)
352 target_val->store(val, std::memory_order_relaxed);
357 const boost::type_identity_t<T>& addend_val)
359 *target_val += addend_val;
363T
fetch_add(std::atomic<T>* target_val, boost::type_identity_t<T> addend_val)
365 return target_val->fetch_add(addend_val, std::memory_order_relaxed);
370 const boost::type_identity_t<T>& subtrahend_val)
372 *target_val -= subtrahend_val;
376T
fetch_sub(std::atomic<T>* target_val, boost::type_identity_t<T> subtrahend_val)
378 return target_val->fetch_sub(subtrahend_val, std::memory_order_relaxed);
382T
exchange(std::atomic<T>* target_val, boost::type_identity_t<T> val)
384 return target_val->exchange(val, std::memory_order_relaxed);
390 if (*target_val < val)
399 T cur =
load(*target_val);
401 && (!target_val->compare_exchange_weak(cur, val, std::memory_order_relaxed, std::memory_order_relaxed)))
408void reset(T* target_val,
const T& fresh_val)
413template<
typename Stat_set>
417 declare_stats(
"", &stats,
nullptr,
418 [&](
const auto* val_ptr,
auto&&,
auto&&,
auto&&,
const Stat_name& name)
420 const auto& val = *val_ptr;
430 os <<
"=[" <<
load(val) <<
']';
435template<
typename Stat_set>
441template<
typename Stat_set,
typename... Ctor_args>
447 vector<string> names;
449 const Stat_set dummy(std::forward<Ctor_args>(ctor_args)...);
450 declare_stats(
"", &dummy,
nullptr,
451 [&](
auto&&,
auto&&,
auto&&,
auto&&,
const Stat_name& name)
453 names.emplace_back(name.
str());
459template<
typename Stat_set>
466template<
typename Stat_set>
467void stats_reset(Stat_set* target_stats,
const Stat_set& fresh_stats)
469 declare_stats(
"", &fresh_stats, target_stats,
470 [&]([[maybe_unused]]
const auto* fresh_val_ptr, [[maybe_unused]]
auto* target_val,
471 [[maybe_unused]]
const auto* hi_wmark_gauged_target_val_or_null,
auto stat_type_tag,
auto&&)
473 constexpr auto stat_type =
decltype(stat_type_tag)::value;
482 reset(target_val, *fresh_val_ptr);
490 store(target_val,
load(*hi_wmark_gauged_target_val_or_null));
495template<
typename Stat_set>
498 declare_stats(
"", &src_stats, target_stats,
499 [&](
const auto* src_val_ptr,
auto* target_val,
auto&&,
auto&&,
auto&&)
507template<
typename Stat_set>
510 declare_stats(
"", &src_stats, target_stats,
511 [&](
const auto* src_val_ptr,
auto* target_val,
auto&&,
auto stat_type_tag,
auto&&)
513 constexpr auto stat_type =
decltype(stat_type_tag)::value;
514 const auto& src_val = *src_val_ptr;
529template<
typename Stat_set,
typename It>
530void stats_aggregate(Stat_set* target_stats,
const It& src_stats_begin,
const It& src_stats_end)
532 assert((src_stats_begin != src_stats_end) &&
"Must aggregate at least 1 thing.");
535 auto src_stats_it = src_stats_begin;
538 for (++src_stats_it; src_stats_it != src_stats_end; ++src_stats_it)
544 declare_stats(
"",
nullptr, target_stats,
545 [&](
auto&&, [[maybe_unused]]
auto* target_val,
auto&&,
auto stat_type_tag,
auto&&)
549 auto scaled_val =
load(*target_val);
552 store(target_val, scaled_val);
558template<
typename Stat_set,
typename It>
559void stats_sum(Stat_set* target_stats,
const It& src_stats_begin,
const It& src_stats_end)
561 assert((src_stats_begin != src_stats_end) &&
"Must sum at least 1 thing.");
564 auto src_stats_it = src_stats_begin;
566 for (++src_stats_it; src_stats_it != src_stats_end; ++src_stats_it)
568 declare_stats(
"", &*src_stats_it, target_stats,
569 [&](
const auto* src_val_ptr,
auto* target_val,
auto&&,
auto&&,
auto&&)
576template<
typename Stat_set,
typename It>
578 const Stat_set* fresh_stats_from_0_shards)
580 const bool empty_range = src_stats_begin == src_stats_end;
581 assert(((!empty_range) || fresh_stats_from_0_shards) &&
"Must provide a fresh_stats if no input-shards.");
609 declare_stats(
"", fresh_stats_from_0_shards, target_stats,
610 [&]([[maybe_unused]]
const auto* fresh_val_ptr, [[maybe_unused]]
auto* target_val,
611 auto&&,
auto stat_type_tag,
auto&&)
613 constexpr auto stat_type =
decltype(stat_type_tag)::value;
616 reset(target_val, *fresh_val_ptr);
626 auto src_stats_it = src_stats_begin;
627 declare_stats(
"", &*src_stats_it, target_stats,
628 [&]([[maybe_unused]]
const auto* src_val_ptr, [[maybe_unused]]
auto* target_val,
auto&&,
629 auto stat_type_tag,
auto&&)
631 constexpr auto stat_type =
decltype(stat_type_tag)::value;
647 for (++src_stats_it; src_stats_it != src_stats_end; ++src_stats_it)
649 declare_stats(
"", &*src_stats_it, target_stats,
650 [&]([[maybe_unused]]
const auto* src_val_ptr, [[maybe_unused]]
auto* target_val,
auto&&,
651 auto stat_type_tag,
auto&&)
653 constexpr auto stat_type =
decltype(stat_type_tag)::value;
669 declare_stats(
"",
nullptr, target_stats,
670 [&](
auto&&, [[maybe_unused]]
auto* target_val,
671 [[maybe_unused]]
const auto* hi_wmark_gauged_target_val_or_null,
auto stat_type_tag,
auto&&)
680template<
typename Stat_set,
typename It>
682 const Stat_set& fresh_stats_from_0_shards)
684 const bool empty_range = src_stats_begin == src_stats_end;
721 declare_stats(
"", &fresh_stats_from_0_shards, target_stats,
722 [&]([[maybe_unused]]
const auto* fresh_val_ptr, [[maybe_unused]]
auto* target_val,
auto&&,
723 auto stat_type_tag,
auto&&)
727 reset(target_val, *fresh_val_ptr);
739 auto src_stats_it = src_stats_begin;
741 const auto reset_shard_accs = [&]()
743 declare_stats(
"", &fresh_stats_from_0_shards, &*src_stats_it,
744 [&]([[maybe_unused]]
const auto* fresh_val_ptr, [[maybe_unused]]
auto* target_shard_val,
auto&&,
745 auto stat_type_tag,
auto&&)
749 reset(target_shard_val, *fresh_val_ptr);
755 declare_stats(
"", &*src_stats_it, target_stats,
756 [&]([[maybe_unused]]
const auto* src_val_ptr, [[maybe_unused]]
auto* target_val,
auto&&,
757 auto stat_type_tag,
auto&&)
767 for (++src_stats_it; src_stats_it != src_stats_end; ++src_stats_it)
769 declare_stats(
"", &*src_stats_it, target_stats,
770 [&]([[maybe_unused]]
const auto* src_val_ptr, [[maybe_unused]]
auto* target_val,
auto&&,
771 auto stat_type_tag,
auto&&)
783 declare_stats(
"",
nullptr, target_stats,
784 [&](
auto&&, [[maybe_unused]]
auto* target_val,
785 [[maybe_unused]]
const auto* hi_wmark_gauged_target_val_or_null,
auto stat_type_tag,
auto&&)
789 store(target_val,
load(*hi_wmark_gauged_target_val_or_null));
794template<
typename Stat_set>
797 declare_stats(
"", reset_state, target_stats,
798 [&]([[maybe_unused]]
const auto* reset_val_ptr, [[maybe_unused]]
auto* target_val,
799 [[maybe_unused]]
const auto* hi_wmark_gauged_target_val_or_null,
auto stat_type_tag,
auto&&)
801 constexpr auto stat_type =
decltype(stat_type_tag)::value;
802 const auto& reset_val = *reset_val_ptr;
828 const auto new_gauge =
load(*hi_wmark_gauged_target_val_or_null);
829 const auto cur_hwm =
load(reset_val);
831 store(target_val, (new_gauge < cur_hwm) ? cur_hwm
841 declare_stats(
"", target_stats, reset_state,
842 [&]([[maybe_unused]]
const auto* target_val, [[maybe_unused]]
auto* reset_val,
843 auto&&,
auto stat_type_tag,
auto&&)
852template<
typename Stat_set>
858 declare_stats(
"",
nullptr, target_stats,
859 [&](
auto&&, [[maybe_unused]]
auto* target_val,
860 [[maybe_unused]]
const auto* hi_wmark_gauged_target_val_or_null,
auto stat_type_tag,
auto&&)
864 store(target_val,
load(*hi_wmark_gauged_target_val_or_null));
Specialized class that (at a light weight) represents a printable Stat_set-member name,...
Stat_name(String_view fragment={})
Constructs a Stat_name that represents only a name fragment with no reference to another Stat_name.
void to_ostream(std::ostream &os) const
On-demand evaluation: os << this->str() but faster.
const String_view m_fragment
Second part, if any, of the concatenation in str(), interpreted according to m_fragment_kind.
std::string str() const
On-demand evaluation: Returns the full name – all fragments, from the root on, each rendered per its ...
const Fragment_kind m_fragment_kind
How to render m_fragment.
void append_to(std::string *target) const
On-demand evaluation: *target += this->str() but faster.
const Stat_name *const m_base
First part, if any, of the concatenation in str().
Fragment_kind
How a fragment of text is rendered into the name.
@ S_LITERAL
The fragment is rendered verbatim.
Sub-module of flow::util providing lightweight facilities for working with simple structs of stat cou...
void stats_mark_reset_state(Stat_set *target_stats)
Sets each HI_WMARK-declared stat-member in *target_stats to its gauged-stat's current value in *targe...
@ S_HI_WMARK
Value of the same type as a specific other value stats.m_v in the same Stat_set with Stat_type S_GAUG...
@ S_GAUGE
Value (often numeric) that represents the state of something at some point in time.
@ S_ACCUMULATOR
Value (typically numeric, or conceptually a collection of numerics) that counts/tallies (typically vi...
void fetch_sub(T *target_val, const boost::type_identity_t< T > &subtrahend_val)
Default fetch_sub(&target_stats.m_val, _val) that simply applies *target_val -= subtrahend_val.
void stats_aggregate_shards(Stat_set *target_stats, const It &src_stats_begin, const It &src_stats_end, const Stat_set *fresh_stats_from_0_shards)
Sharded-stats consumption: Aggregates N source Stat_sets, interpreted as shards of the aggregated who...
void update_hi_wmark(T *target_val, const boost::type_identity_t< T > &val)
Default update_hi_wmark(&target_stats.m_val, val) that updates *target_val to val if and only if the ...
void stats_sum(Stat_set *target_stats, const It &src_stats_begin, const It &src_stats_end)
Equivalent to stats_aggregate() as-if every stat, regardless of its actual stat::Stat_type,...
void stats_aggregate_one(Stat_set *target_stats, const Stat_set &src_stats)
Aggregates the values from src_stats into *target_stats, in-place.
const T & load(const T &val)
Default load(stats.m_val) that simply return stats.m_val.
void stats_assign(Stat_set *target_stats, const Stat_set &src_stats)
Given a source Stat_set, makes the target Stat_set equal to the former.
void reset(Histogram_counter *target_val, const Histogram_counter &)
Executes target_val->clear(), where *target_val is a Histogram_counter.
void stats_reset_shard_aggregate(Stat_set *target_stats, const It &src_stats_begin, const It &src_stats_end, const Stat_set &fresh_stats_from_0_shards)
Reset-stats companion to stats_aggregate_shards(); together the two functions provide support for the...
void fetch_add(T *target_val, const boost::type_identity_t< T > &addend_val)
Default fetch_add(&target_stats.m_val, addend_val) that simply applies *target_val += addend_val.
void stats_since_reset_state(Stat_set *target_stats, Stat_set *reset_state)
Intended for situations where the source of stat readings – including ACCUMULATORs and not just GAUGE...
void stats_aggregate(Stat_set *target_stats, const It &src_stats_begin, const It &src_stats_end)
Aggregates N source Stat_sets – drawn from the iterator range [src_stats_begin, src_stats_end) – into...
std::vector< std::string > stats_field_names(Ctor_args &&... ctor_args)
Returns the names of all declared stats of the given Stat_set type, in declaration order: the same na...
T exchange(std::atomic< T > *target_val, boost::type_identity_t< T > val)
Equivalent to target_val->exchange(val, memory_order_relaxed); sets *target_val to val and returns th...
std::ostream & operator<<(std::ostream &os, const Histogram_counter &val)
Prints string representation of the given Histogram_counter to the given ostream.
void stats_to_ostream(std::ostream &os, const Stat_set &stats)
Outputs a human-readable representation of all declared stats in stats to the given ostream.
void stats_reset(Stat_set *target_stats, const Stat_set &fresh_stats)
With the help of a freshly-initialized Stat_set, resets the target Stat_set so as to immediately begi...
Stat_set_printable< Stat_set > print(const Stat_set &stats)
Returns a lightweight proxy object that, when streamed via operator<<, pretty-prints the given Stat_s...
void store(T *target_val, const boost::type_identity_t< T > &val)
Default store(&target_stats.m_val, val) that simply assigns *target_val = val.
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
Thin proxy wrapping a const reference to a Stat_set, enabling ostream << stat::print(my_stats) syntax...
const Stat_set & m_stats
The referenced stat set.