#include #include #include #include using namespace torch::monitor; TEST(MonitorTest, CounterDouble) { Stat a{ "a", {Aggregation::MEAN, Aggregation::COUNT}, std::chrono::milliseconds(100000), 2, }; a.add(5.0); ASSERT_EQ(a.count(), 1); a.add(6.0); ASSERT_EQ(a.count(), 0); auto stats = a.get(); std::unordered_map want = { {Aggregation::MEAN, 5.5}, {Aggregation::COUNT, 2.0}, }; ASSERT_EQ(stats, want); } TEST(MonitorTest, CounterInt64Sum) { Stat a{ "a", {Aggregation::SUM}, std::chrono::milliseconds(100000), 2, }; a.add(5); a.add(6); auto stats = a.get(); std::unordered_map want = { {Aggregation::SUM, 11}, }; ASSERT_EQ(stats, want); } TEST(MonitorTest, CounterInt64Value) { Stat a{ "a", {Aggregation::VALUE}, std::chrono::milliseconds(100000), 2, }; a.add(5); a.add(6); auto stats = a.get(); std::unordered_map want = { {Aggregation::VALUE, 6}, }; ASSERT_EQ(stats, want); } TEST(MonitorTest, CounterInt64Mean) { Stat a{ "a", {Aggregation::MEAN}, std::chrono::milliseconds(100000), 2, }; { // zero samples case auto stats = a.get(); std::unordered_map want = { {Aggregation::MEAN, 0}, }; ASSERT_EQ(stats, want); } a.add(0); a.add(10); { auto stats = a.get(); std::unordered_map want = { {Aggregation::MEAN, 5}, }; ASSERT_EQ(stats, want); } } TEST(MonitorTest, CounterInt64Count) { Stat a{ "a", {Aggregation::COUNT}, std::chrono::milliseconds(100000), 2, }; ASSERT_EQ(a.count(), 0); a.add(0); ASSERT_EQ(a.count(), 1); a.add(10); ASSERT_EQ(a.count(), 0); auto stats = a.get(); std::unordered_map want = { {Aggregation::COUNT, 2}, }; ASSERT_EQ(stats, want); } TEST(MonitorTest, CounterInt64MinMax) { Stat a{ "a", {Aggregation::MIN, Aggregation::MAX}, std::chrono::milliseconds(100000), 6, }; { auto stats = a.get(); std::unordered_map want = { {Aggregation::MAX, 0}, {Aggregation::MIN, 0}, }; ASSERT_EQ(stats, want); } a.add(0); a.add(5); a.add(-5); a.add(-6); a.add(9); a.add(2); { auto stats = a.get(); std::unordered_map want = { {Aggregation::MAX, 9}, {Aggregation::MIN, -6}, }; ASSERT_EQ(stats, want); } } TEST(MonitorTest, CounterInt64WindowSize) { Stat a{ "a", {Aggregation::COUNT, Aggregation::SUM}, std::chrono::milliseconds(100000), /*windowSize=*/3, }; a.add(1); a.add(2); ASSERT_EQ(a.count(), 2); a.add(3); ASSERT_EQ(a.count(), 0); // after logging max for window, should be zero a.add(4); ASSERT_EQ(a.count(), 0); auto stats = a.get(); std::unordered_map want = { {Aggregation::COUNT, 3}, {Aggregation::SUM, 6}, }; ASSERT_EQ(stats, want); } TEST(MonitorTest, CounterInt64WindowSizeHuge) { Stat a{ "a", {Aggregation::COUNT, Aggregation::SUM}, std::chrono::hours(24 * 365 * 10), // 10 years /*windowSize=*/3, }; a.add(1); a.add(2); ASSERT_EQ(a.count(), 2); a.add(3); ASSERT_EQ(a.count(), 0); // after logging max for window, should be zero a.add(4); ASSERT_EQ(a.count(), 0); auto stats = a.get(); std::unordered_map want = { {Aggregation::COUNT, 3}, {Aggregation::SUM, 6}, }; ASSERT_EQ(stats, want); } template struct TestStat : public Stat { uint64_t mockWindowId{1}; TestStat( std::string name, std::initializer_list aggregations, std::chrono::milliseconds windowSize, int64_t maxSamples = std::numeric_limits::max()) : Stat(name, aggregations, windowSize, maxSamples) {} uint64_t currentWindowId() const override { return mockWindowId; } }; struct AggregatingEventHandler : public EventHandler { std::vector events; void handle(const Event& e) override { events.emplace_back(e); } }; template struct HandlerGuard { std::shared_ptr handler; HandlerGuard() : handler(std::make_shared()) { registerEventHandler(handler); } ~HandlerGuard() { unregisterEventHandler(handler); } }; TEST(MonitorTest, Stat) { HandlerGuard guard; Stat a{ "a", {Aggregation::COUNT, Aggregation::SUM}, std::chrono::milliseconds(1), }; ASSERT_EQ(guard.handler->events.size(), 0); a.add(1); ASSERT_LE(a.count(), 1); std::this_thread::sleep_for(std::chrono::milliseconds(2)); a.add(2); ASSERT_LE(a.count(), 1); ASSERT_GE(guard.handler->events.size(), 1); ASSERT_LE(guard.handler->events.size(), 2); } TEST(MonitorTest, StatEvent) { HandlerGuard guard; TestStat a{ "a", {Aggregation::COUNT, Aggregation::SUM}, std::chrono::milliseconds(1), }; ASSERT_EQ(guard.handler->events.size(), 0); a.add(1); ASSERT_EQ(a.count(), 1); a.add(2); ASSERT_EQ(a.count(), 2); ASSERT_EQ(guard.handler->events.size(), 0); a.mockWindowId = 100; a.add(3); ASSERT_LE(a.count(), 1); ASSERT_EQ(guard.handler->events.size(), 1); Event e = guard.handler->events.at(0); ASSERT_EQ(e.name, "torch.monitor.Stat"); ASSERT_NE(e.timestamp, std::chrono::system_clock::time_point{}); std::unordered_map data{ {"a.sum", 3L}, {"a.count", 2L}, }; ASSERT_EQ(e.data, data); } TEST(MonitorTest, StatEventDestruction) { HandlerGuard guard; { TestStat a{ "a", {Aggregation::COUNT, Aggregation::SUM}, std::chrono::hours(10), }; a.add(1); ASSERT_EQ(a.count(), 1); ASSERT_EQ(guard.handler->events.size(), 0); } ASSERT_EQ(guard.handler->events.size(), 1); Event e = guard.handler->events.at(0); ASSERT_EQ(e.name, "torch.monitor.Stat"); ASSERT_NE(e.timestamp, std::chrono::system_clock::time_point{}); std::unordered_map data{ {"a.sum", 1L}, {"a.count", 1L}, }; ASSERT_EQ(e.data, data); }