DiSMEC++
dismec::stats::StatisticsCollection Class Reference

This class manages a collection of named Statistics objects. More...

#include <collection.h>

Public Member Functions

void declare_stat (stat_id_t index, StatisticMetaData meta)
 Declares a new statistics. Defines the corresponding index and name. More...
 
void declare_tag (tag_id_t index, std::string name)
 Declares a new tag value. More...
 
void register_stat (const std::string &name, std::unique_ptr< Statistics > stat)
 Registers a Statistics object to the named slot. More...
 
const std::vector< StatisticMetaData > & get_statistics_meta () const
 Gets a vector with the declarations for all statistics. More...
 
const Statisticsget_stat (const std::string &name) const
 Returns the Statistics object corresponding to the slot name. More...
 
TagContainer get_tag_by_name (const std::string &name) const
 Gets the tag with the given name. More...
 
const std::vector< TagContainer > & get_all_tags () const
 Gets a vector which contains all the tags owned by this collection. More...
 
void provide_tags (const StatisticsCollection &other)
 Registers all the tags of the other collection as read-only tags in this collection. More...
 
void enable (stat_id_t stat)
 Explicitly enable the collection of statistics for the given index. More...
 
void disable (stat_id_t stat)
 Explicitly disable the collection of statistics for the given index. More...
 
bool is_enabled (stat_id_t stat) const
 Quickly checks whether collection of data is enabled for the given statistics. More...
 
void enable (const std::string &stat)
 Enables collecting data based on the name of a statistics. More...
 
void disable (const std::string &stat)
 Disables collecting data based on the name of a statistics. More...
 
bool has_stat (const std::string &name) const
 Returns whether a stat with the given name is declared. More...
 
bool is_enabled_by_name (const std::string &name) const
 Checks whether gathering data is enabled based on the statistic's name. More...
 
template<class T , std::enable_if_t<!std::is_invocable_v< T >, bool > = true>
void record (stat_id_t stat, T &&value)
 Records an already computed value. More...
 
template<class F , std::enable_if_t< std::is_invocable_v< F >, bool > = true>
void record (stat_id_t stat, F &&callable)
 Records a value that is computed only when needed. More...
 
void set_tag (tag_id_t tag, int value)
 Sets the tag to the given integer value. More...
 

Private Member Functions

template<class T >
void do_record (int index, T &&value)
 

Private Attributes

std::vector< bool > m_Enabled
 
std::vector< StatisticMetaDatam_MetaData
 
std::vector< std::unique_ptr< Statistics > > m_Statistics
 
std::vector< TagContainerm_TagValues
 
std::unordered_map< std::string, TagContainerm_TagLookup
 

Detailed Description

This class manages a collection of named Statistics objects.

The functionality of this class is designed to be performance efficient, but nonetheless it should not be used in the inner loops. It is further designed so that statistics collection can be disabled at runtime, in which case the performance impact should be almost negligible.

This is achieved by assigning each named statistics also an integer id, which is used in the performance critical code path, which consists of the is_enabled() and record() functions. The check whether a particular statistics shall be collected is performed by is_enabled(), which is a simple lookup in a boolean vector, and defined in the header so that it can be inlined. The record() functions first check if the statistics is enabled, and if not no further action is performed. They are also defined in the header, so this check will get inlined too. In all, if statistics are disabled, each call to record should boil down to an inlined access to a boolean vector. For anything but the innermost loops, this should be fast enough.

The actual gathering of the statistics requires an additional vector lookup, followed by a virtual function call into the actual statistics implementation. This should also not impose too much of a performance problem in most cases. A different situation arises if the statistics we want to gather is not calculated as part of the regular computations, and is expensive to calculate. For that purpose, there exists an overload of record() that takes a callable as an argument, which is evaluated only if the statistics is enabled.

Attention
The definition of the statistics integral identifiers is the responsibility of the user of this class. Since they only have to be unique with respect to a single StatisticsCollection, my strategy is to define the ids as constants at the beginning of the implementation file which uses the collection.

For extracting the statistics, no knowledge of the ids is required. This is because we consider that process to be non-performance-critical, and as such we can perform lookups based on the statistic's name. This means that often that the IDs can be considered an implementation detail of the code that records the statistics, which can be hidden from consumer code.

Definition at line 47 of file collection.h.

Member Function Documentation

◆ declare_stat()

void StatisticsCollection::declare_stat ( stat_id_t  index,
StatisticMetaData  meta 
)

Declares a new statistics. Defines the corresponding index and name.

The new statistics is disabled by default, and no Statistics object that gathers its values is associated. This can be changed by calling register_stat(). The indices and names need to be unique.

Parameters
indexIndex of the new statistics.
metaMetadata of the new statistics.
Note
A current limitation of the implementation is that it assumes that statistics are declared in order of their ids, which are assumed to be contiguous.
Exceptions
std::invalid_argumentIf a stat with the same name or id already has been declared.

Definition at line 40 of file collection.cpp.

References m_Enabled, m_MetaData, m_Statistics, dismec::stats::StatisticMetaData::Name, dismec::ssize(), and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by TEST_CASE().

◆ declare_tag()

void StatisticsCollection::declare_tag ( tag_id_t  index,
std::string  name 
)

Declares a new tag value.

Parameters
indexThe unique index to be used for the tag.
nameThe unique name to be used for the tag.

Definition at line 87 of file collection.cpp.

References dismec::stats::TagContainer::create_full_container(), m_TagLookup, m_TagValues, dismec::ssize(), and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by TEST_CASE().

◆ disable() [1/2]

void StatisticsCollection::disable ( const std::string &  stat)

Disables collecting data based on the name of a statistics.

Exceptions
std::invalid_argumentif not such stat exists.

Definition at line 36 of file collection.cpp.

References disable(), m_MetaData, and anonymous_namespace{collection.cpp}::str_to_id().

◆ disable() [2/2]

void StatisticsCollection::disable ( stats::stat_id_t  stat)

Explicitly disable the collection of statistics for the given index.

See also
enable(), is_enabled()

Definition at line 18 of file collection.cpp.

References m_Enabled, and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by disable(), register_stat(), and TEST_CASE().

◆ do_record()

template<class T >
void dismec::stats::StatisticsCollection::do_record ( int  index,
T &&  value 
)
inlineprivate

Definition at line 220 of file collection.h.

References m_Statistics.

Referenced by record().

◆ enable() [1/2]

void StatisticsCollection::enable ( const std::string &  stat)

Enables collecting data based on the name of a statistics.

Exceptions
std::invalid_argumentif not such stat exists.

Definition at line 32 of file collection.cpp.

References enable(), m_MetaData, and anonymous_namespace{collection.cpp}::str_to_id().

◆ enable() [2/2]

void StatisticsCollection::enable ( stat_id_t  stat)

Explicitly enable the collection of statistics for the given index.

Collection of data can only be enabled for statistics for which a corresponding Statistics object has been provided using register_stat().

Exceptions
std::logic_errorIf you try to enable collection of a statistic without a registered Statistics object.
See also
disable(), is_enabled()

Definition at line 12 of file collection.cpp.

References m_Enabled, m_Statistics, and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by enable(), register_stat(), and TEST_CASE().

◆ get_all_tags()

const std::vector<TagContainer>& dismec::stats::StatisticsCollection::get_all_tags ( ) const
inline

Gets a vector which contains all the tags owned by this collection.

Definition at line 101 of file collection.h.

References m_TagValues.

Referenced by TEST_CASE().

◆ get_stat()

const Statistics & StatisticsCollection::get_stat ( const std::string &  name) const

Returns the Statistics object corresponding to the slot name.

Exceptions
std::invalid_argumentif name has not been declared, or has no assigned Statistics object.

Definition at line 75 of file collection.cpp.

References m_MetaData, m_Statistics, and anonymous_namespace{collection.cpp}::str_to_id().

Referenced by TEST_CASE().

◆ get_statistics_meta()

const std::vector<StatisticMetaData>& dismec::stats::StatisticsCollection::get_statistics_meta ( ) const
inline

Gets a vector with the declarations for all statistics.

Definition at line 82 of file collection.h.

References m_MetaData.

Referenced by TEST_CASE().

◆ get_tag_by_name()

TagContainer StatisticsCollection::get_tag_by_name ( const std::string &  name) const

Gets the tag with the given name.

Returns a TagContainer whose value is a pointer to the interval value stored in this collection. Thus, any Statistics object that needs a tag can lookup the tag by using the name in its setup phase, and then during recording only needs to use the TagContainer to get the current value, which is much faster.

Exceptions
std::out_of_rangeif name has neither been declared nor provided by another collection.

Definition at line 105 of file collection.cpp.

References m_TagLookup.

Referenced by dismec::stats::TaggedStat::setup(), and TEST_CASE().

◆ has_stat()

bool StatisticsCollection::has_stat ( const std::string &  name) const

Returns whether a stat with the given name is declared.

Definition at line 122 of file collection.cpp.

References m_MetaData.

Referenced by TEST_CASE().

◆ is_enabled()

bool dismec::stats::StatisticsCollection::is_enabled ( stat_id_t  stat) const
inline

Quickly checks whether collection of data is enabled for the given statistics.

This function is defined in the header so it can be inlined.

Parameters
statThe id of the statistics for which the check if performed.
See also
enable(), disable()

Definition at line 131 of file collection.h.

References m_Enabled, and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by dismec::stats::ScopeTimer::is_enabled(), is_enabled_by_name(), record(), and TEST_CASE().

◆ is_enabled_by_name()

bool StatisticsCollection::is_enabled_by_name ( const std::string &  name) const

Checks whether gathering data is enabled based on the statistic's name.

Because this function has to perform the lookup for the name, it is much slower than is_enabled(). Therefore, even though it performs the exact same function, it has not been provided an overload, but given an extra, longer name to prevent accidental performance problems.

Definition at line 83 of file collection.cpp.

References is_enabled(), m_MetaData, and anonymous_namespace{collection.cpp}::str_to_id().

Referenced by TEST_CASE().

◆ provide_tags()

void StatisticsCollection::provide_tags ( const StatisticsCollection other)

Registers all the tags of the other collection as read-only tags in this collection.

Read-only tags can be accessed by get_tag_by_name(), so that statistics can use them in their setup, but cannot be modified by set_tag(). They don't even have an associated tag_id inside this collection.

Definition at line 109 of file collection.cpp.

References m_TagLookup.

Referenced by TEST_CASE().

◆ record() [1/2]

template<class F , std::enable_if_t< std::is_invocable_v< F >, bool > = true>
void dismec::stats::StatisticsCollection::record ( stat_id_t  stat,
F &&  callable 
)
inline

Records a value that is computed only when needed.

Template Parameters
FA callable type. Will typically be the type of same lambda.
Parameters
statThe id of the stat to be recorded.
callableA callable that produces a value that is compatible with Statistics::record(). Will only be called if the statistics has been enabled.

A typical usage example would look like this

collection.record(id, [&](){ return expensive_function(intermediate); });

Here, intermediate is a value that is calculated as part of the regular program flow, but for recording statistics we need expensive_function(intermediate). The invocation of the callable itself is wrapped into an immediately invoked lambda annotated as cold, so that the expensive calculation will not get inlined into the main program flow and slow down the code path when the statistics is disabled.

See also
Statistics::record().

Definition at line 198 of file collection.h.

References dismec::l2_reg_sq_hinge_detail::__attribute__(), do_record(), is_enabled(), and dismec::opaque_int_type< Tag, T >::to_index().

◆ record() [2/2]

template<class T , std::enable_if_t<!std::is_invocable_v< T >, bool > = true>
void dismec::stats::StatisticsCollection::record ( stat_id_t  stat,
T &&  value 
)
inline

Records an already computed value.

Template Parameters
TThe type of the recorded value. Needs to be compatible with Statistics::record().
Parameters
statThe id of the stat for which the value is recorded.
valueThe actual data.
See also
Statistics::record()

Definition at line 174 of file collection.h.

References do_record(), is_enabled(), and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by dismec::stats::ScopeTimer::record_duration(), and TEST_CASE().

◆ register_stat()

void StatisticsCollection::register_stat ( const std::string &  name,
std::unique_ptr< Statistics stat 
)

Registers a Statistics object to the named slot.

This function can also be used to unregister a Statistics by providing nullptr as the second argument. In that case, the statistics is automatically disabled, otherwise it is enabled.

Parameters
nameName for which stat should be registered.
statThe Statistics object to register.
Exceptions
std::invalid_argumentIf no slot name has been declared, or if there already is a registered stat for the slot and stat is not nullptr.

Definition at line 59 of file collection.cpp.

References disable(), enable(), m_MetaData, m_Statistics, and anonymous_namespace{collection.cpp}::str_to_id().

Referenced by TEST_CASE().

◆ set_tag()

void dismec::stats::StatisticsCollection::set_tag ( tag_id_t  tag,
int  value 
)
inline

Sets the tag to the given integer value.

Definition at line 209 of file collection.h.

References m_TagValues, and dismec::opaque_int_type< Tag, T >::to_index().

Referenced by dismec::stats::Tracked::set_tag(), and TEST_CASE().

Member Data Documentation

◆ m_Enabled

std::vector<bool> dismec::stats::StatisticsCollection::m_Enabled
private

◆ m_MetaData

std::vector<StatisticMetaData> dismec::stats::StatisticsCollection::m_MetaData
private

◆ m_Statistics

std::vector<std::unique_ptr<Statistics> > dismec::stats::StatisticsCollection::m_Statistics
private

Definition at line 226 of file collection.h.

Referenced by declare_stat(), do_record(), enable(), get_stat(), and register_stat().

◆ m_TagLookup

std::unordered_map<std::string, TagContainer> dismec::stats::StatisticsCollection::m_TagLookup
private

Definition at line 229 of file collection.h.

Referenced by declare_tag(), get_tag_by_name(), and provide_tags().

◆ m_TagValues

std::vector<TagContainer> dismec::stats::StatisticsCollection::m_TagValues
private

Definition at line 228 of file collection.h.

Referenced by declare_tag(), get_all_tags(), and set_tag().


The documentation for this class was generated from the following files: