Skip to content

Commit

Permalink
INDEX STATS BY KEY STRUCT
Browse files Browse the repository at this point in the history
  • Loading branch information
pwojcikdev committed Feb 10, 2024
1 parent a9b4775 commit e6d9d28
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 71 deletions.
70 changes: 24 additions & 46 deletions nano/lib/stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,37 +273,33 @@ nano::stats::stats (nano::stats_config config) :
{
}

void nano::stats::add (stat::type type, stat::detail detail, stat::dir dir, uint64_t value, bool detail_only)
void nano::stats::add (stat::type type, stat::detail detail, stat::dir dir, uint64_t value)
{
if (value == 0)
{
return;
}

constexpr uint32_t no_detail_mask = 0xffff00ff;
uint32_t key = key_of (type, detail, dir);
update (key{ type, detail, dir }, value);

update (key, value);

// Optionally update at type-level as well
if (!detail_only && (key & no_detail_mask) != key)
if (detail != stat::detail::all)
{
update (key & no_detail_mask, value);
update (key{ type, stat::detail::all, dir }, value);
}
}

std::shared_ptr<nano::stat_entry> nano::stats::get_entry (uint32_t key)
std::shared_ptr<nano::stat_entry> nano::stats::get_entry (key key)
{
return get_entry (key, config.interval, config.capacity);
}

std::shared_ptr<nano::stat_entry> nano::stats::get_entry (uint32_t key, size_t interval, size_t capacity)
std::shared_ptr<nano::stat_entry> nano::stats::get_entry (key key, size_t interval, size_t capacity)
{
nano::unique_lock<nano::mutex> lock{ stat_mutex };
return get_entry_impl (key, interval, capacity);
}

std::shared_ptr<nano::stat_entry> nano::stats::get_entry_impl (uint32_t key, size_t interval, size_t capacity)
std::shared_ptr<nano::stat_entry> nano::stats::get_entry_impl (key key, size_t interval, size_t capacity)
{
std::shared_ptr<nano::stat_entry> res;
auto entry = entries.find (key);
Expand Down Expand Up @@ -344,16 +340,16 @@ void nano::stats::log_counters_impl (stat_log_sink & sink)
sink.write_header ("counters", walltime);
}

for (auto & it : entries)
for (auto const & [key, value] : entries)
{
std::time_t time = std::chrono::system_clock::to_time_t (it.second->counter.get_timestamp ());
std::time_t time = std::chrono::system_clock::to_time_t (value->counter.get_timestamp ());
tm local_tm = *localtime (&time);

auto key = it.first;
std::string type = type_to_string (key);
std::string detail = detail_to_string (key);
std::string dir = dir_to_string (key);
sink.write_entry (local_tm, type, detail, dir, it.second->counter.get_value (), it.second->histogram.get ());
std::string type{ to_string (key.type) };
std::string detail{ to_string (key.detail) };
std::string dir{ to_string (key.dir) };

sink.write_entry (local_tm, type, detail, dir, value->counter.get_value (), value->histogram.get ());
}
sink.entries ()++;
sink.finalize ();
Expand All @@ -379,45 +375,45 @@ void nano::stats::log_samples_impl (stat_log_sink & sink)
sink.write_header ("samples", walltime);
}

for (auto & it : entries)
for (auto const & [key, value] : entries)
{
auto key = it.first;
std::string type = type_to_string (key);
std::string detail = detail_to_string (key);
std::string dir = dir_to_string (key);
std::string type{ to_string (key.type) };
std::string detail{ to_string (key.detail) };
std::string dir{ to_string (key.dir) };

for (auto & datapoint : it.second->samples)
for (auto & datapoint : value->samples)
{
std::time_t time = std::chrono::system_clock::to_time_t (datapoint.get_timestamp ());
tm local_tm = *localtime (&time);
sink.write_entry (local_tm, type, detail, dir, datapoint.get_value (), nullptr);
}
}

sink.entries ()++;
sink.finalize ();
}

void nano::stats::define_histogram (stat::type type, stat::detail detail, stat::dir dir, std::initializer_list<uint64_t> intervals_a, size_t bin_count_a /*=0*/)
{
auto entry (get_entry (key_of (type, detail, dir)));
auto entry (get_entry (key{ type, detail, dir }));
entry->histogram = std::make_unique<nano::stat_histogram> (intervals_a, bin_count_a);
}

void nano::stats::update_histogram (stat::type type, stat::detail detail, stat::dir dir, uint64_t index_a, uint64_t addend_a)
{
auto entry (get_entry (key_of (type, detail, dir)));
auto entry (get_entry (key{ type, detail, dir }));
debug_assert (entry->histogram != nullptr);
entry->histogram->add (index_a, addend_a);
}

nano::stat_histogram * nano::stats::get_histogram (stat::type type, stat::detail detail, stat::dir dir)
{
auto entry (get_entry (key_of (type, detail, dir)));
auto entry (get_entry (key{ type, detail, dir }));
debug_assert (entry->histogram != nullptr);
return entry->histogram.get ();
}

void nano::stats::update (uint32_t key_a, uint64_t value)
void nano::stats::update (key key_a, uint64_t value)
{
static file_writer log_count (config.log_counters_filename);
static file_writer log_sample (config.log_samples_filename);
Expand Down Expand Up @@ -522,24 +518,6 @@ void nano::stats::clear ()
timestamp = std::chrono::steady_clock::now ();
}

std::string nano::stats::type_to_string (uint32_t key)
{
auto type = static_cast<stat::type> (key >> 16 & 0x000000ff);
return std::string{ nano::to_string (type) };
}

std::string nano::stats::detail_to_string (uint32_t key)
{
auto detail = static_cast<stat::detail> (key >> 8 & 0x000000ff);
return std::string{ nano::to_string (detail) };
}

std::string nano::stats::dir_to_string (uint32_t key)
{
auto dir = static_cast<stat::dir> (key & 0x000000ff);
return std::string{ nano::to_string (dir) };
}

/*
* stat_datapoint
*/
Expand Down
42 changes: 20 additions & 22 deletions nano/lib/stats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

#include <chrono>
#include <initializer_list>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>

namespace nano
{
Expand Down Expand Up @@ -242,7 +242,7 @@ class stats final
*/
void configure (stat::type type, stat::detail detail, stat::dir dir, size_t interval, size_t capacity)
{
get_entry (key_of (type, detail, dir), interval, capacity);
get_entry (key{ type, detail, dir }, interval, capacity);
}

/** Increments the given counter */
Expand Down Expand Up @@ -313,9 +313,8 @@ class stats final
* @param detail Detail type, or detail::none to register on type-level only
* @param dir Direction
* @param value The amount to add
* @param detail_only If true, only update the detail-level counter
*/
void add (stat::type type, stat::detail detail, stat::dir dir, uint64_t value, bool detail_only = false);
void add (stat::type type, stat::detail detail, stat::dir dir, uint64_t value);

/**
* Add a sampling observer for a given counter.
Expand All @@ -325,7 +324,7 @@ class stats final
*/
void observe_sample (stat::type type, stat::detail detail, stat::dir dir, std::function<void (boost::circular_buffer<stat_datapoint> &)> observer)
{
get_entry (key_of (type, detail, dir))->sample_observers.add (observer);
get_entry (key{ type, detail, dir })->sample_observers.add (observer);
}

void observe_sample (stat::type type, stat::dir dir, std::function<void (boost::circular_buffer<stat_datapoint> &)> observer)
Expand All @@ -340,13 +339,13 @@ class stats final
*/
void observe_count (stat::type type, stat::detail detail, stat::dir dir, std::function<void (uint64_t, uint64_t)> observer)
{
get_entry (key_of (type, detail, dir))->count_observers.add (observer);
get_entry (key{ type, detail, dir })->count_observers.add (observer);
}

/** Returns a potentially empty list of the last N samples, where N is determined by the 'capacity' configuration */
boost::circular_buffer<stat_datapoint> * samples (stat::type type, stat::detail detail, stat::dir dir)
{
return &get_entry (key_of (type, detail, dir))->samples;
return &get_entry (key{ type, detail, dir })->samples;
}

/** Returns current value for the given counter at the type level */
Expand All @@ -358,7 +357,7 @@ class stats final
/** Returns current value for the given counter at the detail level */
uint64_t count (stat::type type, stat::detail detail, stat::dir dir = stat::dir::in)
{
return get_entry (key_of (type, detail, dir))->counter.get_value ();
return get_entry (key{ type, detail, dir })->counter.get_value ();
}

/** Returns the number of seconds since clear() was last called, or node startup if it's never called. */
Expand All @@ -381,31 +380,30 @@ class stats final
std::string dump (stat_category category = stat_category::counters);

private:
static std::string type_to_string (uint32_t key);
static std::string dir_to_string (uint32_t key);
static std::string detail_to_string (uint32_t key);

/** Constructs a key given type, detail and direction. This is used as input to update(...) and get_entry(...) */
uint32_t key_of (stat::type type, stat::detail detail, stat::dir dir) const
struct key
{
return static_cast<uint8_t> (type) << 16 | static_cast<uint8_t> (detail) << 8 | static_cast<uint8_t> (dir);
}
stat::type type;
stat::detail detail;
stat::dir dir;

auto operator<=> (const key &) const = default;
};

private:
/** Get entry for key, creating a new entry if necessary, using interval and sample count from config */
std::shared_ptr<nano::stat_entry> get_entry (uint32_t key);
std::shared_ptr<nano::stat_entry> get_entry (key key);

/** Get entry for key, creating a new entry if necessary */
std::shared_ptr<nano::stat_entry> get_entry (uint32_t key, size_t sample_interval, size_t max_samples);
std::shared_ptr<nano::stat_entry> get_entry (key key, size_t sample_interval, size_t max_samples);

/** Unlocked implementation of get_entry() */
std::shared_ptr<nano::stat_entry> get_entry_impl (uint32_t key, size_t sample_interval, size_t max_samples);
std::shared_ptr<nano::stat_entry> get_entry_impl (key key, size_t sample_interval, size_t max_samples);

/**
* Update count and sample and call any observers on the key
* @param key a key constructor from stat::type, stat::detail and stat::direction
* @value Amount to add to the counter
*/
void update (uint32_t key, uint64_t value);
void update (key key, uint64_t value);

/** Unlocked implementation of log_counters() to avoid using recursive locking */
void log_counters_impl (stat_log_sink & sink);
Expand All @@ -420,7 +418,7 @@ class stats final
nano::stats_config config;

/** Stat entries are sorted by key to simplify processing of log output */
std::unordered_map<uint32_t, std::shared_ptr<nano::stat_entry>> entries;
std::map<key, std::shared_ptr<nano::stat_entry>> entries;
std::chrono::steady_clock::time_point log_last_count_writeout{ std::chrono::steady_clock::now () };
std::chrono::steady_clock::time_point log_last_sample_writeout{ std::chrono::steady_clock::now () };

Expand Down
6 changes: 3 additions & 3 deletions nano/lib/stats_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace nano::stat
{
/** Primary statistics type */
enum class type : uint8_t
enum class type
{
traffic_tcp,
error,
Expand Down Expand Up @@ -55,7 +55,7 @@ enum class type : uint8_t
};

/** Optional detail type */
enum class detail : uint8_t
enum class detail
{
all = 0,

Expand Down Expand Up @@ -316,7 +316,7 @@ enum class detail : uint8_t
};

/** Direction of the stat. If the direction is irrelevant, use in */
enum class dir : uint8_t
enum class dir
{
in,
out,
Expand Down

0 comments on commit e6d9d28

Please sign in to comment.