diff options
Diffstat (limited to 'test/syscalls/linux/affinity.cc')
-rw-r--r-- | test/syscalls/linux/affinity.cc | 242 |
1 files changed, 0 insertions, 242 deletions
diff --git a/test/syscalls/linux/affinity.cc b/test/syscalls/linux/affinity.cc deleted file mode 100644 index 128364c34..000000000 --- a/test/syscalls/linux/affinity.cc +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <sched.h> -#include <sys/syscall.h> -#include <sys/types.h> -#include <unistd.h> - -#include "gtest/gtest.h" -#include "absl/strings/str_split.h" -#include "test/util/cleanup.h" -#include "test/util/fs_util.h" -#include "test/util/posix_error.h" -#include "test/util/test_util.h" -#include "test/util/thread_util.h" - -namespace gvisor { -namespace testing { -namespace { - -// These tests are for both the sched_getaffinity(2) and sched_setaffinity(2) -// syscalls. -class AffinityTest : public ::testing::Test { - protected: - void SetUp() override { - EXPECT_THAT( - // Needs use the raw syscall to get the actual size. - cpuset_size_ = syscall(SYS_sched_getaffinity, /*pid=*/0, - sizeof(cpu_set_t), &mask_), - SyscallSucceeds()); - // Lots of tests rely on having more than 1 logical processor available. - EXPECT_GT(CPU_COUNT(&mask_), 1); - } - - static PosixError ClearLowestBit(cpu_set_t* mask, size_t cpus) { - const size_t mask_size = CPU_ALLOC_SIZE(cpus); - for (size_t n = 0; n < cpus; ++n) { - if (CPU_ISSET_S(n, mask_size, mask)) { - CPU_CLR_S(n, mask_size, mask); - return NoError(); - } - } - return PosixError(EINVAL, "No bit to clear, mask is empty"); - } - - PosixError ClearLowestBit() { return ClearLowestBit(&mask_, CPU_SETSIZE); } - - // Stores the initial cpu mask for this process. - cpu_set_t mask_ = {}; - int cpuset_size_ = 0; -}; - -// sched_getaffinity(2) is implemented. -TEST_F(AffinityTest, SchedGetAffinityImplemented) { - EXPECT_THAT(sched_getaffinity(/*pid=*/0, sizeof(cpu_set_t), &mask_), - SyscallSucceeds()); -} - -// PID is not found. -TEST_F(AffinityTest, SchedGetAffinityInvalidPID) { - // Flaky, but it's tough to avoid a race condition when finding an unused pid - EXPECT_THAT(sched_getaffinity(/*pid=*/INT_MAX - 1, sizeof(cpu_set_t), &mask_), - SyscallFailsWithErrno(ESRCH)); -} - -// PID is not found. -TEST_F(AffinityTest, SchedSetAffinityInvalidPID) { - // Flaky, but it's tough to avoid a race condition when finding an unused pid - EXPECT_THAT(sched_setaffinity(/*pid=*/INT_MAX - 1, sizeof(cpu_set_t), &mask_), - SyscallFailsWithErrno(ESRCH)); -} - -TEST_F(AffinityTest, SchedSetAffinityZeroMask) { - CPU_ZERO(&mask_); - EXPECT_THAT(sched_setaffinity(/*pid=*/0, sizeof(cpu_set_t), &mask_), - SyscallFailsWithErrno(EINVAL)); -} - -// N.B. This test case relies on cpuset_size_ larger than the actual number of -// of all existing CPUs. Check your machine if the test fails. -TEST_F(AffinityTest, SchedSetAffinityNonexistentCPUDropped) { - cpu_set_t mask = mask_; - // Add a nonexistent CPU. - // - // The number needs to be larger than the possible number of CPU available, - // but smaller than the number of the CPU that the kernel claims to support -- - // it's implicitly returned by raw sched_getaffinity syscall. - CPU_SET(cpuset_size_ * 8 - 1, &mask); - EXPECT_THAT( - // Use raw syscall because it will be rejected by the libc wrapper - // otherwise. - syscall(SYS_sched_setaffinity, /*pid=*/0, sizeof(cpu_set_t), &mask), - SyscallSucceeds()) - << "failed with cpumask : " << CPUSetToString(mask) - << ", cpuset_size_ : " << cpuset_size_; - cpu_set_t newmask; - EXPECT_THAT(sched_getaffinity(/*pid=*/0, sizeof(cpu_set_t), &newmask), - SyscallSucceeds()); - EXPECT_TRUE(CPU_EQUAL(&mask_, &newmask)) - << "got: " << CPUSetToString(newmask) - << " != expected: " << CPUSetToString(mask_); -} - -TEST_F(AffinityTest, SchedSetAffinityOnlyNonexistentCPUFails) { - // Make an empty cpu set. - CPU_ZERO(&mask_); - // Add a nonexistent CPU. - // - // The number needs to be larger than the possible number of CPU available, - // but smaller than the number of the CPU that the kernel claims to support -- - // it's implicitly returned by raw sched_getaffinity syscall. - int cpu = cpuset_size_ * 8 - 1; - if (cpu <= NumCPUs()) { - GTEST_SKIP() << "Skipping test: cpu " << cpu << " exists"; - } - CPU_SET(cpu, &mask_); - EXPECT_THAT( - // Use raw syscall because it will be rejected by the libc wrapper - // otherwise. - syscall(SYS_sched_setaffinity, /*pid=*/0, sizeof(cpu_set_t), &mask_), - SyscallFailsWithErrno(EINVAL)); -} - -TEST_F(AffinityTest, SchedSetAffinityInvalidSize) { - EXPECT_GT(cpuset_size_, 0); - // Not big enough. - EXPECT_THAT(sched_getaffinity(/*pid=*/0, cpuset_size_ - 1, &mask_), - SyscallFailsWithErrno(EINVAL)); - // Not a multiple of word size. - EXPECT_THAT(sched_getaffinity(/*pid=*/0, cpuset_size_ + 1, &mask_), - SyscallFailsWithErrno(EINVAL)); -} - -TEST_F(AffinityTest, Sanity) { - ASSERT_NO_ERRNO(ClearLowestBit()); - EXPECT_THAT(sched_setaffinity(/*pid=*/0, sizeof(cpu_set_t), &mask_), - SyscallSucceeds()); - cpu_set_t newmask; - EXPECT_THAT(sched_getaffinity(/*pid=*/0, sizeof(cpu_set_t), &newmask), - SyscallSucceeds()); - EXPECT_TRUE(CPU_EQUAL(&mask_, &newmask)) - << "got: " << CPUSetToString(newmask) - << " != expected: " << CPUSetToString(mask_); -} - -TEST_F(AffinityTest, NewThread) { - SKIP_IF(CPU_COUNT(&mask_) < 3); - ASSERT_NO_ERRNO(ClearLowestBit()); - ASSERT_NO_ERRNO(ClearLowestBit()); - EXPECT_THAT(sched_setaffinity(/*pid=*/0, sizeof(cpu_set_t), &mask_), - SyscallSucceeds()); - ScopedThread([this]() { - cpu_set_t child_mask; - ASSERT_THAT(sched_getaffinity(/*pid=*/0, sizeof(cpu_set_t), &child_mask), - SyscallSucceeds()); - ASSERT_TRUE(CPU_EQUAL(&child_mask, &mask_)) - << "child cpu mask: " << CPUSetToString(child_mask) - << " != parent cpu mask: " << CPUSetToString(mask_); - }); -} - -TEST_F(AffinityTest, ConsistentWithProcCpuInfo) { - // Count how many cpus are shown in /proc/cpuinfo. - std::string cpuinfo = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/cpuinfo")); - int count = 0; - for (auto const& line : absl::StrSplit(cpuinfo, '\n')) { - if (absl::StartsWith(line, "processor")) { - count++; - } - } - EXPECT_GE(count, CPU_COUNT(&mask_)); -} - -TEST_F(AffinityTest, ConsistentWithProcStat) { - // Count how many cpus are shown in /proc/stat. - std::string stat = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/stat")); - int count = 0; - for (auto const& line : absl::StrSplit(stat, '\n')) { - if (absl::StartsWith(line, "cpu") && !absl::StartsWith(line, "cpu ")) { - count++; - } - } - EXPECT_GE(count, CPU_COUNT(&mask_)); -} - -TEST_F(AffinityTest, SmallCpuMask) { - const int num_cpus = NumCPUs(); - const size_t mask_size = CPU_ALLOC_SIZE(num_cpus); - cpu_set_t* mask = CPU_ALLOC(num_cpus); - ASSERT_NE(mask, nullptr); - const auto free_mask = Cleanup([&] { CPU_FREE(mask); }); - - CPU_ZERO_S(mask_size, mask); - ASSERT_THAT(sched_getaffinity(0, mask_size, mask), SyscallSucceeds()); -} - -TEST_F(AffinityTest, LargeCpuMask) { - // Allocate mask bigger than cpu_set_t normally allocates. - const size_t cpus = CPU_SETSIZE * 8; - const size_t mask_size = CPU_ALLOC_SIZE(cpus); - - cpu_set_t* large_mask = CPU_ALLOC(cpus); - auto free_mask = Cleanup([large_mask] { CPU_FREE(large_mask); }); - CPU_ZERO_S(mask_size, large_mask); - - // Check that get affinity with large mask works as expected. - ASSERT_THAT(sched_getaffinity(/*pid=*/0, mask_size, large_mask), - SyscallSucceeds()); - EXPECT_TRUE(CPU_EQUAL(&mask_, large_mask)) - << "got: " << CPUSetToString(*large_mask, cpus) - << " != expected: " << CPUSetToString(mask_); - - // Check that set affinity with large mask works as expected. - ASSERT_NO_ERRNO(ClearLowestBit(large_mask, cpus)); - EXPECT_THAT(sched_setaffinity(/*pid=*/0, mask_size, large_mask), - SyscallSucceeds()); - - cpu_set_t* new_mask = CPU_ALLOC(cpus); - auto free_new_mask = Cleanup([new_mask] { CPU_FREE(new_mask); }); - CPU_ZERO_S(mask_size, new_mask); - EXPECT_THAT(sched_getaffinity(/*pid=*/0, mask_size, new_mask), - SyscallSucceeds()); - - EXPECT_TRUE(CPU_EQUAL_S(mask_size, large_mask, new_mask)) - << "got: " << CPUSetToString(*new_mask, cpus) - << " != expected: " << CPUSetToString(*large_mask, cpus); -} - -} // namespace -} // namespace testing -} // namespace gvisor |