1010
1111#include " timing.h"
1212
13+ #include < cstdlib>
1314#include < string>
1415
1516class ScudoTimingTest : public Test {
@@ -33,54 +34,228 @@ class ScudoTimingTest : public Test {
3334
3435 void printAllTimersStats () { Manager.printAll (); }
3536
37+ void getAllTimersStats (scudo::ScopedString &Str) { Manager.getAll (Str); }
38+
3639 scudo::TimingManager &getTimingManager () { return Manager; }
3740
41+ void testCallTimers () {
42+ scudo::ScopedTimer Outer (getTimingManager (), " Level1" );
43+ {
44+ scudo::ScopedTimer Inner1 (getTimingManager (), Outer, " Level2" );
45+ { scudo::ScopedTimer Inner2 (getTimingManager (), Inner1, " Level3" ); }
46+ }
47+ }
48+
3849private:
3950 scudo::TimingManager Manager;
4051};
4152
42- // Given that the output of statistics of timers are dumped through
43- // `scudo::Printf` which is platform dependent, so we don't have a reliable way
44- // to catch the output and verify the details. Now we only verify the number of
45- // invocations on linux.
4653TEST_F (ScudoTimingTest, SimpleTimer) {
47- #if SCUDO_LINUX
48- testing::internal::LogToStderr ();
49- testing::internal::CaptureStderr ();
50- #endif
51-
5254 testIgnoredTimer ();
5355 testChainedCalls ();
54- printAllTimersStats ();
56+ scudo::ScopedString Str;
57+ getAllTimersStats (Str);
5558
56- #if SCUDO_LINUX
57- std::string output = testing::internal::GetCapturedStderr ();
58- EXPECT_TRUE (output.find (" testIgnoredTimer (1)" ) == std::string::npos);
59- EXPECT_TRUE (output.find (" testChainedCalls (1)" ) != std::string::npos);
60- EXPECT_TRUE (output.find (" testFunc2 (1)" ) != std::string::npos);
61- EXPECT_TRUE (output.find (" testFunc1 (1)" ) != std::string::npos);
62- #endif
59+ std::string Output (Str.data ());
60+ EXPECT_TRUE (Output.find (" testIgnoredTimer (1)" ) == std::string::npos);
61+ EXPECT_TRUE (Output.find (" testChainedCalls (1)" ) != std::string::npos);
62+ EXPECT_TRUE (Output.find (" testFunc2 (1)" ) != std::string::npos);
63+ EXPECT_TRUE (Output.find (" testFunc1 (1)" ) != std::string::npos);
6364}
6465
6566TEST_F (ScudoTimingTest, NestedTimer) {
66- #if SCUDO_LINUX
67- testing::internal::LogToStderr ();
68- testing::internal::CaptureStderr ();
69- #endif
70-
7167 {
7268 scudo::ScopedTimer Outer (getTimingManager (), " Outer" );
7369 {
7470 scudo::ScopedTimer Inner1 (getTimingManager (), Outer, " Inner1" );
7571 { scudo::ScopedTimer Inner2 (getTimingManager (), Inner1, " Inner2" ); }
7672 }
7773 }
78- printAllTimersStats ();
74+ scudo::ScopedString Str;
75+ getAllTimersStats (Str);
76+
77+ std::string Output (Str.data ());
78+ EXPECT_TRUE (Output.find (" Outer (1)" ) != std::string::npos);
79+ EXPECT_TRUE (Output.find (" Inner1 (1)" ) != std::string::npos);
80+ EXPECT_TRUE (Output.find (" Inner2 (1)" ) != std::string::npos);
81+ }
82+
83+ TEST_F (ScudoTimingTest, VerifyChainedTimerCalculations) {
84+ {
85+ scudo::ScopedTimer Outer (getTimingManager (), " Level1" );
86+ sleep (1 );
87+ {
88+ scudo::ScopedTimer Inner1 (getTimingManager (), Outer, " Level2" );
89+ sleep (2 );
90+ {
91+ scudo::ScopedTimer Inner2 (getTimingManager (), Inner1, " Level3" );
92+ sleep (3 );
93+ }
94+ }
95+ }
96+ scudo::ScopedString Str;
97+ getAllTimersStats (Str);
98+ std::string Output (Str.data ());
99+
100+ // Get the individual timer values for the average and maximum, then
101+ // verify that the timer values are being calculated properly.
102+ Output = Output.substr (Output.find (' \n ' ) + 1 );
103+ char *end;
104+ unsigned long long Level1AvgNs = std::strtoull (Output.c_str (), &end, 10 );
105+ ASSERT_TRUE (end != nullptr );
106+ unsigned long long Level1MaxNs = std::strtoull (&end[6 ], &end, 10 );
107+ ASSERT_TRUE (end != nullptr );
108+ EXPECT_EQ (Level1AvgNs, Level1MaxNs);
109+
110+ Output = Output.substr (Output.find (' \n ' ) + 1 );
111+ unsigned long long Level2AvgNs = std::strtoull (Output.c_str (), &end, 10 );
112+ ASSERT_TRUE (end != nullptr );
113+ unsigned long long Level2MaxNs = std::strtoull (&end[6 ], &end, 10 );
114+ ASSERT_TRUE (end != nullptr );
115+ EXPECT_EQ (Level2AvgNs, Level2MaxNs);
116+
117+ Output = Output.substr (Output.find (' \n ' ) + 1 );
118+ unsigned long long Level3AvgNs = std::strtoull (Output.c_str (), &end, 10 );
119+ ASSERT_TRUE (end != nullptr );
120+ unsigned long long Level3MaxNs = std::strtoull (&end[6 ], &end, 10 );
121+ ASSERT_TRUE (end != nullptr );
122+ EXPECT_EQ (Level3AvgNs, Level3MaxNs);
123+
124+ EXPECT_GT (Level1AvgNs, Level2AvgNs);
125+ EXPECT_GT (Level2AvgNs, Level3AvgNs);
126+
127+ // The time for the first timer needs to be at least six seconds.
128+ EXPECT_GT (Level1AvgNs, 6000000000U );
129+ // The time for the second timer needs to be at least five seconds.
130+ EXPECT_GT (Level2AvgNs, 5000000000U );
131+ // The time for the third timer needs to be at least three seconds.
132+ EXPECT_GT (Level3AvgNs, 3000000000U );
133+ // The time between the first and second timer needs to be at least one
134+ // second.
135+ EXPECT_GT (Level1AvgNs - Level2AvgNs, 1000000000U );
136+ // The time between the second and third timer needs to be at least two
137+ // second.
138+ EXPECT_GT (Level2AvgNs - Level3AvgNs, 2000000000U );
139+ }
140+
141+ TEST_F (ScudoTimingTest, VerifyMax) {
142+ for (size_t i = 0 ; i < 3 ; i++) {
143+ scudo::ScopedTimer Outer (getTimingManager (), " Level1" );
144+ sleep (1 );
145+ }
146+ scudo::ScopedString Str;
147+ getAllTimersStats (Str);
148+ std::string Output (Str.data ());
149+
150+ Output = Output.substr (Output.find (' \n ' ) + 1 );
151+ char *end;
152+ unsigned long long AvgNs = std::strtoull (Output.c_str (), &end, 10 );
153+ ASSERT_TRUE (end != nullptr );
154+ unsigned long long MaxNs = std::strtoull (&end[6 ], &end, 10 );
155+ ASSERT_TRUE (end != nullptr );
156+
157+ EXPECT_GT (MaxNs, AvgNs);
158+ }
159+
160+ TEST_F (ScudoTimingTest, VerifyMultipleTimerCalls) {
161+ for (size_t i = 0 ; i < 5 ; i++)
162+ testCallTimers ();
163+
164+ scudo::ScopedString Str;
165+ getAllTimersStats (Str);
166+ std::string Output (Str.data ());
167+ EXPECT_TRUE (Output.find (" Level1 (5)" ) != std::string::npos);
168+ EXPECT_TRUE (Output.find (" Level2 (5)" ) != std::string::npos);
169+ EXPECT_TRUE (Output.find (" Level3 (5)" ) != std::string::npos);
170+ }
171+
172+ TEST_F (ScudoTimingTest, VerifyHeader) {
173+ { scudo::ScopedTimer Outer (getTimingManager (), " Timer" ); }
174+ scudo::ScopedString Str;
175+ getAllTimersStats (Str);
176+
177+ std::string Output (Str.data ());
178+ std::string Header (Output.substr (0 , Output.find (' \n ' )));
179+ EXPECT_EQ (Header, " -- Average Operation Time -- -- Maximum Operation Time -- "
180+ " -- Name (# of Calls) --" );
181+ }
182+
183+ TEST_F (ScudoTimingTest, VerifyTimerFormat) {
184+ testCallTimers ();
185+ scudo::ScopedString Str;
186+ getAllTimersStats (Str);
187+ std::string Output (Str.data ());
188+
189+ // Check the top level line, should look similar to:
190+ // 11718.0(ns) 11718(ns) Level1 (1)
191+ Output = Output.substr (Output.find (' \n ' ) + 1 );
192+
193+ // Verify that the Average Operation Time is in the correct location.
194+ EXPECT_EQ (" .0(ns) " , Output.substr (14 , 7 ));
195+
196+ // Verify that the Maximum Operation Time is in the correct location.
197+ EXPECT_EQ (" (ns) " , Output.substr (45 , 5 ));
198+
199+ // Verify that the first timer name is in the correct location.
200+ EXPECT_EQ (" Level1 (1)\n " , Output.substr (61 , 11 ));
201+
202+ // Check a chained timer, should look similar to:
203+ // 5331.0(ns) 5331(ns) Level2 (1)
204+ Output = Output.substr (Output.find (' \n ' ) + 1 );
205+
206+ // Verify that the Average Operation Time is in the correct location.
207+ EXPECT_EQ (" .0(ns) " , Output.substr (14 , 7 ));
208+
209+ // Verify that the Maximum Operation Time is in the correct location.
210+ EXPECT_EQ (" (ns) " , Output.substr (45 , 5 ));
211+
212+ // Verify that the first timer name is in the correct location.
213+ EXPECT_EQ (" Level2 (1)\n " , Output.substr (61 , 13 ));
214+
215+ // Check a secondary chained timer, should look similar to:
216+ // 814.0(ns) 814(ns) Level3 (1)
217+ Output = Output.substr (Output.find (' \n ' ) + 1 );
218+
219+ // Verify that the Average Operation Time is in the correct location.
220+ EXPECT_EQ (" .0(ns) " , Output.substr (14 , 7 ));
221+
222+ // Verify that the Maximum Operation Time is in the correct location.
223+ EXPECT_EQ (" (ns) " , Output.substr (45 , 5 ));
224+
225+ // Verify that the first timer name is in the correct location.
226+ EXPECT_EQ (" Level3 (1)\n " , Output.substr (61 , 15 ));
227+ }
79228
80229#if SCUDO_LINUX
81- std::string output = testing::internal::GetCapturedStderr ();
82- EXPECT_TRUE (output.find (" Outer (1)" ) != std::string::npos);
83- EXPECT_TRUE (output.find (" Inner1 (1)" ) != std::string::npos);
84- EXPECT_TRUE (output.find (" Inner2 (1)" ) != std::string::npos);
230+ TEST_F (ScudoTimingTest, VerifyPrintMatchesGet) {
231+ testing::internal::LogToStderr ();
232+ testing::internal::CaptureStderr ();
233+ testCallTimers ();
234+
235+ { scudo::ScopedTimer Outer (getTimingManager (), " Timer" ); }
236+ printAllTimersStats ();
237+ std::string PrintOutput = testing::internal::GetCapturedStderr ();
238+ EXPECT_TRUE (PrintOutput.size () != 0 );
239+
240+ scudo::ScopedString Str;
241+ getAllTimersStats (Str);
242+ std::string GetOutput (Str.data ());
243+ EXPECT_TRUE (GetOutput.size () != 0 );
244+
245+ EXPECT_EQ (PrintOutput, GetOutput);
246+ }
85247#endif
248+
249+ #if SCUDO_LINUX
250+ TEST_F (ScudoTimingTest, VerifyReporting) {
251+ testing::internal::LogToStderr ();
252+ testing::internal::CaptureStderr ();
253+ // Every 100 calls generates a report, but run a few extra to verify the
254+ // report happened at call 100.
255+ for (size_t i = 0 ; i < 110 ; i++)
256+ scudo::ScopedTimer Outer (getTimingManager (), " VerifyReportTimer" );
257+
258+ std::string Output = testing::internal::GetCapturedStderr ();
259+ EXPECT_TRUE (Output.find (" VerifyReportTimer (100)" ) != std::string::npos);
86260}
261+ #endif
0 commit comments