1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/cpu_affinity_posix.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/system/sys_info.h"
13 #include "base/threading/platform_thread.h"
14 #include "base/threading/thread.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 class TestThread : public PlatformThread::Delegate {
25 : termination_ready_(WaitableEvent::ResetPolicy::MANUAL,
26 WaitableEvent::InitialState::NOT_SIGNALED),
27 terminate_thread_(WaitableEvent::ResetPolicy::MANUAL,
28 WaitableEvent::InitialState::NOT_SIGNALED) {}
29 TestThread(const TestThread&) = delete;
30 TestThread& operator=(const TestThread&) = delete;
31 ~TestThread() override {
32 EXPECT_TRUE(terminate_thread_.IsSignaled())
33 << "Need to mark thread for termination and join the underlying thread "
34 << "before destroying a FunctionTestThread as it owns the "
35 << "WaitableEvent blocking the underlying thread's main.";
38 // Grabs |thread_id_|, signals |termination_ready_|, and then waits for
39 // |terminate_thread_| to be signaled before exiting.
40 void ThreadMain() override {
41 thread_id_ = PlatformThread::CurrentId();
42 EXPECT_NE(thread_id_, kInvalidThreadId);
44 // Make sure that the thread ID is the same across calls.
45 EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
47 termination_ready_.Signal();
48 terminate_thread_.Wait();
53 PlatformThreadId thread_id() const {
54 EXPECT_TRUE(termination_ready_.IsSignaled()) << "Thread ID still unknown";
58 bool IsRunning() const { return termination_ready_.IsSignaled() && !done_; }
60 // Blocks until this thread is started and ready to be terminated.
61 void WaitForTerminationReady() { termination_ready_.Wait(); }
63 // Marks this thread for termination (callers must then join this thread to be
64 // guaranteed of termination).
65 void MarkForTermination() { terminate_thread_.Signal(); }
68 PlatformThreadId thread_id_ = kInvalidThreadId;
70 mutable WaitableEvent termination_ready_;
71 WaitableEvent terminate_thread_;
77 #if defined(OS_ANDROID)
78 #define MAYBE_SetThreadCpuAffinityMode SetThreadCpuAffinityMode
80 // The test only considers Android device hardware models at the moment. Some
81 // CrOS devices on the waterfall have asymmetric CPUs that aren't covered. The
82 // linux-trusty-rel bot also fails to sched_setaffinity().
83 #define MAYBE_SetThreadCpuAffinityMode DISABLED_SetThreadCpuAffinityMode
85 TEST(CpuAffinityTest, MAYBE_SetThreadCpuAffinityMode) {
86 // This test currently only supports Nexus 5x and Pixel devices as big.LITTLE
87 // devices. For other devices, we assume that the cores are symmetric. This is
88 // currently the case for the devices on our waterfalls.
89 std::string device_model = SysInfo::HardwareModelName();
90 int expected_total_cores = SysInfo::SysInfo::NumberOfProcessors();
91 int expected_little_cores = expected_total_cores;
92 if (device_model == "Nexus 5X" || device_model == "Pixel 2" ||
93 device_model == "Pixel 2 XL" || device_model == "Pixel 3" ||
94 device_model == "Pixel 3 XL" || device_model == "Pixel 4" ||
95 device_model == "Pixel 4 XL") {
96 expected_little_cores = 4;
97 EXPECT_LT(expected_little_cores, expected_total_cores);
98 } else if (device_model == "Pixel" || device_model == "Pixel XL") {
99 expected_little_cores = 2;
100 EXPECT_LT(expected_little_cores, expected_total_cores);
101 } else if (device_model == "Pixel 3a" || device_model == "Pixel 3a XL") {
102 expected_little_cores = 6;
103 EXPECT_LT(expected_little_cores, expected_total_cores);
104 } else if (device_model == "Nexus 5" || device_model == "Nexus 7") {
105 // On our Nexus 5 and Nexus 7 bots, something else in the system seems to
106 // set affinity for the test process, making these tests flaky
107 // (crbug.com/1113964).
112 PlatformThreadHandle handle;
113 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
114 thread.WaitForTerminationReady();
115 ASSERT_TRUE(thread.IsRunning());
117 PlatformThreadId thread_id = thread.thread_id();
121 SetThreadCpuAffinityMode(thread_id, CpuAffinityMode::kLittleCoresOnly));
122 EXPECT_EQ(sched_getaffinity(thread_id, sizeof(set), &set), 0);
124 EXPECT_EQ(CPU_COUNT(&set), expected_little_cores);
126 EXPECT_TRUE(SetThreadCpuAffinityMode(thread_id, CpuAffinityMode::kDefault));
127 EXPECT_EQ(sched_getaffinity(thread_id, sizeof(set), &set), 0);
129 EXPECT_EQ(CPU_COUNT(&set), expected_total_cores);
131 thread.MarkForTermination();
132 PlatformThread::Join(handle);
133 ASSERT_FALSE(thread.IsRunning());