xref: /llvm-project/compiler-rt/lib/scudo/standalone/tests/timing_test.cpp (revision c4b7c47fa53ee6d75b64737d475e5dbd1ed4a409)
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