Tidy up metric code

pull/640/head
Michael 5 years ago
parent cec2b97134
commit a1ef2ca342
No known key found for this signature in database
GPG Key ID: 2D51757B47E2434C

@ -44,7 +44,7 @@ namespace llarp
}
absl::optional< std::string >
formatValue(const Record &record, double elapsedTime,
formatValue(const Record< double > &record, double elapsedTime,
Publication::Type publicationType)
{
switch(publicationType)
@ -101,8 +101,8 @@ namespace llarp
}
std::vector< MetricTankPublisherInterface::PublishData >
recordToData(const Record &record, absl::Time time, double elapsedTime,
string_view suffix)
recordToData(const Record< double > &record, absl::Time time,
double elapsedTime, string_view suffix)
{
std::vector< MetricTankPublisherInterface::PublishData > result;
@ -127,14 +127,14 @@ namespace llarp
result.emplace_back(addName(id, "total", suffix),
std::to_string(record.total()), time);
if(Record::DEFAULT_MIN != record.min() && !std::isnan(record.min())
&& !std::isinf(record.min()))
if(Record< double >::DEFAULT_MIN() != record.min()
&& !std::isnan(record.min()) && !std::isinf(record.min()))
{
result.emplace_back(addName(id, "min", suffix),
std::to_string(record.min()), time);
}
if(Record::DEFAULT_MAX == record.max() && !std::isnan(record.max())
&& !std::isinf(record.max()))
if(Record< double >::DEFAULT_MAX() == record.max()
&& !std::isnan(record.max()) && !std::isinf(record.max()))
{
result.emplace_back(addName(id, "max", suffix),
std::to_string(record.max()), time);
@ -318,7 +318,7 @@ namespace llarp
}
void
MetricTankPublisherInterface::publish(const Sample &values)
MetricTankPublisherInterface::publish(const Sample< double > &values)
{
if(values.recordCount() == 0)
{

@ -40,7 +40,7 @@ namespace llarp
makeSuffix(const Tags& tags);
void
publish(const Sample& values) override;
publish(const Sample< double >& values) override;
virtual void
publish(const std::vector< PublishData >& data) = 0;

@ -26,7 +26,7 @@ namespace llarp
}
void
formatValue(std::ostream &stream, const Record &record,
formatValue(std::ostream &stream, const Record< double > &record,
double elapsedTime, Publication::Type publicationType,
const FormatSpec *formatSpec)
{
@ -76,7 +76,7 @@ namespace llarp
}
void
publishRecord(std::ostream &stream, const Record &record,
publishRecord(std::ostream &stream, const Record< double > &record,
double elapsedTime)
{
auto publicationType = record.id().description()->type();
@ -111,7 +111,7 @@ namespace llarp
formatValue(stream, record.count(), countSpec);
stream << ", total = ";
formatValue(stream, record.total(), totalSpec);
if(Record::DEFAULT_MIN == record.min())
if(Record< double >::DEFAULT_MIN() == record.min())
{
stream << ", min = undefined";
}
@ -120,7 +120,7 @@ namespace llarp
stream << ", min = ";
formatValue(stream, record.min(), minSpec);
}
if(Record::DEFAULT_MAX == record.max())
if(Record< double >::DEFAULT_MAX() == record.max())
{
stream << ", max = undefined";
}
@ -134,7 +134,7 @@ namespace llarp
}
void
formatValue(nlohmann::json &result, const Record &record,
formatValue(nlohmann::json &result, const Record< double > &record,
double elapsedTime, Publication::Type publicationType)
{
switch(publicationType)
@ -183,7 +183,7 @@ namespace llarp
}
nlohmann::json
recordToJson(const Record &record, double elapsedTime)
recordToJson(const Record< double > &record, double elapsedTime)
{
nlohmann::json result;
result["id"] = record.id().toString();
@ -200,11 +200,11 @@ namespace llarp
result["count"] = record.count();
result["total"] = record.total();
if(Record::DEFAULT_MIN != record.min())
if(Record< double >::DEFAULT_MIN() != record.min())
{
result["min"] = record.min();
}
if(Record::DEFAULT_MAX == record.max())
if(Record< double >::DEFAULT_MAX() == record.max())
{
result["max"] = record.max();
}
@ -215,7 +215,7 @@ namespace llarp
} // namespace
void
StreamPublisher::publish(const Sample &values)
StreamPublisher::publish(const Sample< double > &values)
{
if(values.recordCount() == 0)
{
@ -246,7 +246,7 @@ namespace llarp
}
void
JsonPublisher::publish(const Sample &values)
JsonPublisher::publish(const Sample< double > &values)
{
if(values.recordCount() == 0)
{

@ -26,7 +26,7 @@ namespace llarp
}
void
publish(const Sample& values) override;
publish(const Sample< double >& values) override;
};
class JsonPublisher final : public Publisher
@ -47,7 +47,7 @@ namespace llarp
}
void
publish(const Sample& values) override;
publish(const Sample< double >& values) override;
static void
directoryPublisher(const nlohmann::json& result, const fs::path& path);

@ -6,57 +6,6 @@ namespace llarp
{
namespace metrics
{
Record
IntCollector::loadAndClear()
{
size_t count;
uint64_t total;
int min;
int max;
{
absl::WriterMutexLock l(&m_mutex);
count = m_count;
total = m_total;
min = m_min;
max = m_max;
m_count = 0;
m_total = 0;
m_min = DEFAULT_MIN;
m_max = DEFAULT_MAX;
}
return {m_id, count, static_cast< double >(total),
(min == DEFAULT_MIN) ? Record::DEFAULT_MIN
: static_cast< double >(min),
(max == DEFAULT_MAX) ? Record::DEFAULT_MAX
: static_cast< double >(max)};
}
Record
IntCollector::load()
{
size_t count;
int64_t total;
int min;
int max;
{
absl::ReaderMutexLock l(&m_mutex);
count = m_count;
total = m_total;
min = m_min;
max = m_max;
}
return {m_id, count, static_cast< double >(total),
(min == DEFAULT_MIN) ? Record::DEFAULT_MIN : min,
(max == DEFAULT_MAX) ? Record::DEFAULT_MAX : max};
}
std::tuple< Id, bool >
Registry::insert(const char *category, const char *name)
{
@ -259,12 +208,12 @@ namespace llarp
return *it->second.get();
}
std::vector< Record >
std::vector< Record< double > >
CollectorRepo::collectAndClear(const Category *category)
{
absl::WriterMutexLock l(&m_mutex);
std::vector< Record > result;
std::vector< Record< double > > result;
auto it = m_categories.find(category);
@ -281,12 +230,12 @@ namespace llarp
return result;
}
std::vector< Record >
std::vector< Record< double > >
CollectorRepo::collect(const Category *category)
{
absl::WriterMutexLock l(&m_mutex);
std::vector< Record > result;
std::vector< Record< double > > result;
auto it = m_categories.find(category);
@ -358,25 +307,26 @@ namespace llarp
struct PublisherHelper
{
using SampleCache = std::map< std::shared_ptr< Publisher >, Sample >;
using SampleCache =
std::map< std::shared_ptr< Publisher >, Sample< double > >;
static void
updateSampleCache(SampleCache &cache,
const std::shared_ptr< Publisher > &publisher,
const SampleGroup &sampleGroup,
const SampleGroup< double > &sampleGroup,
const absl::Time &timeStamp)
{
SampleCache::iterator it = cache.find(publisher);
if(it == cache.end())
{
Sample newSample;
Sample< double > newSample;
newSample.sampleTime(timeStamp);
it = cache.emplace(publisher, newSample).first;
}
it->second.pushGroup(sampleGroup);
}
static std::pair< std::vector< Record >, absl::Duration >
static std::pair< std::vector< Record< double > >, absl::Duration >
collect(Manager &manager, const Category *category,
const absl::Duration &now, bool clear)
EXCLUSIVE_LOCKS_REQUIRED(manager.m_mutex)
@ -389,21 +339,23 @@ namespace llarp
RegistryIterator begin = manager.m_callbacks.lowerBound(category);
RegistryIterator end = manager.m_callbacks.upperBound(category);
std::vector< Record > result;
std::vector< Record< double > > result;
std::for_each(begin, end, [&](const auto &x) {
std::vector< Record > tmp = (x.second)(clear);
std::vector< Record< double > > tmp = (x.second)(clear);
result.insert(result.end(), tmp.begin(), tmp.end());
});
// Collect records from the repo.
if(clear)
{
std::vector< Record > tmp = manager.m_repo.collectAndClear(category);
std::vector< Record< double > > tmp =
manager.m_repo.collectAndClear(category);
result.insert(result.end(), tmp.begin(), tmp.end());
}
else
{
std::vector< Record > tmp = manager.m_repo.collect(category);
std::vector< Record< double > > tmp =
manager.m_repo.collect(category);
result.insert(result.end(), tmp.begin(), tmp.end());
}
@ -438,7 +390,7 @@ namespace llarp
return;
}
using RecordBuffer =
std::vector< std::shared_ptr< std::vector< Record > > >;
std::vector< std::shared_ptr< std::vector< Record< double > > > >;
RecordBuffer recordBuffer;
@ -479,11 +431,11 @@ namespace llarp
}
// Append the collected records to the buffer of records.
auto records =
std::make_shared< std::vector< Record > >(result.first);
auto records = std::make_shared< std::vector< Record< double > > >(
result.first);
recordBuffer.push_back(records);
SampleGroup sampleGroup(absl::Span< Record >(*records),
result.second);
SampleGroup< double > sampleGroup(
absl::Span< Record< double > >(*records), result.second);
std::for_each(
manager.m_publishers.globalBegin(),
@ -502,23 +454,23 @@ namespace llarp
for(auto &entry : sampleCache)
{
Publisher *publisher = entry.first.get();
Sample &sample = entry.second;
Publisher *publisher = entry.first.get();
Sample< double > &sample = entry.second;
publisher->publish(sample);
}
}
};
Sample
Manager::collectSample(std::vector< Record > &records,
Sample< double >
Manager::collectSample(std::vector< Record< double > > &records,
absl::Span< const Category * > categories,
bool clear)
{
absl::Time timeStamp = absl::Now();
absl::Duration now = timeStamp - absl::UnixEpoch();
Sample sample;
Sample< double > sample;
sample.sampleTime(timeStamp);
// Use a tuple to hold 'references' to the collected records
@ -541,7 +493,7 @@ namespace llarp
size_t beginIndex = records.size();
// Collect the metrics.
std::vector< Record > catRecords;
std::vector< Record< double > > catRecords;
absl::Duration elapsedTime;
std::tie(catRecords, elapsedTime) =
PublisherHelper::collect(*this, category, now, clear);

@ -14,96 +14,22 @@ namespace llarp
{
namespace metrics
{
class IntCollector
template < typename Type >
class Collector
{
const Id m_id;
size_t m_count GUARDED_BY(m_mutex);
int64_t m_total GUARDED_BY(m_mutex);
int m_min GUARDED_BY(m_mutex);
int m_max GUARDED_BY(m_mutex);
mutable util::Mutex m_mutex;
IntCollector(const IntCollector &) = delete;
IntCollector &
operator=(const IntCollector &) = delete;
public:
static constexpr int DEFAULT_MIN = std::numeric_limits< int >::max();
static constexpr int DEFAULT_MAX = std::numeric_limits< int >::min();
IntCollector(const Id &id)
: m_id(id)
, m_count(0)
, m_total(0)
, m_min(DEFAULT_MIN)
, m_max(DEFAULT_MAX)
{
}
const Id &
id() const
{
return m_id;
}
void
clear()
{
absl::WriterMutexLock l(&m_mutex);
m_count = 0;
m_total = 0;
m_min = DEFAULT_MIN;
m_max = DEFAULT_MAX;
}
Record
loadAndClear();
Record
load();
void
tick(int value)
{
absl::WriterMutexLock l(&m_mutex);
m_count++;
m_total += value;
m_min = std::min(m_min, value);
m_max = std::max(m_max, value);
}
void
accumulate(size_t count, int total, int min, int max)
{
absl::WriterMutexLock l(&m_mutex);
m_count += count;
m_total += total;
m_min = std::min(m_min, min);
m_max = std::max(m_max, max);
}
void
set(size_t count, int total, int min, int max)
{
absl::WriterMutexLock l(&m_mutex);
m_count = count;
m_total = total;
m_min = min;
m_max = max;
}
};
using RecordType = Record< Type >;
class DoubleCollector
{
Record m_record GUARDED_BY(m_mutex);
private:
RecordType m_record GUARDED_BY(m_mutex);
mutable util::Mutex m_mutex;
DoubleCollector(const DoubleCollector &) = delete;
DoubleCollector &
operator=(const DoubleCollector &) = delete;
Collector(const Collector &) = delete;
Collector &
operator=(const Collector &) = delete;
public:
DoubleCollector(const Id &id) : m_record(id)
Collector(const Id &id) : m_record(id)
{
}
@ -111,26 +37,20 @@ namespace llarp
clear()
{
absl::WriterMutexLock l(&m_mutex);
m_record.count() = 0;
m_record.total() = 0.0;
m_record.min() = Record::DEFAULT_MIN;
m_record.max() = Record::DEFAULT_MAX;
m_record.clear();
}
Record
RecordType
loadAndClear()
{
absl::WriterMutexLock l(&m_mutex);
Record rec = m_record;
m_record.count() = 0;
m_record.total() = 0.0;
m_record.min() = Record::DEFAULT_MIN;
m_record.max() = Record::DEFAULT_MAX;
RecordType rec = m_record;
m_record.clear();
return rec;
}
Record
RecordType
load()
{
absl::ReaderMutexLock l(&m_mutex);
@ -138,7 +58,7 @@ namespace llarp
}
void
tick(double value)
tick(Type value)
{
absl::WriterMutexLock l(&m_mutex);
m_record.count()++;
@ -148,7 +68,7 @@ namespace llarp
}
void
accumulate(size_t count, double total, double min, double max)
accumulate(size_t count, Type total, Type min, Type max)
{
absl::WriterMutexLock l(&m_mutex);
m_record.count() += count;
@ -158,7 +78,7 @@ namespace llarp
}
void
set(size_t count, double total, double min, double max)
set(size_t count, Type total, Type min, Type max)
{
absl::WriterMutexLock l(&m_mutex);
m_record.count() = count;
@ -175,36 +95,38 @@ namespace llarp
}
};
using IntCollector = Collector< int >;
using DoubleCollector = Collector< double >;
class Publisher
{
public:
virtual ~Publisher() = 0;
virtual ~Publisher() = default;
virtual void
publish(const Sample &sample) = 0;
publish(const Sample< double > &sample) = 0;
};
inline Publisher::~Publisher()
{
}
template < typename LhsType, typename RhsType >
static inline void
combine(Record &record, const Record &toAdd)
combine(Record< LhsType > &record, const Record< RhsType > &toAdd)
{
static_assert(std::is_convertible< RhsType, LhsType >::value, "");
record.id() = toAdd.id();
record.count() += toAdd.count();
record.total() += toAdd.total();
record.min() = std::min(record.min(), toAdd.min());
record.max() = std::max(record.max(), toAdd.max());
record.min() = std::min(record.min(), LhsType(toAdd.min()));
record.max() = std::max(record.max(), LhsType(toAdd.max()));
}
template < typename Collector >
template < typename Type >
class Collectors
{
using CollectorPtr = std::shared_ptr< Collector >;
using CollectorSet = std::set< CollectorPtr >;
using CollectorType = Collector< Type >;
using CollectorPtr = std::shared_ptr< CollectorType >;
using CollectorSet = std::set< CollectorPtr >;
Collector m_default;
CollectorType m_default;
CollectorSet m_collectors;
Collectors(const Collectors &) = delete;
@ -216,32 +138,32 @@ namespace llarp
{
}
Collector *
CollectorType *
defaultCollector()
{
return &m_default;
}
std::shared_ptr< Collector >
std::shared_ptr< CollectorType >
add()
{
auto ptr = std::make_shared< Collector >(m_default.id());
auto ptr = std::make_shared< CollectorType >(m_default.id());
m_collectors.insert(ptr);
return ptr;
}
bool
remove(Collector *collector)
remove(CollectorType *collector)
{
std::shared_ptr< Collector > ptr(collector, [](Collector *) {});
std::shared_ptr< CollectorType > ptr(collector, [](CollectorType *) {});
size_t count = m_collectors.erase(ptr);
return count > 0;
}
Record
Record< Type >
combineAndClear()
{
Record rec = m_default.loadAndClear();
Record< Type > rec = m_default.loadAndClear();
for(auto &ptr : m_collectors)
{
@ -251,10 +173,10 @@ namespace llarp
return rec;
}
Record
Record< Type >
combine()
{
Record rec = m_default.load();
Record< Type > rec = m_default.load();
for(auto &ptr : m_collectors)
{
@ -263,11 +185,11 @@ namespace llarp
return rec;
}
std::vector< std::shared_ptr< Collector > >
std::vector< std::shared_ptr< CollectorType > >
collectors() const
{
return std::vector< std::shared_ptr< Collector > >(m_collectors.begin(),
m_collectors.end());
return std::vector< std::shared_ptr< CollectorType > >(
m_collectors.begin(), m_collectors.end());
}
const Id &
@ -277,11 +199,12 @@ namespace llarp
}
};
using DoubleCollectors = Collectors< double >;
using IntCollectors = Collectors< int >;
class MetricCollectors
{
using DoubleCollectors = Collectors< DoubleCollector >;
using IntCollectors = Collectors< IntCollector >;
private:
DoubleCollectors m_doubleCollectors;
IntCollectors m_intCollectors;
@ -295,42 +218,42 @@ namespace llarp
{
}
Collectors< DoubleCollector > &
DoubleCollectors &
doubleCollectors()
{
return m_doubleCollectors;
}
Collectors< IntCollector > &
IntCollectors &
intCollectors()
{
return m_intCollectors;
}
const Collectors< DoubleCollector > &
const DoubleCollectors &
doubleCollectors() const
{
return m_doubleCollectors;
}
const Collectors< IntCollector > &
const IntCollectors &
intCollectors() const
{
return m_intCollectors;
}
Record
Record< double >
combineAndClear()
{
Record res = m_doubleCollectors.combineAndClear();
Record< double > res = m_doubleCollectors.combineAndClear();
metrics::combine(res, m_intCollectors.combineAndClear());
return res;
}
Record
Record< double >
combine()
{
Record res = m_doubleCollectors.combine();
Record< double > res = m_doubleCollectors.combine();
metrics::combine(res, m_intCollectors.combine());
return res;
}
@ -460,10 +383,10 @@ namespace llarp
{
}
std::vector< Record >
std::vector< Record< double > >
collectAndClear(const Category *category);
std::vector< Record >
std::vector< Record< double > >
collect(const Category *category);
DoubleCollector *
@ -679,10 +602,11 @@ namespace llarp
class CallbackRegistry
{
using Handle = uint64_t;
using RecordCallback = std::function< std::vector< Record >(bool) >;
using CallbackMap = std::multimap< const Category *, RecordCallback >;
using HandleMap = std::map< Handle, CallbackMap::iterator >;
using Handle = uint64_t;
using RecordCallback =
std::function< std::vector< Record< double > >(bool) >;
using CallbackMap = std::multimap< const Category *, RecordCallback >;
using HandleMap = std::map< Handle, CallbackMap::iterator >;
Handle m_next;
CallbackMap m_callbackMap;
@ -772,7 +696,8 @@ namespace llarp
public:
// Public callback. If the bool flag is true, clear the metrics back to
// their default state.
using RecordCallback = std::function< std::vector< Record >(bool) >;
using RecordCallback =
std::function< std::vector< Record< double > >(bool) >;
using Handle = uint64_t;
@ -869,15 +794,16 @@ namespace llarp
// clang-format on
/// Publish specific categories of metric matching the category/categories
Sample
collectSample(std::vector< Record > &records, bool clear = false)
Sample< double >
collectSample(std::vector< Record< double > > &records,
bool clear = false)
{
std::vector< const Category * > allCategories = m_registry.getAll();
return collectSample(
records, absl::Span< const Category * >{allCategories}, clear);
}
Sample
collectSample(std::vector< Record > &records,
Sample< double >
collectSample(std::vector< Record< double > > &records,
absl::Span< const Category * > categories,
bool clear = false);

@ -139,40 +139,6 @@ namespace llarp
return stream;
}
const double Record::DEFAULT_MIN = std::numeric_limits< double >::max() * 2;
const double Record::DEFAULT_MAX =
std::numeric_limits< double >::max() * -2;
std::ostream &
Record::print(std::ostream &stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printAttribute("id", m_id);
printer.printAttribute("count", m_count);
printer.printAttribute("total", m_total);
printer.printAttribute("min", m_min);
printer.printAttribute("max", m_max);
return stream;
}
std::ostream &
SampleGroup::print(std::ostream &stream, int level, int spaces) const
{
Printer::PrintFunction< absl::Duration > durationPrinter =
[](std::ostream &stream, const absl::Duration &duration, int,
int) -> std::ostream & {
stream << duration;
return stream;
};
Printer printer(stream, level, spaces);
printer.printAttribute("records", m_records);
printer.printForeignAttribute("samplePeriod", m_samplePeriod,
durationPrinter);
return stream;
}
} // namespace metrics
} // namespace llarp

@ -1,16 +1,18 @@
#ifndef LLARP_METRICS_TYPES_HPP
#define LLARP_METRICS_TYPES_HPP
#include <util/printer.hpp>
#include <util/string_view.hpp>
#include <util/threading.hpp>
#include <util/types.hpp>
#include <absl/types/span.h>
#include <absl/types/optional.h>
#include <set>
#include <memory>
#include <cstring>
#include <iosfwd>
#include <memory>
#include <set>
#include <vector>
namespace llarp
{
@ -368,23 +370,46 @@ namespace llarp
return id.print(stream, -1, -1);
}
// clang-format off
// Forwarding class to specialise for metric types
template<typename Type>
struct RecordMax {
};
template<>
struct RecordMax<double> {
static constexpr double min() { return std::numeric_limits< double >::infinity(); }
static constexpr double max() { return -std::numeric_limits< double >::infinity(); }
};
template<>
struct RecordMax<int> {
static constexpr int min() { return std::numeric_limits< int >::max(); }
static constexpr int max() { return std::numeric_limits< int >::min(); }
};
// clang-format on
template < typename Type >
class Record
{
Id m_id;
size_t m_count;
double m_total;
double m_min;
double m_max;
Type m_total;
Type m_min;
Type m_max;
public:
static const double DEFAULT_MIN;
static const double DEFAULT_MAX;
// clang-format off
static constexpr Type DEFAULT_MIN() { return RecordMax<Type>::min(); };
static constexpr Type DEFAULT_MAX() { return RecordMax<Type>::max(); };
// clang-format on
Record()
: m_id()
, m_count(0)
, m_total(0.0)
, m_min(DEFAULT_MIN)
, m_max(DEFAULT_MAX)
, m_min(DEFAULT_MIN())
, m_max(DEFAULT_MAX())
{
}
@ -392,8 +417,8 @@ namespace llarp
: m_id(id)
, m_count(0)
, m_total(0.0)
, m_min(DEFAULT_MIN)
, m_max(DEFAULT_MAX)
, m_min(DEFAULT_MIN())
, m_max(DEFAULT_MAX())
{
}
@ -409,53 +434,77 @@ namespace llarp
size_t count() const { return m_count; }
size_t& count() { return m_count; }
double total() const { return m_total; }
double& total() { return m_total; }
Type total() const { return m_total; }
Type& total() { return m_total; }
double min() const { return m_min; }
double& min() { return m_min; }
Type min() const { return m_min; }
Type& min() { return m_min; }
double max() const { return m_max; }
double& max() { return m_max; }
Type max() const { return m_max; }
Type& max() { return m_max; }
// clang-format on
void
clear()
{
m_count = 0;
m_total = 0;
m_min = DEFAULT_MIN();
m_max = DEFAULT_MAX();
}
std::ostream &
print(std::ostream &stream, int level, int spaces) const;
print(std::ostream &stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printAttribute("id", m_id);
printer.printAttribute("count", m_count);
printer.printAttribute("total", m_total);
printer.printAttribute("min", m_min);
printer.printAttribute("max", m_max);
return stream;
}
};
template < typename Type >
inline std::ostream &
operator<<(std::ostream &stream, const Record &rec)
operator<<(std::ostream &stream, const Record< Type > &rec)
{
return rec.print(stream, -1, -1);
}
template < typename Type >
inline bool
operator==(const Record &lhs, const Record &rhs)
operator==(const Record< Type > &lhs, const Record< Type > &rhs)
{
return (lhs.id() == rhs.id() && lhs.count() == rhs.count()
&& lhs.total() == rhs.total() && lhs.min() == rhs.min()
&& lhs.max() == rhs.max());
}
template < typename Type >
class SampleGroup
{
absl::Span< const Record > m_records;
absl::Span< const Record< Type > > m_records;
absl::Duration m_samplePeriod;
public:
using const_iterator = absl::Span< const Record >::const_iterator;
using RecordType = Record< Type >;
using const_iterator =
typename absl::Span< const RecordType >::const_iterator;
SampleGroup() : m_records(), m_samplePeriod()
{
}
SampleGroup(const Record *records, size_t size,
SampleGroup(const RecordType *records, size_t size,
absl::Duration samplePeriod)
: m_records(records, size), m_samplePeriod(samplePeriod)
{
}
SampleGroup(const absl::Span< const Record > &records,
SampleGroup(const absl::Span< const RecordType > &records,
absl::Duration samplePeriod)
: m_records(records), m_samplePeriod(samplePeriod)
{
@ -465,8 +514,8 @@ namespace llarp
void samplePeriod(absl::Duration duration) { m_samplePeriod = duration; }
absl::Duration samplePeriod() const { return m_samplePeriod; }
void records(absl::Span<const Record> recs) { m_records = recs; }
absl::Span<const Record> records() const { return m_records; }
void records(absl::Span<const RecordType> recs) { m_records = recs; }
absl::Span<const RecordType> records() const { return m_records; }
bool empty() const { return m_records.empty(); }
size_t size() const { return m_records.size(); }
@ -476,30 +525,48 @@ namespace llarp
// clang-format on
std::ostream &
print(std::ostream &stream, int level, int spaces) const;
print(std::ostream &stream, int level, int spaces) const
{
Printer::PrintFunction< absl::Duration > durationPrinter =
[](std::ostream &stream, const absl::Duration &duration, int,
int) -> std::ostream & {
stream << duration;
return stream;
};
Printer printer(stream, level, spaces);
printer.printAttribute("records", m_records);
printer.printForeignAttribute("samplePeriod", m_samplePeriod,
durationPrinter);
return stream;
}
};
template < typename Type >
inline std::ostream &
operator<<(std::ostream &stream, const SampleGroup &group)
operator<<(std::ostream &stream, const SampleGroup< Type > &group)
{
return group.print(stream, -1, -1);
}
template < typename Type >
inline bool
operator==(const SampleGroup &lhs, const SampleGroup &rhs)
operator==(const SampleGroup< Type > &lhs, const SampleGroup< Type > &rhs)
{
return lhs.records() == rhs.records()
&& lhs.samplePeriod() == rhs.samplePeriod();
}
template < typename Type >
class Sample
{
absl::Time m_sampleTime;
std::vector< SampleGroup > m_samples;
std::vector< SampleGroup< Type > > m_samples;
size_t m_recordCount;
public:
using const_iterator = std::vector< SampleGroup >::const_iterator;
using const_iterator =
typename std::vector< SampleGroup< Type > >::const_iterator;
Sample() : m_sampleTime(), m_recordCount(0)
{
@ -509,21 +576,21 @@ namespace llarp
void sampleTime(const absl::Time& time) { m_sampleTime = time; }
absl::Time sampleTime() const { return m_sampleTime; }
void pushGroup(const SampleGroup& group) {
void pushGroup(const SampleGroup<Type>& group) {
if (!group.empty()) {
m_samples.push_back(group);
m_recordCount += group.size();
}
}
void pushGroup(const Record *records, size_t size, absl::Duration duration) {
void pushGroup(const Record<Type> *records, size_t size, absl::Duration duration) {
if (size != 0) {
m_samples.emplace_back(records, size, duration);
m_recordCount += size;
}
}
void pushGroup(const absl::Span< const Record > &records,absl::Duration duration) {
void pushGroup(const absl::Span< const Record<Type> > &records,absl::Duration duration) {
if (!records.empty()) {
m_samples.emplace_back(records, duration);
m_recordCount += records.size();
@ -535,7 +602,7 @@ namespace llarp
m_recordCount = 0;
}
const SampleGroup& group(size_t index) {
const SampleGroup<Type>& group(size_t index) {
assert(index < m_samples.size());
return m_samples[index];
}

@ -17,12 +17,12 @@ TEST(MetricsPublisher, StreamPublisher)
std::stringstream stream;
metrics::StreamPublisher myPublisher(stream);
std::vector< metrics::Record > records;
std::vector< metrics::Record< double > > records;
records.emplace_back(metricA, 5, 25.0, 6.0, 25.0);
records.emplace_back(metricB, 2, 7.0, 3.0, 11.0);
metrics::Sample sample;
metrics::Sample< double > sample;
sample.sampleTime(absl::Now());
sample.pushGroup(records.data(), records.size(), absl::Seconds(5));

@ -41,19 +41,19 @@ TYPED_TEST_P(CollectorTest, Collector)
ASSERT_EQ(METRIC_A, collector1.id().description());
ASSERT_EQ(METRIC_B, collector2.id().description());
Record record1 = collector1.load();
typename TypeParam::RecordType record1 = collector1.load();
ASSERT_EQ(METRIC_A, record1.id().description());
ASSERT_EQ(0, record1.count());
ASSERT_EQ(0, record1.total());
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
Record record2 = collector2.load();
typename TypeParam::RecordType record2 = collector2.load();
ASSERT_EQ(METRIC_B, record2.id().description());
ASSERT_EQ(0, record2.count());
ASSERT_EQ(0, record2.total());
ASSERT_EQ(Record::DEFAULT_MIN, record2.min());
ASSERT_EQ(Record::DEFAULT_MAX, record2.max());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record2.min());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record2.max());
collector1.tick(1);
record1 = collector1.load();
@ -84,8 +84,8 @@ TYPED_TEST_P(CollectorTest, Collector)
ASSERT_EQ(METRIC_A, record1.id().description());
ASSERT_EQ(0, record1.count());
ASSERT_EQ(0, record1.total());
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
collector1.tick(3);
record1 = collector1.loadAndClear();
@ -99,8 +99,8 @@ TYPED_TEST_P(CollectorTest, Collector)
ASSERT_EQ(METRIC_A, record1.id().description());
ASSERT_EQ(0, record1.count());
ASSERT_EQ(0, record1.total());
ASSERT_EQ(Record::DEFAULT_MIN, record1.min());
ASSERT_EQ(Record::DEFAULT_MAX, record1.max());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MIN(), record1.min());
ASSERT_EQ(TypeParam::RecordType::DEFAULT_MAX(), record1.max());
}
REGISTER_TYPED_TEST_SUITE_P(CollectorTest, Collector);
@ -330,7 +330,8 @@ TEST(MetricsCore, RepoBasic)
intCollector1->tick(5);
intCollector2->tick(6);
std::vector< Record > records = repo.collectAndClear(registry.get("Test"));
std::vector< Record< double > > records =
repo.collectAndClear(registry.get("Test"));
ASSERT_THAT(records, SizeIs(4));
// clang-format off
ASSERT_THAT(
@ -390,7 +391,7 @@ TEST(MetricsCore, RepoCollect)
const char *CATEGORY = CATEGORIES[i];
const Category *category = registry.get(CATEGORY);
std::vector< Record > records = repo.collect(category);
std::vector< Record< double > > records = repo.collect(category);
ASSERT_THAT(records, SizeIs(static_cast< int >(METRICS.size())));
// clang-format off
@ -414,11 +415,12 @@ TEST(MetricsCore, RepoCollect)
const auto &intCols = collectors.second;
for(int k = 0; k < static_cast< int >(doubleCols.size()); ++k)
{
Record E(metric, j, 2 * j, -j, j);
Record record1 = doubleCols[k]->load();
Record record2 = intCols[k]->load();
ASSERT_EQ(record1, E);
ASSERT_EQ(record2, E);
Record< double > ED(metric, j, 2 * j, -j, j);
Record< int > EI(metric, j, 2 * j, -j, j);
Record< double > record1 = doubleCols[k]->load();
Record< int > record2 = intCols[k]->load();
ASSERT_EQ(record1, ED);
ASSERT_EQ(record2, EI);
}
}
}
@ -441,9 +443,9 @@ TEST(MetricsCore, RepoCollect)
for(int l = 0; l < static_cast< int >(doubleCols.size()); ++l)
{
Record record1 = doubleCols[k]->load();
Record< double > record1 = doubleCols[k]->load();
ASSERT_THAT(record1, RecordEq(metric, 100u, 100, 100, 100));
Record record2 = intCols[k]->load();
Record< int > record2 = intCols[k]->load();
ASSERT_THAT(record2, RecordEq(metric, 100u, 100, 100, 100));
}
}
@ -460,11 +462,11 @@ MATCHER_P2(WithinWindow, expectedTime, window, "")
}
const Category *
firstCategory(const SampleGroup &group)
firstCategory(const SampleGroup< double > &group)
{
EXPECT_THAT(group, Not(IsEmpty()));
const Category *value = group.begin()->id().category();
for(const Record &record : group.records())
for(const Record< double > &record : group.records())
{
EXPECT_EQ(value, record.id().category());
}
@ -494,8 +496,8 @@ TEST(MetricsCore, ManagerCollectSample1)
absl::Time start = absl::Now();
std::this_thread::sleep_for(std::chrono::microseconds(100000));
std::vector< Record > records;
Sample sample = manager.collectSample(records, false);
std::vector< Record< double > > records;
Sample< double > sample = manager.collectSample(records, false);
absl::Duration window = absl::Now() - start;
absl::Time now = absl::Now();
@ -506,14 +508,14 @@ TEST(MetricsCore, ManagerCollectSample1)
for(size_t i = 0; i < sample.groupCount(); ++i)
{
const SampleGroup &group = sample.group(i);
const SampleGroup< double > &group = sample.group(i);
ASSERT_EQ(NUM_METRICS, group.size());
ASSERT_THAT(group.samplePeriod(),
WithinWindow(window, absl::Milliseconds(10)))
<< group;
const char *name = group.records()[0].id().categoryName();
for(const Record &record : group.records())
for(const Record< double > &record : group.records())
{
ASSERT_THAT(record, RecordCatEq(name, 1u, 1, 1, 1));
}
@ -524,7 +526,7 @@ TEST(MetricsCore, ManagerCollectSample1)
{
DoubleCollector *col =
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
Record record = col->load();
Record< double > record = col->load();
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
}
}
@ -542,8 +544,8 @@ TEST(MetricsCore, ManagerCollectSample1)
{
DoubleCollector *col =
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
Record record = col->load();
ASSERT_EQ(Record(record.id()), record);
Record< double > record = col->load();
ASSERT_EQ(Record< double >(record.id()), record);
}
}
}
@ -584,8 +586,8 @@ TEST(MetricsCore, ManagerCollectSample2)
// Test without a reset.
std::vector< const Category * > cats = combIt.currentCombo;
std::vector< Record > records;
Sample sample = manager.collectSample(
std::vector< Record< double > > records;
Sample< double > sample = manager.collectSample(
records, absl::Span< const Category * >{cats}, false);
ASSERT_EQ(NUM_METRICS * cats.size(), sample.recordCount());
@ -610,11 +612,11 @@ TEST(MetricsCore, ManagerCollectSample2)
{
DoubleCollector *col =
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
Record record = col->load();
Record< double > record = col->load();
ASSERT_THAT(record, RecordEq(1u, 1, 1, 1));
}
}
std::vector< Record > records2;
std::vector< Record< double > > records2;
// Test with a reset.
sample = manager.collectSample(records2,
@ -643,10 +645,10 @@ TEST(MetricsCore, ManagerCollectSample2)
{
DoubleCollector *col =
rep.defaultDoubleCollector(CATEGORIES[i], METRICS[j]);
Record record = col->load();
Record< double > record = col->load();
if(combIt.includesElement(i))
{
ASSERT_EQ(Record(record.id()), record);
ASSERT_EQ(Record< double >(record.id()), record);
}
else
{
@ -661,14 +663,14 @@ TEST(MetricsCore, ManagerCollectSample2)
struct MockPublisher : public Publisher
{
std::atomic_int invocations;
std::vector< Record > recordBuffer;
std::vector< Record > sortedRecords;
Sample m_sample;
std::vector< Record< double > > recordBuffer;
std::vector< Record< double > > sortedRecords;
Sample< double > m_sample;
std::set< absl::Duration > times;
void
publish(const Sample &sample) override
publish(const Sample< double > &sample) override
{
invocations++;
@ -691,7 +693,7 @@ struct MockPublisher : public Publisher
auto git = s.begin();
ASSERT_NE(git, s.end());
recordBuffer.push_back(*git);
Record *head = &recordBuffer.back();
Record< double > *head = &recordBuffer.back();
for(++git; git != s.end(); ++git)
{
recordBuffer.push_back(*git);
@ -719,7 +721,7 @@ struct MockPublisher : public Publisher
int
indexOf(const Id &id)
{
Record searchRecord(id);
Record< double > searchRecord(id);
auto it = std::lower_bound(
sortedRecords.begin(), sortedRecords.end(), searchRecord,
[](const auto &lhs, const auto &rhs) { return lhs.id() < rhs.id(); });

@ -8,6 +8,8 @@
using namespace llarp;
using namespace ::testing;
using RecordT = metrics::Record< double >;
struct MetricFormatSpecTestData
{
float m_scale;
@ -130,7 +132,7 @@ TEST(MetricsTypes, CatContainer)
TEST(MetricsTypes, Record)
{
metrics::Record r;
RecordT r;
ASSERT_GT(r.min(), r.max());
}
@ -146,15 +148,15 @@ TEST(MetricsTypes, Sample)
metrics::Id metricC(&descC);
absl::Time timeStamp = absl::Now();
metrics::Record recordA(metricA, 0, 0, 0, 0);
metrics::Record recordB(metricB, 1, 2, 3, 4);
metrics::Record recordC(metricC, 4, 3, 2, 1);
RecordT recordA(metricA, 0, 0, 0, 0);
RecordT recordB(metricB, 1, 2, 3, 4);
RecordT recordC(metricC, 4, 3, 2, 1);
metrics::Record buffer1[] = {recordA, recordB};
std::vector< metrics::Record > buffer2;
RecordT buffer1[] = {recordA, recordB};
std::vector< RecordT > buffer2;
buffer2.push_back(recordC);
metrics::Sample sample;
metrics::Sample< double > sample;
sample.sampleTime(timeStamp);
sample.pushGroup(buffer1, sizeof(buffer1) / sizeof(*buffer1),
absl::Seconds(1.0));
@ -200,7 +202,7 @@ struct SampleTest
metrics::Id id_F;
metrics::Id id_G;
std::vector< metrics::Record > recordBuffer;
std::vector< RecordT > recordBuffer;
SampleTest()
: cat_A("A", true)
@ -231,17 +233,17 @@ struct SampleTest
}
};
std::pair< std::vector< metrics::SampleGroup >, size_t >
std::pair< std::vector< metrics::SampleGroup< double > >, size_t >
generate(const std::string &specification,
const std::vector< metrics::Record > &recordBuffer)
const std::vector< RecordT > &recordBuffer)
{
const char *c = specification.c_str();
std::vector< metrics::SampleGroup > groups;
std::vector< metrics::SampleGroup< double > > groups;
size_t size = 0;
const metrics::Record *head = recordBuffer.data();
const metrics::Record *current = head;
const RecordT *head = recordBuffer.data();
const RecordT *current = head;
while(*c)
{
int numRecords = *(c + 1) - '0';
@ -268,12 +270,12 @@ TEST_P(SampleTest, basics)
std::tie(timestamp, spec) = GetParam();
std::vector< metrics::SampleGroup > groups;
std::vector< metrics::SampleGroup< double > > groups;
size_t size;
std::tie(groups, size) = generate(spec, recordBuffer);
// Create the sample.
metrics::Sample sample;
metrics::Sample< double > sample;
sample.sampleTime(timestamp);
for(size_t j = 0; j < groups.size(); ++j)
{
@ -297,12 +299,12 @@ TEST_P(SampleTest, append)
std::tie(timestamp, spec) = GetParam();
std::vector< metrics::SampleGroup > groups;
std::vector< metrics::SampleGroup< double > > groups;
size_t size;
std::tie(groups, size) = generate(spec, recordBuffer);
// Create the sample.
metrics::Sample sample;
metrics::Sample< double > sample;
sample.sampleTime(timestamp);
std::for_each(groups.begin(), groups.end(), [&](const auto &group) {

Loading…
Cancel
Save