summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrucedawson <brucedawson@chromium.org>2015-02-12 14:33:22 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-12 22:34:08 +0000
commitaa3d0c59862b7adecafa3d962b073b29322deec9 (patch)
tree09994b721f37cc554179c79c9efbaa327f3d7204
parent72e0856eb5934945142f1b10ac7f1ace76c6f837 (diff)
downloadchromium_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.cc39
-rw-r--r--ipc/ipc_perftest_support.h21
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);
+};
+
}
}