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