Commit e6c19c13 authored by Emanuele Altieri's avatar Emanuele Altieri Committed by Facebook GitHub Bot

Fix flaky unit test for ThreadPoolExecutor CPU counter

Summary:
Using a per-thread CPU clock when burning CPU time (instead of the system
clock), so measurements should be accurate independently of the load on the
system.

Reviewed By: yfeldblum

Differential Revision: D31436995

fbshipit-source-id: 3e732e2f4d2c04846dcafef32b00a87617c940b8
parent 4bd3e4e0
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <folly/executors/thread_factory/InitThreadFactory.h> #include <folly/executors/thread_factory/InitThreadFactory.h>
#include <folly/executors/thread_factory/PriorityThreadFactory.h> #include <folly/executors/thread_factory/PriorityThreadFactory.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#include <folly/portability/PThread.h>
#include <folly/synchronization/detail/Spin.h> #include <folly/synchronization/detail/Spin.h>
using namespace folly; using namespace folly;
...@@ -56,18 +57,23 @@ static Func burnMs(uint64_t ms) { ...@@ -56,18 +57,23 @@ static Func burnMs(uint64_t ms) {
return [ms]() { std::this_thread::sleep_for(milliseconds(ms)); }; return [ms]() { std::this_thread::sleep_for(milliseconds(ms)); };
} }
#ifdef __linux__
static std::chrono::nanoseconds thread_clock_now() {
timespec tp;
clockid_t clockid;
CHECK(!pthread_getcpuclockid(pthread_self(), &clockid));
CHECK(!clock_gettime(clockid, &tp));
return std::chrono::nanoseconds(tp.tv_nsec) + std::chrono::seconds(tp.tv_sec);
}
// Loop and burn cpu cycles // Loop and burn cpu cycles
FOLLY_MAYBE_UNUSED static void burnThreadCpu(milliseconds ms) {
static void busyLoopFor(milliseconds ms) { auto expires = thread_clock_now() + ms;
using clock = high_resolution_clock; while (thread_clock_now() < expires) {
auto expires = clock::now() + ms;
while (clock::now() < expires) {
// (we want to burn cpu time)
} }
} }
// Loop without using much cpu time // Loop without using much cpu time
FOLLY_MAYBE_UNUSED
static void idleLoopFor(milliseconds ms) { static void idleLoopFor(milliseconds ms) {
using clock = high_resolution_clock; using clock = high_resolution_clock;
auto expires = clock::now() + ms; auto expires = clock::now() + ms;
...@@ -75,6 +81,7 @@ static void idleLoopFor(milliseconds ms) { ...@@ -75,6 +81,7 @@ static void idleLoopFor(milliseconds ms) {
/* sleep override */ std::this_thread::sleep_for(100ms); /* sleep override */ std::this_thread::sleep_for(100ms);
} }
} }
#endif
static WorkerProvider* kWorkerProviderGlobal = nullptr; static WorkerProvider* kWorkerProviderGlobal = nullptr;
...@@ -354,7 +361,7 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) { ...@@ -354,7 +361,7 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) {
// get busy // get busy
Latch latch(4); Latch latch(4);
auto busy_loop = [&] { auto busy_loop = [&] {
busyLoopFor(1s); burnThreadCpu(1s);
latch.count_down(); latch.count_down();
}; };
auto idle_loop = [&] { auto idle_loop = [&] {
...@@ -386,7 +393,7 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) { ...@@ -386,7 +393,7 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) {
// now burn some more cycles // now burn some more cycles
baton.reset(); baton.reset();
e.add([&] { e.add([&] {
busyLoopFor(500ms); burnThreadCpu(500ms);
baton.post(); baton.post();
}); });
baton.wait(); baton.wait();
...@@ -400,7 +407,9 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) { ...@@ -400,7 +407,9 @@ TEST(ThreadPoolExecutorTest, GetUsedCpuTime) {
ASSERT_EQ(e.getUsedCpuTime(), nanoseconds(0)); ASSERT_EQ(e.getUsedCpuTime(), nanoseconds(0));
Baton<> baton; Baton<> baton;
e.add([&] { e.add([&] {
busyLoopFor(500ms); auto expires = steady_clock::now() + 500ms;
while (steady_clock::now() < expires) {
}
baton.post(); baton.post();
}); });
baton.wait(); baton.wait();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment