From: Francis Dupont Date: Tue, 31 Mar 2020 16:39:50 +0000 (+0200) Subject: [#1174] Changed stats to use C++11 chrono X-Git-Tag: Kea-1.7.10~54 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11c8af9c4bb5f825f9371d6511fe4adf6f3d749c;p=thirdparty%2Fkea.git [#1174] Changed stats to use C++11 chrono --- diff --git a/m4macros/ax_cpp11.m4 b/m4macros/ax_cpp11.m4 index a63ea5e93b..6176728016 100644 --- a/m4macros/ax_cpp11.m4 +++ b/m4macros/ax_cpp11.m4 @@ -153,7 +153,7 @@ for retry in "none" "--std=c++11" "--std=c++0x" "--std=c++1x" "fail"; do continue]) AC_MSG_CHECKING(range-for support) - feature="constexpr" + feature="range-for support" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [#include @@ -220,11 +220,22 @@ for retry in "none" "--std=c++11" "--std=c++0x" "--std=c++1x" "fail"; do [#include std::atomic_flag flag;], [])], - [AC_MSG_RESULT([yes]) - break], + [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) continue]) + AC_MSG_CHECKING(chrono support) + feature="chrono" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [#include + using namespace std::chrono;], + [auto now = high_resolution_clock::now();])], + [AC_MSG_RESULT([yes]) + break], + [AC_MSG_RESULT([no]) + continue]) + done -])dnl AX_ISC_RPATH +])dnl AX_ISC_CPP11 diff --git a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc index 107caea4b1..3e1645516c 100644 --- a/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc +++ b/src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -634,7 +634,7 @@ TEST_F(CtrlChannelDhcpv4SrvTest, controlChannelStats) { s << "{ \"arguments\": { "; for (auto st = initial_stats.begin(); st != initial_stats.end();) { s << "\"" << *st << "\": [ [ 0, \""; - s << isc::util::ptimeToText(StatsMgr::instance().getObservation(*st)->getInteger().second); + s << isc::util::clockToText(StatsMgr::instance().getObservation(*st)->getInteger().second); s << "\" ] ]"; if (++st != initial_stats.end()) { s << ", "; diff --git a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc index 20ce9080f5..69fe15f0e8 100644 --- a/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc @@ -18,11 +18,11 @@ #include #include #include -#include #include #include #include #include +#include #include "marker_file.h" #include "test_libraries.h" @@ -1191,7 +1191,7 @@ TEST_F(CtrlChannelDhcpv6SrvTest, controlChannelStats) { s << "{ \"arguments\": { "; for (auto st = initial_stats.begin(); st != initial_stats.end();) { s << "\"" << *st << "\": [ [ 0, \""; - s << isc::util::ptimeToText(StatsMgr::instance().getObservation(*st)->getInteger().second); + s << isc::util::clockToText(StatsMgr::instance().getObservation(*st)->getInteger().second); s << "\" ] ]"; if (++st != initial_stats.end()) { s << ", "; diff --git a/src/lib/stats/observation.cc b/src/lib/stats/observation.cc index 926feff85f..711df8874a 100644 --- a/src/lib/stats/observation.cc +++ b/src/lib/stats/observation.cc @@ -7,15 +7,14 @@ #include #include -#include +#include #include -#include -#include +#include #include using namespace std; +using namespace std::chrono; using namespace isc::data; -using namespace boost::posix_time; namespace isc { namespace stats { @@ -195,10 +194,10 @@ void Observation::setValueInternal(SampleType value, StorageType& storage, } if (storage.empty()) { - storage.push_back(make_pair(value, microsec_clock::local_time())); + storage.push_back(make_pair(value, SampleClock::now())); } else { // Storing of more than one sample - storage.push_front(make_pair(value, microsec_clock::local_time())); + storage.push_front(make_pair(value, SampleClock::now())); if (max_sample_count_.first) { // if max_sample_count_ is set to true @@ -407,7 +406,7 @@ Observation::getJSON() const { for (std::list::iterator it = s.begin(); it != s.end(); ++it) { entry = isc::data::Element::createList(); value = isc::data::Element::create(static_cast((*it).first)); - timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second)); + timestamp = isc::data::Element::create(isc::util::clockToText((*it).second)); entry->add(value); entry->add(timestamp); @@ -424,7 +423,7 @@ Observation::getJSON() const { for (std::list::iterator it = s.begin(); it != s.end(); ++it) { entry = isc::data::Element::createList(); value = isc::data::Element::create((*it).first); - timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second)); + timestamp = isc::data::Element::create(isc::util::clockToText((*it).second)); entry->add(value); entry->add(timestamp); @@ -441,7 +440,7 @@ Observation::getJSON() const { for (std::list::iterator it = s.begin(); it != s.end(); ++it) { entry = isc::data::Element::createList(); value = isc::data::Element::create(isc::util::durationToText((*it).first)); - timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second)); + timestamp = isc::data::Element::create(isc::util::clockToText((*it).second)); entry->add(value); entry->add(timestamp); @@ -458,7 +457,7 @@ Observation::getJSON() const { for (std::list::iterator it = s.begin(); it != s.end(); ++it) { entry = isc::data::Element::createList(); value = isc::data::Element::create((*it).first); - timestamp = isc::data::Element::create(isc::util::ptimeToText((*it).second)); + timestamp = isc::data::Element::create(isc::util::clockToText((*it).second)); entry->add(value); entry->add(timestamp); @@ -489,7 +488,7 @@ void Observation::reset() { } case STAT_DURATION: { duration_samples_.clear(); - setValue(time_duration(0, 0, 0, 0)); + setValue(StatsDuration::zero()); return; } case STAT_STRING: { diff --git a/src/lib/stats/observation.h b/src/lib/stats/observation.h index 306d89335d..f1c6583e48 100644 --- a/src/lib/stats/observation.h +++ b/src/lib/stats/observation.h @@ -10,8 +10,7 @@ #include #include #include -#include -#include +#include #include #include @@ -28,9 +27,13 @@ public: isc::Exception(file, line, what) {} }; +/// @brief Define clock +/// +typedef std::chrono::system_clock SampleClock; + /// @brief Defines duration resolution /// -typedef boost::posix_time::time_duration StatsDuration; +typedef std::chrono::system_clock::duration StatsDuration; /// @defgroup stat_samples Specifies supported observation types. /// @@ -39,16 +42,16 @@ typedef boost::posix_time::time_duration StatsDuration; /// @{ /// @brief Integer (implemented as signed 64-bit integer) -typedef std::pair IntegerSample; +typedef std::pair IntegerSample; /// @brief Float (implemented as double precision) -typedef std::pair FloatSample; +typedef std::pair FloatSample; /// @brief Time Duration -typedef std::pair DurationSample; +typedef std::pair DurationSample; /// @brief String -typedef std::pair StringSample; +typedef std::pair StringSample; /// @} @@ -121,9 +124,9 @@ public: /// @param duration determines maximum age of samples /// Example: /// To set a statistic to keep observations for the last 5 minutes, call: - /// setMaxSampleAge(time_duration(0, 5, 0, 0)); + /// setMaxSampleAge(std::chrono::minutes(5)); /// To revert statistic to a single value, call: - /// setMaxSampleAge(time_duration(0, 0, 0, 0)); + /// setMaxSampleAge(StatsDuration::zero()); void setMaxSampleAge(const StatsDuration& duration); /// @brief Determines how many samples of a given statistic should be kept. @@ -388,7 +391,7 @@ private: /// @brief Maximum timespan of samples /// The limit is represented as a pair - /// of bool value and StatsDuration(boost::posix_time::time_duration) + /// of bool value and StatsDuration /// Only one kind of limit can be active /// The bool value informs which limit /// is available @@ -399,7 +402,8 @@ private: /// /// By default the MaxSampleCount is set to 20 /// and MaxSampleAge is disabled - static std::pair default_max_sample_age_; + std::pair max_sample_age_ = std::make_pair(false, + StatsDuration::zero()); /// @defgroup samples_storage Storage for supported observations /// diff --git a/src/lib/stats/stats_mgr.cc b/src/lib/stats/stats_mgr.cc index 67f5e5a338..8c4c93a380 100644 --- a/src/lib/stats/stats_mgr.cc +++ b/src/lib/stats/stats_mgr.cc @@ -10,12 +10,12 @@ #include #include #include -#include #include -#include #include +#include using namespace std; +using namespace std::chrono; using namespace isc::data; using namespace isc::config; using namespace isc::util; @@ -615,13 +615,7 @@ StatsMgr::getStatDuration(const ConstElementPtr& params, reason = "Missing mandatory 'duration' parameter."; return (false); } - int64_t time_duration = stat_duration->intValue(); - int64_t hours = time_duration / 3600; - time_duration -= hours * 3600; - int64_t minutes = time_duration / 60; - time_duration -= minutes * 60; - int64_t seconds = time_duration; - duration = boost::posix_time::time_duration(hours, minutes, seconds, 0); + duration = std::chrono::seconds(stat_duration->intValue()); return (true); } diff --git a/src/lib/stats/stats_mgr.h b/src/lib/stats/stats_mgr.h index 9723c6b0ae..4b5f576644 100644 --- a/src/lib/stats/stats_mgr.h +++ b/src/lib/stats/stats_mgr.h @@ -137,9 +137,9 @@ public: /// setMaxSampleCount() below. /// Example: /// To set a statistic to keep observations for the last 5 minutes, call: - /// setMaxSampleAge("incoming-packets", time_duration(0, 5, 0, 0)); + /// setMaxSampleAge("incoming-packets", StatsDuration::minutes(5)); /// to revert statistic to a single value, call: - /// setMaxSampleAge("incoming-packets", time_duration(0, 0, 0, 0)); + /// setMaxSampleAge("incoming-packets", StatsDuration:zero()); /// /// @param name name of the observation /// @param duration determines maximum age of samples diff --git a/src/lib/stats/tests/context_unittest.cc b/src/lib/stats/tests/context_unittest.cc index 329cdae36f..777db8bd8d 100644 --- a/src/lib/stats/tests/context_unittest.cc +++ b/src/lib/stats/tests/context_unittest.cc @@ -8,13 +8,13 @@ #include #include -#include +#include #include using namespace isc::data; using namespace isc::stats; -using namespace boost::posix_time; using namespace std; +using namespace std::chrono; // Basic test that checks get, add, del methods TEST(ContextTest, basic) { @@ -109,15 +109,16 @@ TEST(ContextTest, basic) { EXPECT_EQ(from_ctx->getMaxSampleCount().second, 50); // Set sample age for all statistics - EXPECT_NO_THROW(ctx.setMaxSampleAgeAll(millisec::time_duration(0, 4, 5, 3))); + const StatsDuration& dur(minutes(4) + seconds(5) + milliseconds(3)); + EXPECT_NO_THROW(ctx.setMaxSampleAgeAll(dur)); EXPECT_NO_THROW(from_ctx = ctx.get("alpha")); ASSERT_TRUE(from_ctx); - EXPECT_EQ(from_ctx->getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); + EXPECT_EQ(from_ctx->getMaxSampleAge().second, dur); EXPECT_NO_THROW(from_ctx = ctx.get("gamma")); ASSERT_TRUE(from_ctx); - EXPECT_EQ(from_ctx->getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); + EXPECT_EQ(from_ctx->getMaxSampleAge().second, dur); // Clear all statistics. EXPECT_NO_THROW(ctx.clear()); diff --git a/src/lib/stats/tests/observation_unittest.cc b/src/lib/stats/tests/observation_unittest.cc index 32e07bafdf..6c414ccf9d 100644 --- a/src/lib/stats/tests/observation_unittest.cc +++ b/src/lib/stats/tests/observation_unittest.cc @@ -8,9 +8,8 @@ #include #include -#include +#include #include -#include #include #include @@ -20,10 +19,18 @@ using namespace isc; using namespace isc::stats; -using namespace boost::posix_time; +using namespace std::chrono; namespace { +const StatsDuration& dur1234(hours(1) + minutes(2) + seconds(3) + + milliseconds(4)); +const StatsDuration& dur5678(hours(5) + minutes(6) + seconds(7) + + milliseconds(8)); +const StatsDuration& dur681012(hours(6) + minutes(8) + seconds(10) + + milliseconds(12)); +const StatsDuration& dur453(minutes(4) + seconds(5) + milliseconds(3)); + /// @brief Test class for Observation /// /// This simple fixture class initializes four observations: @@ -36,7 +43,7 @@ public: ObservationTest() : a("alpha", static_cast(1234)), // integer b("beta", 12.34), // float - c("gamma", millisec::time_duration(1, 2, 3, 4)), // duration + c("gamma", dur1234), // duration d("delta", "1234") { // string } @@ -56,8 +63,7 @@ TEST_F(ObservationTest, constructor) { EXPECT_EQ(1234, a.getInteger().first); EXPECT_EQ(12.34, b.getFloat().first); - EXPECT_EQ(millisec::time_duration(1, 2, 3, 4), - c.getDuration().first); + EXPECT_EQ(dur1234, c.getDuration().first); EXPECT_EQ("1234", d.getString().first); // Let's check that attempting to get a different type @@ -84,23 +90,23 @@ TEST_F(ObservationTest, constructor) { TEST_F(ObservationTest, setValue) { EXPECT_NO_THROW(a.setValue(static_cast(5678))); EXPECT_NO_THROW(b.setValue(56e+78)); - EXPECT_NO_THROW(c.setValue(millisec::time_duration(5, 6, 7, 8))); + EXPECT_NO_THROW(c.setValue(dur5678)); EXPECT_NO_THROW(d.setValue("fiveSixSevenEight")); EXPECT_EQ(5678, a.getInteger().first); EXPECT_EQ(56e+78, b.getFloat().first); - EXPECT_EQ(millisec::time_duration(5, 6, 7, 8), c.getDuration().first); + EXPECT_EQ(dur5678, c.getDuration().first); EXPECT_EQ("fiveSixSevenEight", d.getString().first); // Now check whether setting value to a different type does // throw an exception EXPECT_THROW(a.setValue(56e+78), InvalidStatType); - EXPECT_THROW(a.setValue(millisec::time_duration(5, 6, 7, 8)), InvalidStatType); + EXPECT_THROW(a.setValue(dur5678), InvalidStatType); EXPECT_THROW(a.setValue("fiveSixSevenEight"), InvalidStatType); EXPECT_THROW(b.setValue(static_cast(5678)), InvalidStatType); - EXPECT_THROW(b.setValue(millisec::time_duration(5, 6, 7, 8)), InvalidStatType); + EXPECT_THROW(b.setValue(dur5678), InvalidStatType); EXPECT_THROW(b.setValue("fiveSixSevenEight"), InvalidStatType); EXPECT_THROW(c.setValue(static_cast(5678)), InvalidStatType); @@ -109,7 +115,7 @@ TEST_F(ObservationTest, setValue) { EXPECT_THROW(d.setValue(static_cast(5678)), InvalidStatType); EXPECT_THROW(d.setValue(56e+78), InvalidStatType); - EXPECT_THROW(d.setValue(millisec::time_duration(5, 6, 7, 8)), InvalidStatType); + EXPECT_THROW(d.setValue(dur5678), InvalidStatType); } // This test checks whether it is possible to add value to existing @@ -120,12 +126,12 @@ TEST_F(ObservationTest, addValue) { EXPECT_NO_THROW(a.addValue(static_cast(5678))); EXPECT_NO_THROW(b.addValue(56.78)); - EXPECT_NO_THROW(c.addValue(millisec::time_duration(5, 6, 7, 8))); + EXPECT_NO_THROW(c.addValue(dur5678)); EXPECT_NO_THROW(d.addValue("fiveSixSevenEight")); EXPECT_EQ(6912, a.getInteger().first); EXPECT_EQ(69.12, b.getFloat().first); - EXPECT_EQ(millisec::time_duration(6, 8, 10, 12), c.getDuration().first); + EXPECT_EQ(dur681012, c.getDuration().first); EXPECT_EQ("1234fiveSixSevenEight", d.getString().first); ASSERT_EQ(a.getSize(), 2); @@ -140,18 +146,18 @@ TEST_F(ObservationTest, moreThanOne) { // Arrays of 4 types of samples int64_t int_samples[3] = {1234, 6912, 5678}; double float_samples[3] = {12.34, 69.12, 56e+78}; - millisec::time_duration duration_samples[3] = {millisec::time_duration(1, 2, 3, 4), - millisec::time_duration(6, 8, 10, 12), millisec::time_duration(5, 6, 7, 8)}; + StatsDuration duration_samples[3] = {dur1234, + dur681012, dur5678}; std::string string_samples[3] = {"1234", "1234fiveSixSevenEight", "fiveSixSevenEight"}; EXPECT_NO_THROW(a.addValue(static_cast(5678))); EXPECT_NO_THROW(b.addValue(56.78)); - EXPECT_NO_THROW(c.addValue(millisec::time_duration(5, 6, 7, 8))); + EXPECT_NO_THROW(c.addValue(dur5678)); EXPECT_NO_THROW(d.addValue("fiveSixSevenEight")); EXPECT_NO_THROW(a.setValue(static_cast(5678))); EXPECT_NO_THROW(b.setValue(56e+78)); - EXPECT_NO_THROW(c.setValue(millisec::time_duration(5, 6, 7, 8))); + EXPECT_NO_THROW(c.setValue(dur5678)); EXPECT_NO_THROW(d.setValue("fiveSixSevenEight")); ASSERT_EQ(a.getSize(), 3); @@ -203,7 +209,7 @@ TEST_F(ObservationTest, getSize) { a.addValue(static_cast(5678)); b.addValue(56.78); - c.addValue(millisec::time_duration(5, 6, 7, 8)); + c.addValue(dur5678); d.addValue("fiveSixSevenEight"); EXPECT_NO_THROW(a.getSize()); @@ -219,7 +225,7 @@ TEST_F(ObservationTest, getSize) { a.setValue(static_cast(5678)); b.setValue(56e+78); - c.setValue(millisec::time_duration(5, 6, 7, 8)); + c.setValue(dur5678); d.setValue("fiveSixSevenEight"); EXPECT_NO_THROW(a.getSize()); @@ -245,10 +251,10 @@ TEST_F(ObservationTest, setCountLimit) { std::string string_samples[22] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v"}; - millisec::time_duration duration_samples[22]; + StatsDuration duration_samples[22]; for (uint32_t i = 0; i < 22; ++i) { - duration_samples[i] = millisec::time_duration(0, 0, 0, i); + duration_samples[i] = milliseconds(i); } // By default the max_sample_count is set to 20 and max_sample_age @@ -355,7 +361,7 @@ TEST_F(ObservationTest, setCountLimit) { // Add new values to each type of Observation a.setValue(static_cast(21)); b.setValue(21.0); - c.setValue(millisec::time_duration(0, 0, 0, 21)); + c.setValue(milliseconds(21)); d.setValue("v"); samples_int = a.getIntegers(); @@ -394,29 +400,29 @@ TEST_F(ObservationTest, setCountLimit) { // Checks whether setting age limits works properly TEST_F(ObservationTest, setAgeLimit) { // Set max_sample_age to 1 second - ASSERT_NO_THROW(c.setMaxSampleAge(millisec::time_duration(0, 0, 1, 0))); + ASSERT_NO_THROW(c.setMaxSampleAge(seconds(1))); // Add some value - c.setValue(millisec::time_duration(0, 0, 0, 5)); + c.setValue(milliseconds(5)); // Wait 1 second sleep(1); // and add new value - c.setValue(millisec::time_duration(0, 0, 0, 3)); + c.setValue(milliseconds(3)); // get the list of all samples std::list samples_duration = c.getDurations(); // check whether the size of samples is equal to 1 ASSERT_EQ(c.getSize(), 1); // and whether it contains an expected value - EXPECT_EQ((*samples_duration.begin()).first, millisec::time_duration(0, 0, 0, 3)); + EXPECT_EQ((*samples_duration.begin()).first, milliseconds(3)); // Wait 1 second to ensure removing previously set value sleep(1); // add 10 new values for (uint32_t i = 0; i < 10; ++i) { - c.setValue(millisec::time_duration(0, 0, 0, i)); + c.setValue(milliseconds(i)); } // change the max_sample_age to smaller - ASSERT_NO_THROW(c.setMaxSampleAge(millisec::time_duration(0, 0, 0, 300))); + ASSERT_NO_THROW(c.setMaxSampleAge(milliseconds(300))); samples_duration = c.getDurations(); // check whether the size of samples is equal to 10 @@ -425,7 +431,7 @@ TEST_F(ObservationTest, setAgeLimit) { // and whether it contains expected values uint32_t i = 9; for (std::list::iterator it = samples_duration.begin(); it != samples_duration.end(); ++it) { - EXPECT_EQ((*it).first, millisec::time_duration(0, 0, 0, i)); + EXPECT_EQ((*it).first, milliseconds(i)); --i; } } @@ -450,20 +456,20 @@ TEST_F(ObservationTest, getLimits) { EXPECT_EQ(d.getMaxSampleCount().second, 20); // change limit to time duration - ASSERT_NO_THROW(a.setMaxSampleAge(millisec::time_duration(0, 4, 5, 3))); - ASSERT_NO_THROW(b.setMaxSampleAge(millisec::time_duration(0, 4, 5, 3))); - ASSERT_NO_THROW(c.setMaxSampleAge(millisec::time_duration(0, 4, 5, 3))); - ASSERT_NO_THROW(d.setMaxSampleAge(millisec::time_duration(0, 4, 5, 3))); + ASSERT_NO_THROW(a.setMaxSampleAge(dur453)); + ASSERT_NO_THROW(b.setMaxSampleAge(dur453)); + ASSERT_NO_THROW(c.setMaxSampleAge(dur453)); + ASSERT_NO_THROW(d.setMaxSampleAge(dur453)); EXPECT_EQ(a.getMaxSampleAge().first, true); EXPECT_EQ(b.getMaxSampleAge().first, true); EXPECT_EQ(c.getMaxSampleAge().first, true); EXPECT_EQ(d.getMaxSampleAge().first, true); - EXPECT_EQ(a.getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); - EXPECT_EQ(b.getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); - EXPECT_EQ(c.getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); - EXPECT_EQ(d.getMaxSampleAge().second, millisec::time_duration(0, 4, 5, 3)); + EXPECT_EQ(a.getMaxSampleAge().second, dur453); + EXPECT_EQ(b.getMaxSampleAge().second, dur453); + EXPECT_EQ(c.getMaxSampleAge().second, dur453); + EXPECT_EQ(d.getMaxSampleAge().second, dur453); EXPECT_EQ(a.getMaxSampleCount().first, false); EXPECT_EQ(b.getMaxSampleCount().first, false); @@ -480,12 +486,12 @@ TEST_F(ObservationTest, getLimits) { // Test checks whether timing is reported properly. TEST_F(ObservationTest, timers) { - ptime before = microsec_clock::local_time(); + auto before = SampleClock::now(); b.setValue(123.0); // Set it to a random value and record the time. // Allow a bit of imprecision. This test allows 500ms. That should be ok, // when running on virtual machines. - ptime after = before + milliseconds(500); + auto after = before + milliseconds(500); // Now wait some time. We want to confirm that the timestamp recorded is the // time the observation took place, not current time. @@ -505,12 +511,12 @@ TEST_F(ObservationTest, timers) { TEST_F(ObservationTest, integerToJSON) { // String which contains first added sample std::string first_sample = ", [ 1234, \"" + - isc::util::ptimeToText(a.getInteger().second) + "\" ] ]"; + isc::util::clockToText(a.getInteger().second) + "\" ] ]"; a.setValue(static_cast(1234)); std::string exp = "[ [ 1234, \"" + - isc::util::ptimeToText(a.getInteger().second) + "\" ]" + first_sample; + isc::util::clockToText(a.getInteger().second) + "\" ]" + first_sample; std::cout << a.getJSON()->str() << std::endl; EXPECT_EQ(exp, a.getJSON()->str()); @@ -523,7 +529,7 @@ TEST_F(ObservationTest, integerToJSON) { TEST_F(ObservationTest, floatToJSON) { // String which contains first added sample std::string first_sample = ", [ 12.34, \"" + - isc::util::ptimeToText(b.getFloat().second) + "\" ] ]"; + isc::util::clockToText(b.getFloat().second) + "\" ] ]"; // Let's use a value that converts easily to floating point. // No need to deal with infinite fractions in binary systems. @@ -531,7 +537,7 @@ TEST_F(ObservationTest, floatToJSON) { b.setValue(1234.5); std::string exp = "[ [ 1234.5, \"" + - isc::util::ptimeToText(b.getFloat().second) + "\" ]" + first_sample; + isc::util::clockToText(b.getFloat().second) + "\" ]" + first_sample; std::cout << b.getJSON()->str() << std::endl; EXPECT_EQ(exp, b.getJSON()->str()); @@ -542,14 +548,14 @@ TEST_F(ObservationTest, floatToJSON) { // details. TEST_F(ObservationTest, durationToJSON) { // String which contains first added sample - std::string first_sample = ", [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(c.getDuration().second) + "\" ] ]"; + std::string first_sample = ", [ \"01:02:03.004000\", \"" + + isc::util::clockToText(c.getDuration().second) + "\" ] ]"; // 1 hour 2 minutes 3 seconds and 4 milliseconds - c.setValue(time_duration(1, 2, 3, 4)); + c.setValue(dur1234); - std::string exp = "[ [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(c.getDuration().second) + "\" ]" + first_sample; + std::string exp = "[ [ \"01:02:03.004000\", \"" + + isc::util::clockToText(c.getDuration().second) + "\" ]" + first_sample; std::cout << c.getJSON()->str() << std::endl; EXPECT_EQ(exp, c.getJSON()->str()); @@ -561,12 +567,12 @@ TEST_F(ObservationTest, durationToJSON) { TEST_F(ObservationTest, stringToJSON) { // String which contains first added sample std::string first_sample = ", [ \"1234\", \"" + - isc::util::ptimeToText(d.getString().second) + "\" ] ]"; + isc::util::clockToText(d.getString().second) + "\" ] ]"; d.setValue("Lorem ipsum dolor sit amet"); std::string exp = "[ [ \"Lorem ipsum dolor sit amet\", \"" + - isc::util::ptimeToText(d.getString().second) + "\" ]" + first_sample; + isc::util::clockToText(d.getString().second) + "\" ]" + first_sample; std::cout << d.getJSON()->str() << std::endl; EXPECT_EQ(exp, d.getJSON()->str()); @@ -576,7 +582,7 @@ TEST_F(ObservationTest, stringToJSON) { TEST_F(ObservationTest, reset) { EXPECT_NO_THROW(a.addValue(static_cast(5678))); EXPECT_NO_THROW(b.addValue(56.78)); - EXPECT_NO_THROW(c.addValue(millisec::time_duration(5, 6, 7, 8))); + EXPECT_NO_THROW(c.addValue(dur5678)); EXPECT_NO_THROW(d.addValue("fiveSixSevenEight")); a.reset(); // integer @@ -586,7 +592,7 @@ TEST_F(ObservationTest, reset) { EXPECT_EQ(0, a.getInteger().first); EXPECT_EQ(0.0, b.getFloat().first); - EXPECT_EQ(time_duration(0, 0, 0, 0), c.getDuration().first); + EXPECT_EQ(StatsDuration::zero(), c.getDuration().first); EXPECT_EQ("", d.getString().first); ASSERT_EQ(a.getSize(), 1); diff --git a/src/lib/stats/tests/stats_mgr_unittest.cc b/src/lib/stats/tests/stats_mgr_unittest.cc index 178de72047..7a4f5d9077 100644 --- a/src/lib/stats/tests/stats_mgr_unittest.cc +++ b/src/lib/stats/tests/stats_mgr_unittest.cc @@ -10,8 +10,7 @@ #include #include #include -#include -#include +#include #include #include @@ -22,10 +21,16 @@ using namespace isc; using namespace isc::data; using namespace isc::stats; using namespace isc::config; -using namespace boost::posix_time; +using namespace std::chrono; namespace { +const StatsDuration& dur1234(hours(1) + minutes(2) + seconds(3) + + milliseconds(4)); +const StatsDuration& dur5678(hours(5) + minutes(6) + seconds(7) + + milliseconds(8)); +const StatsDuration& dur1245(hours(1) + minutes(2) + seconds(45)); + /// @brief Fixture class for StatsMgr testing /// /// Very simple class that makes sure that StatsMgr is indeed instantiated @@ -66,7 +71,7 @@ TEST_F(StatsMgrTest, integerStat) { ASSERT_TRUE(alpha); std::string exp = "{ \"alpha\": [ [ 1234, \"" + - isc::util::ptimeToText(alpha->getInteger().second) + "\" ] ] }"; + isc::util::clockToText(alpha->getInteger().second) + "\" ] ] }"; EXPECT_EQ(exp, StatsMgr::instance().get("alpha")->str()); } @@ -81,7 +86,7 @@ TEST_F(StatsMgrTest, floatStat) { ASSERT_TRUE(beta); std::string exp = "{ \"beta\": [ [ 12.34, \"" + - isc::util::ptimeToText(beta->getFloat().second) + "\" ] ] }"; + isc::util::clockToText(beta->getFloat().second) + "\" ] ] }"; EXPECT_EQ(exp, StatsMgr::instance().get("beta")->str()); } @@ -89,15 +94,14 @@ TEST_F(StatsMgrTest, floatStat) { // Test checks whether it's possible to record and later report // a duration statistic. TEST_F(StatsMgrTest, durationStat) { - EXPECT_NO_THROW(StatsMgr::instance().setValue("gamma", - microsec::time_duration(1, 2, 3, 4))); + EXPECT_NO_THROW(StatsMgr::instance().setValue("gamma", dur1234)); ObservationPtr gamma; EXPECT_NO_THROW(gamma = StatsMgr::instance().getObservation("gamma")); ASSERT_TRUE(gamma); - std::string exp = "{ \"gamma\": [ [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(gamma->getDuration().second) + "\" ] ] }"; + std::string exp = "{ \"gamma\": [ [ \"01:02:03.004000\", \"" + + isc::util::clockToText(gamma->getDuration().second) + "\" ] ] }"; EXPECT_EQ(exp, StatsMgr::instance().get("gamma")->str()); } @@ -113,7 +117,7 @@ TEST_F(StatsMgrTest, stringStat) { ASSERT_TRUE(delta); std::string exp = "{ \"delta\": [ [ \"Lorem ipsum\", \"" + - isc::util::ptimeToText(delta->getString().second) + "\" ] ] }"; + isc::util::clockToText(delta->getString().second) + "\" ] ] }"; EXPECT_EQ(exp, StatsMgr::instance().get("delta")->str()); } @@ -122,7 +126,7 @@ TEST_F(StatsMgrTest, stringStat) { TEST_F(StatsMgrTest, getSize) { StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", microsec::time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); EXPECT_NO_THROW(StatsMgr::instance().getSize("alpha")); @@ -142,7 +146,7 @@ TEST_F(StatsMgrTest, setLimits) { StatsMgr::instance().setValue("foo", static_cast(1)); EXPECT_NO_THROW(StatsMgr::instance().setMaxSampleAge("foo", - time_duration(0, 0, 1, 0))); + seconds(1))); for (uint32_t i = 0; i < 10; ++i) { if (i == 5) { @@ -167,31 +171,31 @@ TEST_F(StatsMgrTest, setLimitsAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // check the setting of time limit to existing statistics - EXPECT_NO_THROW(StatsMgr::instance().setMaxSampleAgeAll(time_duration(0, 0, 1, 0))); + EXPECT_NO_THROW(StatsMgr::instance().setMaxSampleAgeAll(seconds(1))); // check if time limit was set properly and whether count limit is disabled EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().second, - time_duration(0, 0, 1, 0)); + seconds(1)); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleAge().second, - time_duration(0, 0, 1, 0)); + seconds(1)); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleAge().second, - time_duration(0, 0, 1, 0)); + seconds(1)); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleAge().second, - time_duration(0, 0, 1, 0)); + seconds(1)); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleCount().first, false); // check the setting of count limit to existing statistics @@ -351,27 +355,27 @@ TEST_F(StatsMgrTest, getGetAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem"); // The string's representation of firstly added statistics std::string alpha_first = ", [ 1234, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + isc::util::clockToText(StatsMgr::instance().getObservation("alpha") ->getInteger().second) + "\" ] ]"; std::string beta_first = ", [ 12.34, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + isc::util::clockToText(StatsMgr::instance().getObservation("beta") ->getFloat().second) + "\" ] ]"; - std::string gamma_first = ", [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + std::string gamma_first = ", [ \"01:02:03.004000\", \"" + + isc::util::clockToText(StatsMgr::instance().getObservation("gamma") ->getDuration().second) + "\" ] ]"; std::string delta_first = ", [ \"Lorem\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + isc::util::clockToText(StatsMgr::instance().getObservation("delta") ->getString().second) + "\" ] ]"; // Now add some values to them StatsMgr::instance().addValue("alpha", static_cast(5678)); StatsMgr::instance().addValue("beta", 56.78); - StatsMgr::instance().addValue("gamma", time_duration(5, 6, 7, 8)); + StatsMgr::instance().addValue("gamma", dur5678); StatsMgr::instance().addValue("delta", " ipsum"); // There should be 4 statistics reported @@ -389,16 +393,16 @@ TEST_F(StatsMgrTest, getGetAll) { ASSERT_TRUE(rep_delta); std::string exp_str_alpha = "[ [ 6912, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + isc::util::clockToText(StatsMgr::instance().getObservation("alpha") ->getInteger().second) + "\" ]" + alpha_first; std::string exp_str_beta = "[ [ 69.12, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + isc::util::clockToText(StatsMgr::instance().getObservation("beta") ->getFloat().second) + "\" ]" + beta_first; - std::string exp_str_gamma = "[ [ \"06:08:10.000012\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + std::string exp_str_gamma = "[ [ \"06:08:10.012000\", \"" + + isc::util::clockToText(StatsMgr::instance().getObservation("gamma") ->getDuration().second) + "\" ]" + gamma_first; std::string exp_str_delta = "[ [ \"Lorem ipsum\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + isc::util::clockToText(StatsMgr::instance().getObservation("delta") ->getString().second) + "\" ]" + delta_first; // Check that individual stats are reported properly @@ -434,7 +438,7 @@ TEST_F(StatsMgrTest, reset) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // This should reset alpha to 0 @@ -445,7 +449,7 @@ TEST_F(StatsMgrTest, reset) { // The other stats should remain untouched EXPECT_EQ(12.34, StatsMgr::instance().getObservation("beta")->getFloat().first); - EXPECT_EQ(time_duration(1, 2, 3, 4), + EXPECT_EQ(dur1234, StatsMgr::instance().getObservation("gamma")->getDuration().first); EXPECT_EQ("Lorem ipsum", StatsMgr::instance().getObservation("delta")->getString().first); @@ -456,7 +460,7 @@ TEST_F(StatsMgrTest, reset) { EXPECT_NO_THROW(StatsMgr::instance().reset("delta")); EXPECT_EQ(0.0, StatsMgr::instance().getObservation("beta")->getFloat().first); - EXPECT_EQ(time_duration(0, 0, 0, 0), + EXPECT_EQ(StatsDuration::zero(), StatsMgr::instance().getObservation("gamma")->getDuration().first); EXPECT_EQ("", StatsMgr::instance().getObservation("delta")->getString().first); @@ -470,7 +474,7 @@ TEST_F(StatsMgrTest, resetAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // This should reset alpha to 0 @@ -479,7 +483,7 @@ TEST_F(StatsMgrTest, resetAll) { StatsMgr::instance().getObservation("alpha")->getInteger().first); EXPECT_EQ(0.0, StatsMgr::instance().getObservation("beta")->getFloat().first); - EXPECT_EQ(time_duration(0, 0, 0, 0), + EXPECT_EQ(StatsDuration::zero(), StatsMgr::instance().getObservation("gamma")->getDuration().first); EXPECT_EQ("", StatsMgr::instance().getObservation("delta")->getString().first); @@ -493,7 +497,7 @@ TEST_F(StatsMgrTest, removeAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // This should reset alpha to 0 @@ -525,13 +529,13 @@ TEST_F(StatsMgrTest, DISABLED_performanceSingleAdd) { uint32_t cycles = 1000000; - ptime before = microsec_clock::local_time(); + auto before = SampleClock::now(); for (uint32_t i = 0; i < cycles; ++i) { StatsMgr::instance().addValue("metric1", 0.1 * i); } - ptime after = microsec_clock::local_time(); + auto after = SampleClock::now(); - time_duration dur = after - before; + auto dur = after - before; std::cout << "Incrementing a single statistic " << cycles << " times took: " << isc::util::durationToText(dur) << std::endl; @@ -547,13 +551,13 @@ TEST_F(StatsMgrTest, DISABLED_performanceSingleSet) { uint32_t cycles = 1000000; - ptime before = microsec_clock::local_time(); + auto before = SampleClock::now(); for (uint32_t i = 0; i < cycles; ++i) { StatsMgr::instance().setValue("metric1", 0.1 * i); } - ptime after = microsec_clock::local_time(); + auto after = SampleClock::now(); - time_duration dur = after - before; + auto dur = after - before; std::cout << "Setting a single statistic " << cycles << " times took: " << isc::util::durationToText(dur) << std::endl; @@ -577,13 +581,13 @@ TEST_F(StatsMgrTest, DISABLED_performanceMultipleAdd) { StatsMgr::instance().setValue(tmp.str(), static_cast(i)); } - ptime before = microsec_clock::local_time(); + auto before = SampleClock::now(); for (uint32_t i = 0; i < cycles; ++i) { StatsMgr::instance().addValue("metric1", static_cast(i)); } - ptime after = microsec_clock::local_time(); + auto after = SampleClock::now(); - time_duration dur = after - before; + auto dur = after - before; std::cout << "Incrementing one of " << stats << " statistics " << cycles << " times took: " << isc::util::durationToText(dur) << std::endl; @@ -607,13 +611,13 @@ TEST_F(StatsMgrTest, DISABLED_performanceMultipleSet) { StatsMgr::instance().setValue(tmp.str(), static_cast(i)); } - ptime before = microsec_clock::local_time(); + auto before = SampleClock::now(); for (uint32_t i = 0; i < cycles; ++i) { StatsMgr::instance().setValue("metric1", static_cast(i)); } - ptime after = microsec_clock::local_time(); + auto after = SampleClock::now(); - time_duration dur = after - before; + auto dur = after - before; std::cout << "Setting one of " << stats << " statistics " << cycles << " times took: " << isc::util::durationToText(dur) << std::endl; @@ -650,7 +654,7 @@ TEST_F(StatsMgrTest, commandStatisticGet) { ASSERT_TRUE(alpha); std::string exp = "{ \"alpha\": [ [ 1234, \"" + - isc::util::ptimeToText(alpha->getInteger().second) + "\" ] ] }"; + isc::util::clockToText(alpha->getInteger().second) + "\" ] ] }"; EXPECT_EQ("{ \"arguments\": " + exp + ", \"result\": 0 }", rsp->str()); } @@ -685,7 +689,7 @@ TEST_F(StatsMgrTest, commandGetAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // Now get them. They're used to generate expected output @@ -700,16 +704,16 @@ TEST_F(StatsMgrTest, commandGetAll) { ASSERT_TRUE(rep_delta); std::string exp_str_alpha = "[ [ 1234, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + isc::util::clockToText(StatsMgr::instance().getObservation("alpha") ->getInteger().second) + "\" ] ]"; std::string exp_str_beta = "[ [ 12.34, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + isc::util::clockToText(StatsMgr::instance().getObservation("beta") ->getFloat().second) + "\" ] ]"; - std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + std::string exp_str_gamma = "[ [ \"01:02:03.004000\", \"" + + isc::util::clockToText(StatsMgr::instance().getObservation("gamma") ->getDuration().second) + "\" ] ]"; std::string exp_str_delta = "[ [ \"Lorem ipsum\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + isc::util::clockToText(StatsMgr::instance().getObservation("delta") ->getString().second) + "\" ] ]"; // Check that all of them can be reported at once @@ -788,7 +792,7 @@ TEST_F(StatsMgrTest, commandResetAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // Now get them. They're used to generate expected output @@ -803,16 +807,16 @@ TEST_F(StatsMgrTest, commandResetAll) { ASSERT_TRUE(rep_delta); std::string exp_str_alpha = "[ [ 1234, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("alpha") + isc::util::clockToText(StatsMgr::instance().getObservation("alpha") ->getInteger().second) + "\" ] ]"; std::string exp_str_beta = "[ [ 12.34, \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("beta") + isc::util::clockToText(StatsMgr::instance().getObservation("beta") ->getFloat().second) + "\" ] ]"; - std::string exp_str_gamma = "[ [ \"01:02:03.000004\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("gamma") + std::string exp_str_gamma = "[ [ \"01:02:03.004000\", \"" + + isc::util::clockToText(StatsMgr::instance().getObservation("gamma") ->getDuration().second) + "\" ] ]"; std::string exp_str_delta = "[ [ \"Lorem ipsum\", \"" + - isc::util::ptimeToText(StatsMgr::instance().getObservation("delta") + isc::util::clockToText(StatsMgr::instance().getObservation("delta") ->getString().second) + "\" ] ]"; // Check that all of them can be reset at once @@ -829,7 +833,7 @@ TEST_F(StatsMgrTest, commandResetAll) { StatsMgr::instance().getObservation("alpha")->getInteger().first); EXPECT_EQ(0.0f, StatsMgr::instance().getObservation("beta")->getFloat().first); - EXPECT_EQ(time_duration(0, 0, 0, 0), + EXPECT_EQ(StatsDuration::zero(), StatsMgr::instance().getObservation("gamma")->getDuration().first); EXPECT_EQ("", StatsMgr::instance().getObservation("delta")->getString().first); @@ -884,7 +888,7 @@ TEST_F(StatsMgrTest, commandRemoveAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); // Check that all of them can be reset at once @@ -909,7 +913,7 @@ TEST_F(StatsMgrTest, commandSetMaxSampleAge) { ElementPtr params = Element::createMap(); params->set("name", Element::create("alpha")); - params->set("duration", Element::create(1245)); // time_duration(0, 20, 45, 0) + params->set("duration", Element::create(1245)); // minutes(20) + seconds(45) ConstElementPtr rsp = StatsMgr::instance().statisticSetMaxSampleAgeHandler("statistic-sample-age-set", params); @@ -920,7 +924,7 @@ TEST_F(StatsMgrTest, commandSetMaxSampleAge) { // check if time limit was set properly and whether count limit is disabled EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().second, - time_duration(0, 20, 45, 0)); + minutes(20) + seconds(45)); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleCount().first, false); } @@ -962,11 +966,11 @@ TEST_F(StatsMgrTest, commandSetMaxSampleAgeAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); ElementPtr params = Element::createMap(); - params->set("duration", Element::create(3765)); // time_duration(1, 2, 45, 0) + params->set("duration", Element::create(3765)); // dur1245 ConstElementPtr rsp = StatsMgr::instance().statisticSetMaxSampleAgeAllHandler(params); @@ -982,22 +986,22 @@ TEST_F(StatsMgrTest, commandSetMaxSampleAgeAll) { // check if time limit was set properly and whether count limit is disabled EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleAge().second, - time_duration(1, 2, 45, 0)); + dur1245); EXPECT_EQ(StatsMgr::instance().getObservation("alpha")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleAge().second, - time_duration(1, 2, 45, 0)); + dur1245); EXPECT_EQ(StatsMgr::instance().getObservation("beta")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleAge().second, - time_duration(1, 2, 45, 0)); + dur1245); EXPECT_EQ(StatsMgr::instance().getObservation("gamma")->getMaxSampleCount().first, false); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleAge().first, true); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleAge().second, - time_duration(1, 2, 45, 0)); + dur1245); EXPECT_EQ(StatsMgr::instance().getObservation("delta")->getMaxSampleCount().first, false); } @@ -1060,7 +1064,7 @@ TEST_F(StatsMgrTest, commandSetMaxSampleCountAll) { // Set a couple of statistics StatsMgr::instance().setValue("alpha", static_cast(1234)); StatsMgr::instance().setValue("beta", 12.34); - StatsMgr::instance().setValue("gamma", time_duration(1, 2, 3, 4)); + StatsMgr::instance().setValue("gamma", dur1234); StatsMgr::instance().setValue("delta", "Lorem ipsum"); ElementPtr params = Element::createMap(); diff --git a/src/lib/util/Makefile.am b/src/lib/util/Makefile.am index 14319e9e9d..ceced193b5 100644 --- a/src/lib/util/Makefile.am +++ b/src/lib/util/Makefile.am @@ -9,6 +9,7 @@ AM_CXXFLAGS = $(KEA_CXXFLAGS) lib_LTLIBRARIES = libkea-util.la libkea_util_la_SOURCES = boost_time_utils.h boost_time_utils.cc libkea_util_la_SOURCES += buffer.h io_utilities.h +libkea_util_la_SOURCES += chrono_time_utils.h chrono_time_utils.cc libkea_util_la_SOURCES += csv_file.h csv_file.cc libkea_util_la_SOURCES += doubles.h libkea_util_la_SOURCES += filename.h filename.cc diff --git a/src/lib/util/chrono_time_utils.cc b/src/lib/util/chrono_time_utils.cc new file mode 100644 index 0000000000..f351397551 --- /dev/null +++ b/src/lib/util/chrono_time_utils.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include +#include + +using namespace std::chrono; + +std::string +isc::util::clockToText(system_clock::time_point t, size_t fsecs_precision) { + time_t tt = system_clock::to_time_t(t); + struct tm tm; + localtime_r(&tt, &tm); + std::stringstream s; + s << (tm.tm_year + 1900) + << "-" << std::setw(2) << std::setfill('0') << (tm.tm_mon + 1) + << "-" << std::setw(2) << std::setfill('0') << tm.tm_mday + << " " << std::setw(2) << std::setfill('0') << tm.tm_hour + << ":" << std::setw(2) << std::setfill('0') << tm.tm_min + << ":" << std::setw(2) << std::setfill('0') << tm.tm_sec; + + // If the requested precision is less than the maximum native precision + // we will divide the fractional seconds value by 10^(max - requested) + if (fsecs_precision) { + microseconds frac = t - system_clock::from_time_t(tt); + auto fsecs = frac.count(); + size_t width = MAX_FSECS_PRECISION; + if (fsecs_precision < width) { + for (auto i = 0; i < width - fsecs_precision; ++i) { + fsecs /= 10; + } + + width = fsecs_precision; + } + + s << "." << std::setw(width) + << std::setfill('0') + << fsecs; + } + + return (s.str()); +} + +std::string +isc::util::durationToText(system_clock::duration dur, size_t fsecs_precision) { + seconds unfrac = duration_cast(dur); + auto secs = unfrac.count(); + std::stringstream s; + auto hours = secs / 3600; + secs -= hours * 3600; + s << std::setw(2) << std::setfill('0') << hours; + auto mins = secs / 60; + secs -= mins * 60; + s << ":" << std::setw(2) << std::setfill('0') << mins + << ":" << std::setw(2) << std::setfill('0') << secs; + + // If the requested precision is less than the maximum native precision + // we will divide the fractional seconds value by 10^(max - requested) + if (fsecs_precision) { + microseconds frac = dur - unfrac; + auto fsecs = frac.count(); + size_t width = MAX_FSECS_PRECISION; + if (fsecs_precision < width) { + for (auto i = 0; i < width - fsecs_precision; ++i) { + fsecs /= 10; + } + + width = fsecs_precision; + } + + s << "." << std::setw(width) + << std::setfill('0') + << fsecs; + } + + return (s.str()); +} diff --git a/src/lib/util/chrono_time_utils.h b/src/lib/util/chrono_time_utils.h new file mode 100644 index 0000000000..cfcecccb8c --- /dev/null +++ b/src/lib/util/chrono_time_utils.h @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef KEA_CHRONO_TIME_UTILS_H +#define KEA_CHRONO_TIME_UTILS_H + +#include +#include + +namespace isc { +namespace util { + +/// @brief The number of digits of fractional seconds supplied by the +/// underlying class, std::chrono::time_point. Typically 6 = microseconds. +const size_t MAX_FSECS_PRECISION = 6; + +/// @brief Converts chrono time point structure to text +/// +/// This is Kea implementation for converting time point to strings. +/// @param t time point value to convert to text +/// @param fsecs_precision number of digits of precision for fractional seconds. +/// Zero omits the value. +/// +/// @return a string representing time +std::string clockToText(std::chrono::system_clock::time_point t, + size_t fsecs_precision = MAX_FSECS_PRECISION); + +/// @brief Converts StatsDuration to text +/// +/// See @ref clockToText for explanation why we chose our own implementation. +/// @param dur duration value to convert to text +/// @param fsecs_precision number of digits of precision for fractional seconds. +/// Zero omits the value. +/// +/// @return a string representing time +std::string durationToText(std::chrono::system_clock::duration, + size_t fsecs_precision = MAX_FSECS_PRECISION); + +}; // end of isc::util namespace +}; // end of isc namespace + +#endif diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am index a5668e3334..b04d07278f 100644 --- a/src/lib/util/tests/Makefile.am +++ b/src/lib/util/tests/Makefile.am @@ -32,6 +32,7 @@ run_unittests_SOURCES += base32hex_unittest.cc run_unittests_SOURCES += base64_unittest.cc run_unittests_SOURCES += boost_time_utils_unittest.cc run_unittests_SOURCES += buffer_unittest.cc +run_unittests_SOURCES += chrono_time_utils_unittest.cc run_unittests_SOURCES += csv_file_unittest.cc run_unittests_SOURCES += doubles_unittest.cc run_unittests_SOURCES += fd_share_tests.cc diff --git a/src/lib/util/tests/chrono_time_utils_unittest.cc b/src/lib/util/tests/chrono_time_utils_unittest.cc new file mode 100644 index 0000000000..a0ed42f36d --- /dev/null +++ b/src/lib/util/tests/chrono_time_utils_unittest.cc @@ -0,0 +1,147 @@ +// Copyright (C) 2015-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +#include + +#include + +using namespace std; +using namespace std::chrono; +using namespace isc::util; + +/// Check the clockToText() function returns a numeric month. +TEST(ChronoTimeUtilsTest, epoch) { + // The system clock is a wall clock using the local time zone so + // the epoch is zero only at some places or of course if the + // system is in UTC... + struct tm epoch; + memset(&epoch, 0, sizeof(epoch)); + epoch.tm_year = 70; + epoch.tm_mday = 1; + time_t tepoch = timelocal(&epoch); + system_clock::time_point pepoch = system_clock::from_time_t(tepoch); + + // We're going to loop through precision values starting with 0 through + // the max supported precision. Each pass should after the first, should + // add an additional level of precision: secs, secs/10, secs/100, + // secs/1000 and so on. The initial string has no fraction seconds. + std::string expected("1970-01-01 00:00:00"); + std::string sepoch; + for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) { + if (precision == 1) { + // Adding fractional seconds so we need append a decimal point. + expected.push_back('.'); + } + + if (precision >= 1) { + // Adding an additional level of precision, append a zero. + expected.push_back('0'); + } + + // Now let's see if we get the correct precision in the text. + sepoch = clockToText(pepoch, precision); + EXPECT_EQ(expected, sepoch) << " test precision:" << precision; + } + + // Expected string should have same precision as default, so + // test the default. + sepoch = clockToText(pepoch); + EXPECT_EQ(expected, sepoch); + + // Now test a requested precision beyond default. We should + // get the default precision. + sepoch = clockToText(pepoch, MAX_FSECS_PRECISION + 1); + EXPECT_EQ(expected, sepoch); + +} + +/// Check the durationToText() works as expected. +/// Note durationToText() is not called by clockToText(). +TEST(ChronoTimeUtilsTest, duration) { + system_clock::duration p123 = hours(1) + minutes(2) + seconds(3); + + // We're going to loop through precision values starting with 0 through + // the max supported precision. Each pass should after the first, should + // add an additional level of precision: secs, secs/10, secs/100, + // secs/1000 and so on. The initial string has no fraction seconds. + std::string expected("01:02:03"); + std::string s123; + for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) { + if (precision == 1) { + // Adding fractional seconds so we need append a decimal point. + expected.push_back('.'); + } + + if (precision >= 1) { + // Adding an additional level of precision, append a zero. + expected.push_back('0'); + } + + // Now let's see if we get the correct precision in the text. + s123 = durationToText(p123, precision); + EXPECT_EQ(expected, s123) << " test precision:" << precision; + } + + // Expected string should have same precision as default, so + // test the default. + s123 = durationToText(p123); + EXPECT_EQ(expected, s123); + + // Now test a requested precision beyond default. We should + // get the default precision. + s123 = durationToText(p123, MAX_FSECS_PRECISION + 1); + EXPECT_EQ(expected, s123); +} + +// The 2015 Bastille day +TEST(ChronoTimeUtilsTest, bastilleDay) { + struct tm tm; + tm.tm_year = 2015 - 1900; + tm.tm_mon = 7 - 1; + tm.tm_mday = 14; + tm.tm_hour = 12; + tm.tm_min = 13; + tm.tm_sec = 14; + time_t tbast = timelocal(&tm); + system_clock::time_point tpbast = system_clock::from_time_t(tbast); + tpbast += milliseconds(500); + + // We're going to loop through precision values starting with 0 through + // the max supported precision. Each pass should after the first, should + // add an additional level of precision: secs, secs/10, secs/100, + // secs/1000 and so on. The initial string has no fraction seconds. + std::string expected("2015-07-14 12:13:14"); + std::string sbast; + for (int precision = 0; precision <= MAX_FSECS_PRECISION; ++precision) { + if (precision == 1) { + // Adding fractional seconds so we need append a decimal point + // and the digit 5 (i.e. 500 ms = .5 secs). + expected.push_back('.'); + expected.push_back('5'); + } else if (precision > 1) { + // Adding an additional level of precision, append a zero. + expected.push_back('0'); + } + + // Now let's see if we get the correct precision in the text. + sbast = clockToText(tpbast, precision); + EXPECT_EQ(expected, sbast) << " test precision:" << precision; + } + + // Expected string should have same precision as default, so + // test the default. + sbast = clockToText(tpbast); + EXPECT_EQ(expected, sbast); + + // Now test a requested precision beyond default. We should + // get the default precision. + sbast = clockToText(tpbast, MAX_FSECS_PRECISION + 1); + EXPECT_EQ(expected, sbast); +}