2945f1fbca896b0d1589d23c75afe5be22427c52
[folly.git] / folly / io / async / test / TimeUtilTest.cpp
1 /*
2  * Copyright 2004-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <thread>
17
18 #include <glog/logging.h>
19
20 #include <folly/io/async/test/TimeUtil.h>
21 #include <folly/portability/GTest.h>
22 #include <folly/portability/Unistd.h>
23
24 using folly::TimePoint;
25 using namespace std::literals::chrono_literals;
26 using std::chrono::duration_cast;
27 using std::chrono::milliseconds;
28 using std::chrono::nanoseconds;
29 using std::chrono::steady_clock;
30
31 // Define a PrintTo() function for std::chrono::nanoseconds so that these
32 // will be printed nicely on EXPECT*() failures.
33 // Define this in std::chrono so that argument-dependent lookup works.
34 namespace std {
35 namespace chrono {
36 static inline void PrintTo(nanoseconds ns, ::std::ostream* os) {
37   *os << ns.count() << "ns";
38 }
39 }
40 }
41
42 #ifdef __linux__
43 void runThread(nanoseconds duration, nanoseconds* timeWaiting) {
44   TimePoint start;
45
46   // Loop consuming CPU until the duration has expired.
47   while (true) {
48     TimePoint now;
49     if (now.getTimeStart() - start.getTimeStart() > duration) {
50       // Time to quit
51       // Report how long we spent waiting to be scheduled on the CPU.
52       *timeWaiting = (now.getTimeWaiting() - start.getTimeWaiting());
53       VLOG(1) << "thread " << start.getTid() << ": elapsed "
54               << duration_cast<milliseconds>(
55                      now.getTimeStart() - start.getTimeStart())
56                      .count()
57               << "ms, time waiting: "
58               << duration_cast<milliseconds>(*timeWaiting).count() << "ms";
59       break;
60     }
61   }
62 }
63
64 // Test to make sure that TimePoint computes sane values for time
65 // spent waiting on CPU.
66 TEST(TimeUtil, getTimeWaiting) {
67   TimePoint tp;
68
69   // Run twice as many threads as CPU cores, to ensure that some of
70   // them should be waiting sometime.
71   auto numThreads = sysconf(_SC_NPROCESSORS_CONF) * 2;
72
73   std::vector<std::thread> threads;
74   std::vector<nanoseconds> timeWaiting;
75   timeWaiting.resize(numThreads, 0ns);
76
77   auto start = steady_clock::now();
78   for (int n = 0; n < numThreads; ++n) {
79     threads.emplace_back(runThread, 1s, &timeWaiting[n]);
80   }
81
82   for (auto& thread : threads) {
83     thread.join();
84   }
85   auto end = steady_clock::now();
86
87   auto timeSpent = end - start;
88   nanoseconds max{0};
89   for (int n = 0; n < numThreads; ++n) {
90     max = std::max(max, timeWaiting[n]);
91     // No thread could possibly have been waiting for longer than
92     // the test actually took to run.
93     EXPECT_LT(timeWaiting[n], timeSpent);
94   }
95   // Make sure that at least one thread spent some time waiting
96   EXPECT_GE(max, 1ns);
97 }
98 #endif