
BUG=1138737 TBR: dcheng@chromium.org Change-Id: I7c31b95b48be172e3305f02e7e71951aa3aa455d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2473760 Commit-Queue: Eric Seckler <eseckler@chromium.org> Reviewed-by: Eric Seckler <eseckler@chromium.org> Cr-Commit-Position: refs/heads/master@{#817419}
137 lines
4.9 KiB
C++
137 lines
4.9 KiB
C++
// 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
|