/* * Copyright (C) 2016 The Android Open Source Project * * 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 <algorithm> #include <chrono> #include <thread> #include <vector> #include <sys/capability.h> #include <cutils/sched_policy.h> #include <gtest/gtest.h> bool hasCapSysNice() { __user_cap_header_struct header; memset(&header, 0, sizeof(header)); header.version = _LINUX_CAPABILITY_VERSION_3; __user_cap_data_struct caps[_LINUX_CAPABILITY_U32S_3]; if (capget(&header, &caps[0])) { GTEST_LOG_(WARNING) << "failed to get process capabilities"; return false; } auto nice_idx = CAP_TO_INDEX(CAP_SYS_NICE); auto nice_mask = CAP_TO_MASK(CAP_SYS_NICE); return caps[nice_idx].effective & nice_mask; } long long medianSleepTime() { std::vector<long long> sleepTimes; constexpr size_t numSamples = 100; for (size_t i = 0; i < numSamples; i++) { auto start = std::chrono::steady_clock::now(); std::this_thread::sleep_for(std::chrono::nanoseconds(1)); auto end = std::chrono::steady_clock::now(); auto diff = end - start; sleepTimes.push_back(diff.count()); } constexpr auto median = numSamples / 2; std::nth_element(sleepTimes.begin(), sleepTimes.begin() + median, sleepTimes.end()); return sleepTimes[median]; } static void AssertPolicy(SchedPolicy expected_policy) { SchedPolicy current_policy; ASSERT_EQ(0, get_sched_policy(0, ¤t_policy)); EXPECT_EQ(expected_policy, current_policy); } TEST(SchedPolicy, set_sched_policy) { if (!schedboost_enabled()) { // schedboost_enabled() (i.e. CONFIG_CGROUP_SCHEDTUNE) is optional; // it's only needed on devices using energy-aware scheduler. GTEST_LOG_(INFO) << "skipping test that requires CONFIG_CGROUP_SCHEDTUNE"; return; } ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND)); AssertPolicy(SP_BACKGROUND); ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND)); AssertPolicy(SP_FOREGROUND); } TEST(SchedPolicy, set_sched_policy_timerslack) { if (!hasCapSysNice()) { GTEST_LOG_(INFO) << "skipping test that requires CAP_SYS_NICE"; return; } // A measureable effect of scheduling policy is that the kernel has 800x // greater slack time in waking up a sleeping background thread. // // Look for 10x difference in how long FB and BG threads actually sleep // when trying to sleep for 1 ns. This difference is large enough not // to happen by chance, but small enough (compared to 800x) to keep inherent // fuzziness in scheduler behavior from causing false negatives. const unsigned int BG_FG_SLACK_FACTOR = 10; ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND)); auto bgSleepTime = medianSleepTime(); ASSERT_EQ(0, set_sched_policy(0, SP_FOREGROUND)); auto fgSleepTime = medianSleepTime(); ASSERT_GT(bgSleepTime, fgSleepTime * BG_FG_SLACK_FACTOR); } TEST(SchedPolicy, get_sched_policy_name) { EXPECT_STREQ("bg", get_sched_policy_name(SP_BACKGROUND)); EXPECT_STREQ("error", get_sched_policy_name(SchedPolicy(-2))); EXPECT_STREQ("error", get_sched_policy_name(SP_CNT)); }