diff options
author | brucedawson <brucedawson@chromium.org> | 2015-02-12 14:33:22 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-12 22:34:08 +0000 |
commit | aa3d0c59862b7adecafa3d962b073b29322deec9 (patch) | |
tree | 09994b721f37cc554179c79c9efbaa327f3d7204 | |
parent | 72e0856eb5934945142f1b10ac7f1ace76c6f837 (diff) | |
download | chromium_src-aa3d0c59862b7adecafa3d962b073b29322deec9.zip chromium_src-aa3d0c59862b7adecafa3d962b073b29322deec9.tar.gz chromium_src-aa3d0c59862b7adecafa3d962b073b29322deec9.tar.bz2 |
This change adds a LockThreadAffinity and uses it to
lock most threads of ipc_perftest and ipc_mojo_perftest
to a single core.
This is important because the different threads and
processes naturally end up on different cores and these
cores end up idle about 40% of the time, due to each
process waiting on the others. This confuses the power
management systems in Windows and Linux such that they
don't reliably ramp up the CPU speeds.
In extreme cases this can make these tests run ~3x slower
(at 1.2 GHz instead of at ~3.8 GHz).
In addition to running the tests more quickly the thread
affinity makes them much more consistent, which makes
measuring performance more scientific.
Setting the OS power plan to high-performance can also
help maximize performance and minimize variation.
Review URL: https://codereview.chromium.org/914403002
Cr-Commit-Position: refs/heads/master@{#316066}
-rw-r--r-- | ipc/ipc_perftest_support.cc | 39 | ||||
-rw-r--r-- | ipc/ipc_perftest_support.h | 21 |
2 files changed, 60 insertions, 0 deletions
diff --git a/ipc/ipc_perftest_support.cc b/ipc/ipc_perftest_support.cc index 0a6a03e..f8a11c5 100644 --- a/ipc/ipc_perftest_support.cc +++ b/ipc/ipc_perftest_support.cc @@ -26,6 +26,10 @@ namespace IPC { namespace test { +// Avoid core 0 due to conflicts with Intel's Power Gadget. +// Setting thread affinity will fail harmlessly on single/dual core machines. +const int kSharedCore = 2; + // This class simply collects stats about abstract "events" (each of which has a // start time and an end time). class EventTimeTracker { @@ -244,6 +248,7 @@ void IPCChannelPerfTestBase::RunTestChannelPingPong( ASSERT_TRUE(ConnectChannel()); ASSERT_TRUE(StartClient()); + LockThreadAffinity thread_locker(kSharedCore); for (size_t i = 0; i < params.size(); i++) { listener.SetTestParams(params[i].message_count(), params[i].message_size()); @@ -284,6 +289,7 @@ void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( listener.Init(channel_proxy()); ASSERT_TRUE(StartClient()); + LockThreadAffinity thread_locker(kSharedCore); for (size_t i = 0; i < params.size(); i++) { listener.SetTestParams(params[i].message_count(), params[i].message_size()); @@ -326,6 +332,7 @@ scoped_ptr<Channel> PingPongTestClient::CreateChannel( } int PingPongTestClient::RunMain() { + LockThreadAffinity thread_locker(kSharedCore); scoped_ptr<Channel> channel = CreateChannel(listener_.get()); listener_->Init(channel.get()); CHECK(channel->Connect()); @@ -338,5 +345,37 @@ scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() { return main_message_loop_.message_loop_proxy(); } +LockThreadAffinity::LockThreadAffinity(int cpu_number) + : affinity_set_ok_(false) { +#if defined(OS_WIN) + const DWORD_PTR thread_mask = 1 << cpu_number; + old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask); + affinity_set_ok_ = old_affinity_ != 0; +#elif defined(OS_LINUX) + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu_number, &cpuset); + auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_); + DCHECK_EQ(0, get_result); + auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset); + // Check for get_result failure, even though it should always succeed. + affinity_set_ok_ = (set_result == 0) && (get_result == 0); +#endif + if (!affinity_set_ok_) + LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number; +} + +LockThreadAffinity::~LockThreadAffinity() { + if (!affinity_set_ok_) + return; +#if defined(OS_WIN) + auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_); + DCHECK_NE(0u, set_result); +#elif defined(OS_LINUX) + auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_); + DCHECK_EQ(0, set_result); +#endif +} + } // namespace test } // namespace IPC diff --git a/ipc/ipc_perftest_support.h b/ipc/ipc_perftest_support.h index 611a209..578256f 100644 --- a/ipc/ipc_perftest_support.h +++ b/ipc/ipc_perftest_support.h @@ -53,6 +53,27 @@ class PingPongTestClient { scoped_ptr<Channel> channel_; }; +// This class locks the current thread to a particular CPU core. This is +// important because otherwise the different threads and processes of these +// tests end up on different CPU cores which means that all of the cores are +// lightly loaded so the OS (Windows and Linux) fails to ramp up the CPU +// frequency, leading to unpredictable and often poor performance. +class LockThreadAffinity { + public: + explicit LockThreadAffinity(int cpu_number); + ~LockThreadAffinity(); + + private: + bool affinity_set_ok_; +#if defined(OS_WIN) + DWORD_PTR old_affinity_; +#elif defined(OS_LINUX) + cpu_set_t old_cpuset_; +#endif + + DISALLOW_COPY_AND_ASSIGN(LockThreadAffinity); +}; + } } |