From 47416292909930ba4262e6264689f4960be395c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Sat, 10 Feb 2024 23:41:45 +0100 Subject: [PATCH] CONFIG --- nano/lib/stats.cpp | 153 ++++++++++++++++++---------------------- nano/lib/stats.hpp | 15 ++-- nano/lib/tomlconfig.hpp | 1 + nano/lib/utility.hpp | 6 +- 4 files changed, 80 insertions(+), 95 deletions(-) diff --git a/nano/lib/stats.cpp b/nano/lib/stats.cpp index 7f2e4b8c49..faf0fc178f 100644 --- a/nano/lib/stats.cpp +++ b/nano/lib/stats.cpp @@ -10,59 +10,6 @@ #include #include -/* - * stats_config - */ - -nano::error nano::stats_config::deserialize_toml (nano::tomlconfig & toml) -{ - auto sampling_l (toml.get_optional_child ("sampling")); - if (sampling_l) - { - sampling_l->get ("enable", sampling_enabled); - sampling_l->get ("capacity", capacity); - sampling_l->get ("interval", interval); - } - - auto log_l (toml.get_optional_child ("log")); - if (log_l) - { - log_l->get ("headers", log_headers); - log_l->get ("interval_counters", log_interval_counters); - log_l->get ("interval_samples", log_interval_samples); - log_l->get ("rotation_count", log_rotation_count); - log_l->get ("filename_counters", log_counters_filename); - log_l->get ("filename_samples", log_samples_filename); - - // Don't allow specifying the same file name for counter and samples logs - if (log_counters_filename == log_samples_filename) - { - toml.get_error ().set ("The statistics counter and samples config values must be different"); - } - } - - return toml.get_error (); -} - -nano::error nano::stats_config::serialize_toml (nano::tomlconfig & toml) const -{ - nano::tomlconfig sampling_l; - sampling_l.put ("enable", sampling_enabled, "Enable or disable sampling.\ntype:bool"); - sampling_l.put ("capacity", capacity, "How many sample intervals to keep in the ring buffer.\ntype:uint64"); - sampling_l.put ("interval", interval, "Sample interval.\ntype:milliseconds"); - toml.put_child ("sampling", sampling_l); - - nano::tomlconfig log_l; - log_l.put ("headers", log_headers, "If true, write headers on each counter or samples writeout.\nThe header contains log type and the current wall time.\ntype:bool"); - log_l.put ("interval_counters", log_interval_counters, "How often to log counters. 0 disables logging.\ntype:milliseconds"); - log_l.put ("interval_samples", log_interval_samples, "How often to log samples. 0 disables logging.\ntype:milliseconds"); - log_l.put ("rotation_count", log_rotation_count, "Maximum number of log outputs before rotating the file.\ntype:uint64"); - log_l.put ("filename_counters", log_counters_filename, "Log file name for counters.\ntype:string"); - log_l.put ("filename_samples", log_samples_filename, "Log file name for samples.\ntype:string"); - toml.put_child ("log", log_l); - return toml.get_error (); -} - /* * stat_log_sink */ @@ -222,7 +169,7 @@ auto nano::stats::count (stat::type type, stat::detail detail, stat::dir dir) co void nano::stats::sample (stat::sample type, nano::stats::sampler_value_t value) { update_sampler (sampler_key{ type }, [this, value] (sampler_entry & sampler) { - sampler.add (value, config.capacity); + sampler.add (value, config.max_samples); }); } @@ -380,41 +327,29 @@ void nano::stats::update () std::lock_guard guard{ mutex }; if (!stopped) { - auto has_interval_counter = [&] () { - return config.log_interval_counters > 0; - }; - auto has_sampling = [&] () { - return config.sampling_enabled && config.interval > 0; - }; - - if (has_interval_counter () || has_sampling ()) - { - auto now = std::chrono::steady_clock::now (); // Only sample clock if necessary as this impacts node performance due to frequent usage + auto now = std::chrono::steady_clock::now (); // Only sample clock if necessary as this impacts node performance due to frequent usage - // TODO: Replace with a proper std::chrono time - std::time_t time = std::chrono::system_clock::to_time_t (std::chrono::system_clock::now ()); - tm local_tm = *localtime (&time); + // TODO: Replace with a proper std::chrono time + std::time_t time = std::chrono::system_clock::to_time_t (std::chrono::system_clock::now ()); + tm local_tm = *localtime (&time); - // Counters - if (has_interval_counter ()) + // Counters + if (config.log_counters_interval.count () > 0) + { + if (nano::elapsed (log_last_count_writeout, config.log_counters_interval)) { - std::chrono::duration duration = now - log_last_count_writeout; - if (duration.count () > config.log_interval_counters) - { - log_counters_impl (log_count, local_tm); - log_last_count_writeout = now; - } + log_counters_impl (log_count, local_tm); + log_last_count_writeout = now; } + } - // Samples - if (has_sampling ()) + // Samples + if (config.log_samples_interval.count () > 0) + { + if (nano::elapsed (log_last_sample_writeout, config.log_samples_interval)) { - std::chrono::duration duration = now - log_last_sample_writeout; - if (duration.count () > config.log_interval_samples) - { - log_samples_impl (log_sample, local_tm); - log_last_sample_writeout = now; - } + log_samples_impl (log_sample, local_tm); + log_last_sample_writeout = now; } } } @@ -465,4 +400,56 @@ auto nano::stats::sampler_entry::collect () -> std::vector std::vector result{ samples.begin (), samples.end () }; samples.clear (); return result; +} + +/* + * stats_config + */ + +nano::error nano::stats_config::serialize_toml (nano::tomlconfig & toml) const +{ + toml.put ("max_samples", max_samples, "Maximum number of samples to keep in the ring buffer.\ntype:uint64"); + + nano::tomlconfig log_l; + log_l.put ("headers", log_headers, "If true, write headers on each counter or samples writeout.\nThe header contains log type and the current wall time.\ntype:bool"); + log_l.put ("interval_counters", log_counters_interval.count (), "How often to log counters. 0 disables logging.\ntype:milliseconds"); + log_l.put ("interval_samples", log_samples_interval.count (), "How often to log samples. 0 disables logging.\ntype:milliseconds"); + log_l.put ("rotation_count", log_rotation_count, "Maximum number of log outputs before rotating the file.\ntype:uint64"); + log_l.put ("filename_counters", log_counters_filename, "Log file name for counters.\ntype:string"); + log_l.put ("filename_samples", log_samples_filename, "Log file name for samples.\ntype:string"); + toml.put_child ("log", log_l); + + return toml.get_error (); +} + +nano::error nano::stats_config::deserialize_toml (nano::tomlconfig & toml) +{ + toml.get ("max_samples", max_samples); + + if (auto maybe_log_l = toml.get_optional_child ("log")) + { + auto log_l = *maybe_log_l; + + log_l.get ("headers", log_headers); + + auto counters_interval_l = log_counters_interval.count (); + log_l.get ("interval_counters", counters_interval_l); + log_counters_interval = std::chrono::milliseconds{ counters_interval_l }; + + auto samples_interval_l = log_samples_interval.count (); + log_l.get ("interval_samples", samples_interval_l); + log_samples_interval = std::chrono::milliseconds{ samples_interval_l }; + + log_l.get ("rotation_count", log_rotation_count); + log_l.get ("filename_counters", log_counters_filename); + log_l.get ("filename_samples", log_samples_filename); + + // Don't allow specifying the same file name for counter and samples logs + if (log_counters_filename == log_samples_filename) + { + toml.get_error ().set ("The statistics counter and samples config values must be different"); + } + } + + return toml.get_error (); } \ No newline at end of file diff --git a/nano/lib/stats.hpp b/nano/lib/stats.hpp index cda272fb8d..3efb2bb80e 100644 --- a/nano/lib/stats.hpp +++ b/nano/lib/stats.hpp @@ -33,20 +33,15 @@ class stats_config final nano::error deserialize_toml (nano::tomlconfig & toml); nano::error serialize_toml (nano::tomlconfig & toml) const; - /** If true, sampling of counters is enabled */ - bool sampling_enabled{ false }; - - /** How many sample intervals to keep in the ring buffer */ - size_t capacity{ 0 }; - - /** Sample interval in milliseconds */ - size_t interval{ 0 }; +public: + /** Maximum number samples to keep in the ring buffer */ + size_t max_samples{ 1024 * 16 }; /** How often to log sample array, in milliseconds. Default is 0 (no logging) */ - size_t log_interval_samples{ 0 }; + std::chrono::milliseconds log_samples_interval{ 0 }; /** How often to log counters, in milliseconds. Default is 0 (no logging) */ - size_t log_interval_counters{ 0 }; + std::chrono::milliseconds log_counters_interval{ 0 }; /** Maximum number of log outputs before rotating the file */ size_t log_rotation_count{ 100 }; diff --git a/nano/lib/tomlconfig.hpp b/nano/lib/tomlconfig.hpp index 140e1b0ab9..da83db4f1b 100644 --- a/nano/lib/tomlconfig.hpp +++ b/nano/lib/tomlconfig.hpp @@ -29,6 +29,7 @@ class tomlconfig : public nano::configbase public: tomlconfig (); tomlconfig (std::shared_ptr const & tree_a, std::shared_ptr const & error_a = nullptr); + void doc (std::string const & key, std::string const & doc); nano::error & read (std::filesystem::path const & path_a); nano::error & read (std::istream & stream_overrides, std::filesystem::path const & path_a); diff --git a/nano/lib/utility.hpp b/nano/lib/utility.hpp index 7b2ce35cab..06646e95c1 100644 --- a/nano/lib/utility.hpp +++ b/nano/lib/utility.hpp @@ -197,18 +197,20 @@ using clock = std::chrono::steady_clock; /** * Check whether time elapsed between `last` and `now` is greater than `duration` + * Force usage of steady clock */ template -bool elapsed (nano::clock::time_point const & last, Duration duration, nano::clock::time_point const & now) +bool elapsed (nano::clock::time_point const & last, Duration const & duration, nano::clock::time_point const & now) { return last + duration < now; } /** * Check whether time elapsed since `last` is greater than `duration` + * Force usage of steady clock */ template -bool elapsed (nano::clock::time_point const & last, Duration duration) +bool elapsed (nano::clock::time_point const & last, Duration const & duration) { return elapsed (last, duration, nano::clock::now ()); }