14dc3bcf0SChia-hung Duan //===-- timing_test.cpp -----------------------------------------*- C++ -*-===// 24dc3bcf0SChia-hung Duan // 34dc3bcf0SChia-hung Duan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44dc3bcf0SChia-hung Duan // See https://llvm.org/LICENSE.txt for license information. 54dc3bcf0SChia-hung Duan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64dc3bcf0SChia-hung Duan // 74dc3bcf0SChia-hung Duan //===----------------------------------------------------------------------===// 84dc3bcf0SChia-hung Duan 94dc3bcf0SChia-hung Duan #include "tests/scudo_unit_test.h" 104dc3bcf0SChia-hung Duan 114dc3bcf0SChia-hung Duan #include "timing.h" 124dc3bcf0SChia-hung Duan 1341de50b7SChristopher Ferris #include <cstdlib> 144dc3bcf0SChia-hung Duan #include <string> 154dc3bcf0SChia-hung Duan 164dc3bcf0SChia-hung Duan class ScudoTimingTest : public Test { 174dc3bcf0SChia-hung Duan public: 184dc3bcf0SChia-hung Duan void testFunc1() { scudo::ScopedTimer ST(Manager, __func__); } 194dc3bcf0SChia-hung Duan 204dc3bcf0SChia-hung Duan void testFunc2() { 214dc3bcf0SChia-hung Duan scudo::ScopedTimer ST(Manager, __func__); 224dc3bcf0SChia-hung Duan testFunc1(); 234dc3bcf0SChia-hung Duan } 244dc3bcf0SChia-hung Duan 254dc3bcf0SChia-hung Duan void testChainedCalls() { 264dc3bcf0SChia-hung Duan scudo::ScopedTimer ST(Manager, __func__); 274dc3bcf0SChia-hung Duan testFunc2(); 284dc3bcf0SChia-hung Duan } 294dc3bcf0SChia-hung Duan 304dc3bcf0SChia-hung Duan void testIgnoredTimer() { 314dc3bcf0SChia-hung Duan scudo::ScopedTimer ST(Manager, __func__); 324dc3bcf0SChia-hung Duan ST.ignore(); 334dc3bcf0SChia-hung Duan } 344dc3bcf0SChia-hung Duan 354dc3bcf0SChia-hung Duan void printAllTimersStats() { Manager.printAll(); } 364dc3bcf0SChia-hung Duan 3741de50b7SChristopher Ferris void getAllTimersStats(scudo::ScopedString &Str) { Manager.getAll(Str); } 3841de50b7SChristopher Ferris 394dc3bcf0SChia-hung Duan scudo::TimingManager &getTimingManager() { return Manager; } 404dc3bcf0SChia-hung Duan 4141de50b7SChristopher Ferris void testCallTimers() { 4241de50b7SChristopher Ferris scudo::ScopedTimer Outer(getTimingManager(), "Level1"); 4341de50b7SChristopher Ferris { 4441de50b7SChristopher Ferris scudo::ScopedTimer Inner1(getTimingManager(), Outer, "Level2"); 4541de50b7SChristopher Ferris { scudo::ScopedTimer Inner2(getTimingManager(), Inner1, "Level3"); } 4641de50b7SChristopher Ferris } 4741de50b7SChristopher Ferris } 4841de50b7SChristopher Ferris 494dc3bcf0SChia-hung Duan private: 504dc3bcf0SChia-hung Duan scudo::TimingManager Manager; 514dc3bcf0SChia-hung Duan }; 524dc3bcf0SChia-hung Duan 534dc3bcf0SChia-hung Duan TEST_F(ScudoTimingTest, SimpleTimer) { 544dc3bcf0SChia-hung Duan testIgnoredTimer(); 554dc3bcf0SChia-hung Duan testChainedCalls(); 5641de50b7SChristopher Ferris scudo::ScopedString Str; 5741de50b7SChristopher Ferris getAllTimersStats(Str); 584dc3bcf0SChia-hung Duan 5941de50b7SChristopher Ferris std::string Output(Str.data()); 6041de50b7SChristopher Ferris EXPECT_TRUE(Output.find("testIgnoredTimer (1)") == std::string::npos); 6141de50b7SChristopher Ferris EXPECT_TRUE(Output.find("testChainedCalls (1)") != std::string::npos); 6241de50b7SChristopher Ferris EXPECT_TRUE(Output.find("testFunc2 (1)") != std::string::npos); 6341de50b7SChristopher Ferris EXPECT_TRUE(Output.find("testFunc1 (1)") != std::string::npos); 644dc3bcf0SChia-hung Duan } 654dc3bcf0SChia-hung Duan 664dc3bcf0SChia-hung Duan TEST_F(ScudoTimingTest, NestedTimer) { 674dc3bcf0SChia-hung Duan { 684dc3bcf0SChia-hung Duan scudo::ScopedTimer Outer(getTimingManager(), "Outer"); 694dc3bcf0SChia-hung Duan { 704dc3bcf0SChia-hung Duan scudo::ScopedTimer Inner1(getTimingManager(), Outer, "Inner1"); 714dc3bcf0SChia-hung Duan { scudo::ScopedTimer Inner2(getTimingManager(), Inner1, "Inner2"); } 724dc3bcf0SChia-hung Duan } 734dc3bcf0SChia-hung Duan } 7441de50b7SChristopher Ferris scudo::ScopedString Str; 7541de50b7SChristopher Ferris getAllTimersStats(Str); 7641de50b7SChristopher Ferris 7741de50b7SChristopher Ferris std::string Output(Str.data()); 7841de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Outer (1)") != std::string::npos); 7941de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Inner1 (1)") != std::string::npos); 8041de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Inner2 (1)") != std::string::npos); 8141de50b7SChristopher Ferris } 8241de50b7SChristopher Ferris 8341de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyChainedTimerCalculations) { 8441de50b7SChristopher Ferris { 8541de50b7SChristopher Ferris scudo::ScopedTimer Outer(getTimingManager(), "Level1"); 8641de50b7SChristopher Ferris sleep(1); 8741de50b7SChristopher Ferris { 8841de50b7SChristopher Ferris scudo::ScopedTimer Inner1(getTimingManager(), Outer, "Level2"); 8941de50b7SChristopher Ferris sleep(2); 9041de50b7SChristopher Ferris { 9141de50b7SChristopher Ferris scudo::ScopedTimer Inner2(getTimingManager(), Inner1, "Level3"); 9241de50b7SChristopher Ferris sleep(3); 9341de50b7SChristopher Ferris } 9441de50b7SChristopher Ferris } 9541de50b7SChristopher Ferris } 9641de50b7SChristopher Ferris scudo::ScopedString Str; 9741de50b7SChristopher Ferris getAllTimersStats(Str); 9841de50b7SChristopher Ferris std::string Output(Str.data()); 9941de50b7SChristopher Ferris 10041de50b7SChristopher Ferris // Get the individual timer values for the average and maximum, then 10141de50b7SChristopher Ferris // verify that the timer values are being calculated properly. 10241de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 10341de50b7SChristopher Ferris char *end; 10441de50b7SChristopher Ferris unsigned long long Level1AvgNs = std::strtoull(Output.c_str(), &end, 10); 10541de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 10641de50b7SChristopher Ferris unsigned long long Level1MaxNs = std::strtoull(&end[6], &end, 10); 10741de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 10841de50b7SChristopher Ferris EXPECT_EQ(Level1AvgNs, Level1MaxNs); 10941de50b7SChristopher Ferris 11041de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 11141de50b7SChristopher Ferris unsigned long long Level2AvgNs = std::strtoull(Output.c_str(), &end, 10); 11241de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 11341de50b7SChristopher Ferris unsigned long long Level2MaxNs = std::strtoull(&end[6], &end, 10); 11441de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 11541de50b7SChristopher Ferris EXPECT_EQ(Level2AvgNs, Level2MaxNs); 11641de50b7SChristopher Ferris 11741de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 11841de50b7SChristopher Ferris unsigned long long Level3AvgNs = std::strtoull(Output.c_str(), &end, 10); 11941de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 12041de50b7SChristopher Ferris unsigned long long Level3MaxNs = std::strtoull(&end[6], &end, 10); 12141de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 12241de50b7SChristopher Ferris EXPECT_EQ(Level3AvgNs, Level3MaxNs); 12341de50b7SChristopher Ferris 12441de50b7SChristopher Ferris EXPECT_GT(Level1AvgNs, Level2AvgNs); 12541de50b7SChristopher Ferris EXPECT_GT(Level2AvgNs, Level3AvgNs); 12641de50b7SChristopher Ferris 12741de50b7SChristopher Ferris // The time for the first timer needs to be at least six seconds. 12841de50b7SChristopher Ferris EXPECT_GT(Level1AvgNs, 6000000000U); 12941de50b7SChristopher Ferris // The time for the second timer needs to be at least five seconds. 13041de50b7SChristopher Ferris EXPECT_GT(Level2AvgNs, 5000000000U); 13141de50b7SChristopher Ferris // The time for the third timer needs to be at least three seconds. 13241de50b7SChristopher Ferris EXPECT_GT(Level3AvgNs, 3000000000U); 13341de50b7SChristopher Ferris // The time between the first and second timer needs to be at least one 13441de50b7SChristopher Ferris // second. 13541de50b7SChristopher Ferris EXPECT_GT(Level1AvgNs - Level2AvgNs, 1000000000U); 13641de50b7SChristopher Ferris // The time between the second and third timer needs to be at least two 13741de50b7SChristopher Ferris // second. 13841de50b7SChristopher Ferris EXPECT_GT(Level2AvgNs - Level3AvgNs, 2000000000U); 13941de50b7SChristopher Ferris } 14041de50b7SChristopher Ferris 14141de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyMax) { 14241de50b7SChristopher Ferris for (size_t i = 0; i < 3; i++) { 14341de50b7SChristopher Ferris scudo::ScopedTimer Outer(getTimingManager(), "Level1"); 14441de50b7SChristopher Ferris sleep(1); 14541de50b7SChristopher Ferris } 14641de50b7SChristopher Ferris scudo::ScopedString Str; 14741de50b7SChristopher Ferris getAllTimersStats(Str); 14841de50b7SChristopher Ferris std::string Output(Str.data()); 14941de50b7SChristopher Ferris 15041de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 15141de50b7SChristopher Ferris char *end; 15241de50b7SChristopher Ferris unsigned long long AvgNs = std::strtoull(Output.c_str(), &end, 10); 15341de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 15441de50b7SChristopher Ferris unsigned long long MaxNs = std::strtoull(&end[6], &end, 10); 15541de50b7SChristopher Ferris ASSERT_TRUE(end != nullptr); 15641de50b7SChristopher Ferris 157*c4b7c47fSFabio D'Urso EXPECT_GE(MaxNs, AvgNs); 15841de50b7SChristopher Ferris } 15941de50b7SChristopher Ferris 16041de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyMultipleTimerCalls) { 16141de50b7SChristopher Ferris for (size_t i = 0; i < 5; i++) 16241de50b7SChristopher Ferris testCallTimers(); 16341de50b7SChristopher Ferris 16441de50b7SChristopher Ferris scudo::ScopedString Str; 16541de50b7SChristopher Ferris getAllTimersStats(Str); 16641de50b7SChristopher Ferris std::string Output(Str.data()); 16741de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Level1 (5)") != std::string::npos); 16841de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Level2 (5)") != std::string::npos); 16941de50b7SChristopher Ferris EXPECT_TRUE(Output.find("Level3 (5)") != std::string::npos); 17041de50b7SChristopher Ferris } 17141de50b7SChristopher Ferris 17241de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyHeader) { 17341de50b7SChristopher Ferris { scudo::ScopedTimer Outer(getTimingManager(), "Timer"); } 17441de50b7SChristopher Ferris scudo::ScopedString Str; 17541de50b7SChristopher Ferris getAllTimersStats(Str); 17641de50b7SChristopher Ferris 17741de50b7SChristopher Ferris std::string Output(Str.data()); 17841de50b7SChristopher Ferris std::string Header(Output.substr(0, Output.find('\n'))); 17941de50b7SChristopher Ferris EXPECT_EQ(Header, "-- Average Operation Time -- -- Maximum Operation Time -- " 18041de50b7SChristopher Ferris "-- Name (# of Calls) --"); 18141de50b7SChristopher Ferris } 18241de50b7SChristopher Ferris 18341de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyTimerFormat) { 18441de50b7SChristopher Ferris testCallTimers(); 18541de50b7SChristopher Ferris scudo::ScopedString Str; 18641de50b7SChristopher Ferris getAllTimersStats(Str); 18741de50b7SChristopher Ferris std::string Output(Str.data()); 18841de50b7SChristopher Ferris 18941de50b7SChristopher Ferris // Check the top level line, should look similar to: 19041de50b7SChristopher Ferris // 11718.0(ns) 11718(ns) Level1 (1) 19141de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 19241de50b7SChristopher Ferris 19341de50b7SChristopher Ferris // Verify that the Average Operation Time is in the correct location. 19441de50b7SChristopher Ferris EXPECT_EQ(".0(ns) ", Output.substr(14, 7)); 19541de50b7SChristopher Ferris 19641de50b7SChristopher Ferris // Verify that the Maximum Operation Time is in the correct location. 19741de50b7SChristopher Ferris EXPECT_EQ("(ns) ", Output.substr(45, 5)); 19841de50b7SChristopher Ferris 19941de50b7SChristopher Ferris // Verify that the first timer name is in the correct location. 20041de50b7SChristopher Ferris EXPECT_EQ("Level1 (1)\n", Output.substr(61, 11)); 20141de50b7SChristopher Ferris 20241de50b7SChristopher Ferris // Check a chained timer, should look similar to: 20341de50b7SChristopher Ferris // 5331.0(ns) 5331(ns) Level2 (1) 20441de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 20541de50b7SChristopher Ferris 20641de50b7SChristopher Ferris // Verify that the Average Operation Time is in the correct location. 20741de50b7SChristopher Ferris EXPECT_EQ(".0(ns) ", Output.substr(14, 7)); 20841de50b7SChristopher Ferris 20941de50b7SChristopher Ferris // Verify that the Maximum Operation Time is in the correct location. 21041de50b7SChristopher Ferris EXPECT_EQ("(ns) ", Output.substr(45, 5)); 21141de50b7SChristopher Ferris 21241de50b7SChristopher Ferris // Verify that the first timer name is in the correct location. 21341de50b7SChristopher Ferris EXPECT_EQ(" Level2 (1)\n", Output.substr(61, 13)); 21441de50b7SChristopher Ferris 21541de50b7SChristopher Ferris // Check a secondary chained timer, should look similar to: 21641de50b7SChristopher Ferris // 814.0(ns) 814(ns) Level3 (1) 21741de50b7SChristopher Ferris Output = Output.substr(Output.find('\n') + 1); 21841de50b7SChristopher Ferris 21941de50b7SChristopher Ferris // Verify that the Average Operation Time is in the correct location. 22041de50b7SChristopher Ferris EXPECT_EQ(".0(ns) ", Output.substr(14, 7)); 22141de50b7SChristopher Ferris 22241de50b7SChristopher Ferris // Verify that the Maximum Operation Time is in the correct location. 22341de50b7SChristopher Ferris EXPECT_EQ("(ns) ", Output.substr(45, 5)); 22441de50b7SChristopher Ferris 22541de50b7SChristopher Ferris // Verify that the first timer name is in the correct location. 22641de50b7SChristopher Ferris EXPECT_EQ(" Level3 (1)\n", Output.substr(61, 15)); 22741de50b7SChristopher Ferris } 2284dc3bcf0SChia-hung Duan 2294dc3bcf0SChia-hung Duan #if SCUDO_LINUX 23041de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyPrintMatchesGet) { 23141de50b7SChristopher Ferris testing::internal::LogToStderr(); 23241de50b7SChristopher Ferris testing::internal::CaptureStderr(); 23341de50b7SChristopher Ferris testCallTimers(); 23441de50b7SChristopher Ferris 23541de50b7SChristopher Ferris { scudo::ScopedTimer Outer(getTimingManager(), "Timer"); } 23641de50b7SChristopher Ferris printAllTimersStats(); 23741de50b7SChristopher Ferris std::string PrintOutput = testing::internal::GetCapturedStderr(); 23841de50b7SChristopher Ferris EXPECT_TRUE(PrintOutput.size() != 0); 23941de50b7SChristopher Ferris 24041de50b7SChristopher Ferris scudo::ScopedString Str; 24141de50b7SChristopher Ferris getAllTimersStats(Str); 24241de50b7SChristopher Ferris std::string GetOutput(Str.data()); 24341de50b7SChristopher Ferris EXPECT_TRUE(GetOutput.size() != 0); 24441de50b7SChristopher Ferris 24541de50b7SChristopher Ferris EXPECT_EQ(PrintOutput, GetOutput); 2464dc3bcf0SChia-hung Duan } 24741de50b7SChristopher Ferris #endif 24841de50b7SChristopher Ferris 24941de50b7SChristopher Ferris #if SCUDO_LINUX 25041de50b7SChristopher Ferris TEST_F(ScudoTimingTest, VerifyReporting) { 25141de50b7SChristopher Ferris testing::internal::LogToStderr(); 25241de50b7SChristopher Ferris testing::internal::CaptureStderr(); 25341de50b7SChristopher Ferris // Every 100 calls generates a report, but run a few extra to verify the 25441de50b7SChristopher Ferris // report happened at call 100. 25541de50b7SChristopher Ferris for (size_t i = 0; i < 110; i++) 25641de50b7SChristopher Ferris scudo::ScopedTimer Outer(getTimingManager(), "VerifyReportTimer"); 25741de50b7SChristopher Ferris 25841de50b7SChristopher Ferris std::string Output = testing::internal::GetCapturedStderr(); 25941de50b7SChristopher Ferris EXPECT_TRUE(Output.find("VerifyReportTimer (100)") != std::string::npos); 26041de50b7SChristopher Ferris } 26141de50b7SChristopher Ferris #endif 262