2014-04-30 00:49:14 +02:00
|
|
|
/*
|
2018-12-21 20:41:50 +01:00
|
|
|
* Copyright (C) 2019 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.
|
|
|
|
*/
|
2009-09-12 19:06:57 +02:00
|
|
|
|
2019-01-25 06:30:52 +01:00
|
|
|
#include <processgroup/sched_policy.h>
|
2017-11-10 19:22:07 +01:00
|
|
|
|
2012-05-09 00:05:42 +02:00
|
|
|
#define LOG_TAG "SchedPolicy"
|
|
|
|
|
2014-04-30 00:49:14 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
#include <android-base/logging.h>
|
|
|
|
#include <android-base/threads.h>
|
|
|
|
#include <cgroup_map.h>
|
|
|
|
#include <processgroup/processgroup.h>
|
|
|
|
|
|
|
|
using android::base::GetThreadId;
|
2014-04-30 00:49:14 +02:00
|
|
|
|
2012-05-09 00:05:42 +02:00
|
|
|
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
|
|
|
|
* Call this any place a SchedPolicy is used as an input parameter.
|
|
|
|
* Returns the possibly re-mapped policy.
|
|
|
|
*/
|
2018-12-21 20:41:50 +01:00
|
|
|
static inline SchedPolicy _policy(SchedPolicy p) {
|
|
|
|
return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
|
2012-05-09 00:05:42 +02:00
|
|
|
}
|
2009-10-29 19:48:00 +01:00
|
|
|
|
2019-02-02 23:19:41 +01:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
int set_cpuset_policy(int tid, SchedPolicy policy) {
|
2012-03-16 17:43:19 +01:00
|
|
|
if (tid == 0) {
|
2018-12-21 20:41:50 +01:00
|
|
|
tid = GetThreadId();
|
2015-06-08 23:56:29 +02:00
|
|
|
}
|
|
|
|
policy = _policy(policy);
|
|
|
|
|
|
|
|
switch (policy) {
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_BACKGROUND:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"CPUSET_SP_BACKGROUND"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_FOREGROUND:
|
|
|
|
case SP_AUDIO_APP:
|
|
|
|
case SP_AUDIO_SYS:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_TOP_APP:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"CPUSET_SP_TOP_APP"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_SYSTEM:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"CPUSET_SP_SYSTEM"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_RESTRICTED:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"CPUSET_SP_RESTRICTED"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
default:
|
|
|
|
break;
|
2015-10-27 00:22:11 +01:00
|
|
|
}
|
|
|
|
|
2015-06-22 23:00:56 +02:00
|
|
|
return 0;
|
2015-06-08 23:56:29 +02:00
|
|
|
}
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
int set_sched_policy(int tid, SchedPolicy policy) {
|
2012-03-16 17:43:19 +01:00
|
|
|
if (tid == 0) {
|
2018-12-21 20:41:50 +01:00
|
|
|
tid = GetThreadId();
|
2012-03-16 17:43:19 +01:00
|
|
|
}
|
|
|
|
policy = _policy(policy);
|
2009-09-12 19:06:57 +02:00
|
|
|
|
2009-10-29 19:48:00 +01:00
|
|
|
#if POLICY_DEBUG
|
|
|
|
char statfile[64];
|
|
|
|
char statline[1024];
|
|
|
|
char thread_name[255];
|
|
|
|
|
2016-04-19 20:25:14 +02:00
|
|
|
snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
|
2009-10-29 19:48:00 +01:00
|
|
|
memset(thread_name, 0, sizeof(thread_name));
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
unique_fd fd(TEMP_FAILURE_RETRY(open(statfile, O_RDONLY | O_CLOEXEC)));
|
2009-10-29 19:48:00 +01:00
|
|
|
if (fd >= 0) {
|
|
|
|
int rc = read(fd, statline, 1023);
|
|
|
|
statline[rc] = 0;
|
2018-12-21 20:41:50 +01:00
|
|
|
char* p = statline;
|
|
|
|
char* q;
|
2009-10-29 19:48:00 +01:00
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
for (p = statline; *p != '('; p++)
|
|
|
|
;
|
2009-10-29 19:48:00 +01:00
|
|
|
p++;
|
2018-12-21 20:41:50 +01:00
|
|
|
for (q = p; *q != ')'; q++)
|
|
|
|
;
|
2009-10-29 19:48:00 +01:00
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
strncpy(thread_name, p, (q - p));
|
2009-10-29 19:48:00 +01:00
|
|
|
}
|
2012-04-20 00:25:58 +02:00
|
|
|
switch (policy) {
|
2015-06-08 23:56:29 +02:00
|
|
|
case SP_BACKGROUND:
|
2018-12-21 20:41:50 +01:00
|
|
|
SLOGD("vvv tid %d (%s)", tid, thread_name);
|
2015-06-08 23:56:29 +02:00
|
|
|
break;
|
|
|
|
case SP_FOREGROUND:
|
|
|
|
case SP_AUDIO_APP:
|
|
|
|
case SP_AUDIO_SYS:
|
2016-01-12 01:16:35 +01:00
|
|
|
case SP_TOP_APP:
|
2018-12-21 20:41:50 +01:00
|
|
|
SLOGD("^^^ tid %d (%s)", tid, thread_name);
|
|
|
|
break;
|
|
|
|
case SP_SYSTEM:
|
|
|
|
SLOGD("/// tid %d (%s)", tid, thread_name);
|
2015-06-08 23:56:29 +02:00
|
|
|
break;
|
2017-03-26 07:46:10 +02:00
|
|
|
case SP_RT_APP:
|
2018-12-21 20:41:50 +01:00
|
|
|
SLOGD("RT tid %d (%s)", tid, thread_name);
|
|
|
|
break;
|
2015-06-08 23:56:29 +02:00
|
|
|
default:
|
2018-12-21 20:41:50 +01:00
|
|
|
SLOGD("??? tid %d (%s)", tid, thread_name);
|
2015-06-08 23:56:29 +02:00
|
|
|
break;
|
2009-09-12 19:06:57 +02:00
|
|
|
}
|
2018-12-21 20:41:50 +01:00
|
|
|
#endif
|
2009-09-12 19:06:57 +02:00
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
switch (policy) {
|
|
|
|
case SP_BACKGROUND:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_FOREGROUND:
|
|
|
|
case SP_AUDIO_APP:
|
|
|
|
case SP_AUDIO_SYS:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_TOP_APP:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"SCHED_SP_TOP_APP"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
case SP_RT_APP:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"SCHED_SP_RT_APP"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
default:
|
2019-09-16 13:07:17 +02:00
|
|
|
return SetTaskProfiles(tid, {"SCHED_SP_DEFAULT"}, true) ? 0 : -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
}
|
2014-04-23 03:55:08 +02:00
|
|
|
|
2009-09-12 19:06:57 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2009-09-16 02:10:17 +02:00
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
bool cpusets_enabled() {
|
2019-05-09 02:59:55 +02:00
|
|
|
static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").IsUsable());
|
2018-12-21 20:41:50 +01:00
|
|
|
return enabled;
|
|
|
|
}
|
2012-05-09 00:05:42 +02:00
|
|
|
|
2020-01-14 13:55:57 +01:00
|
|
|
static bool schedtune_enabled() {
|
|
|
|
return (CgroupMap::GetInstance().FindController("schedtune").IsUsable());
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool cpuctl_enabled() {
|
|
|
|
return (CgroupMap::GetInstance().FindController("cpu").IsUsable());
|
|
|
|
}
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
bool schedboost_enabled() {
|
2020-01-14 13:55:57 +01:00
|
|
|
static bool enabled = schedtune_enabled() || cpuctl_enabled();
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) {
|
2019-03-23 01:01:08 +01:00
|
|
|
auto controller = CgroupMap::GetInstance().FindController(subsys);
|
2012-05-09 00:05:42 +02:00
|
|
|
|
2019-05-09 02:59:55 +02:00
|
|
|
if (!controller.IsUsable()) return -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
|
2019-03-23 01:01:08 +01:00
|
|
|
if (!controller.GetTaskGroup(tid, &subgroup)) {
|
2019-03-07 20:59:12 +01:00
|
|
|
LOG(ERROR) << "Failed to find cgroup for tid " << tid;
|
2018-12-21 20:41:50 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2012-05-09 00:05:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-21 20:41:50 +01:00
|
|
|
int get_sched_policy(int tid, SchedPolicy* policy) {
|
|
|
|
if (tid == 0) {
|
|
|
|
tid = GetThreadId();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string group;
|
|
|
|
if (schedboost_enabled()) {
|
2020-01-14 13:55:57 +01:00
|
|
|
if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
|
|
|
|
(getCGroupSubsys(tid, "cpu", group) < 0))
|
|
|
|
return -1;
|
2018-12-21 20:41:50 +01:00
|
|
|
}
|
|
|
|
if (group.empty() && cpusets_enabled()) {
|
|
|
|
if (getCGroupSubsys(tid, "cpuset", group) < 0) return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: replace hardcoded directories
|
|
|
|
if (group.empty()) {
|
|
|
|
*policy = SP_FOREGROUND;
|
|
|
|
} else if (group == "foreground") {
|
|
|
|
*policy = SP_FOREGROUND;
|
|
|
|
} else if (group == "system-background") {
|
|
|
|
*policy = SP_SYSTEM;
|
|
|
|
} else if (group == "background") {
|
|
|
|
*policy = SP_BACKGROUND;
|
|
|
|
} else if (group == "top-app") {
|
|
|
|
*policy = SP_TOP_APP;
|
|
|
|
} else if (group == "restricted") {
|
|
|
|
*policy = SP_RESTRICTED;
|
|
|
|
} else {
|
|
|
|
errno = ERANGE;
|
|
|
|
return -1;
|
|
|
|
}
|
2012-05-09 00:05:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-02 23:19:41 +01:00
|
|
|
#else
|
|
|
|
|
|
|
|
/* Stubs for non-Android targets. */
|
|
|
|
|
|
|
|
int set_sched_policy(int, SchedPolicy) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_sched_policy(int, SchedPolicy* policy) {
|
|
|
|
*policy = SP_SYSTEM_DEFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2018-04-25 23:52:50 +02:00
|
|
|
const char* get_sched_policy_name(SchedPolicy policy) {
|
2012-03-16 17:43:19 +01:00
|
|
|
policy = _policy(policy);
|
2018-04-25 23:52:50 +02:00
|
|
|
static const char* const kSchedPolicyNames[] = {
|
2018-04-13 19:15:49 +02:00
|
|
|
[SP_BACKGROUND] = "bg", [SP_FOREGROUND] = "fg", [SP_SYSTEM] = " ",
|
|
|
|
[SP_AUDIO_APP] = "aa", [SP_AUDIO_SYS] = "as", [SP_TOP_APP] = "ta",
|
|
|
|
[SP_RT_APP] = "rt", [SP_RESTRICTED] = "rs",
|
2012-03-06 01:14:39 +01:00
|
|
|
};
|
2018-04-25 23:52:50 +02:00
|
|
|
static_assert(arraysize(kSchedPolicyNames) == SP_CNT, "missing name");
|
|
|
|
if (policy < SP_BACKGROUND || policy >= SP_CNT) {
|
2019-10-12 00:09:09 +02:00
|
|
|
return nullptr;
|
2018-04-25 23:52:50 +02:00
|
|
|
}
|
|
|
|
return kSchedPolicyNames[policy];
|
2012-03-06 01:14:39 +01:00
|
|
|
}
|
2019-10-12 00:09:09 +02:00
|
|
|
|
|
|
|
const char* get_cpuset_policy_profile_name(SchedPolicy policy) {
|
|
|
|
/*
|
|
|
|
* cpuset profile array for:
|
|
|
|
* SP_DEFAULT(-1), SP_BACKGROUND(0), SP_FOREGROUND(1),
|
|
|
|
* SP_SYSTEM(2), SP_AUDIO_APP(3), SP_AUDIO_SYS(4),
|
|
|
|
* SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7)
|
|
|
|
* index is policy + 1
|
|
|
|
* this need keep in sync with SchedPolicy enum
|
|
|
|
*/
|
|
|
|
static constexpr const char* kCpusetProfiles[SP_CNT + 1] = {
|
|
|
|
"CPUSET_SP_DEFAULT", "CPUSET_SP_BACKGROUND", "CPUSET_SP_FOREGROUND",
|
|
|
|
"CPUSET_SP_SYSTEM", "CPUSET_SP_FOREGROUND", "CPUSET_SP_FOREGROUND",
|
|
|
|
"CPUSET_SP_TOP_APP", "CPUSET_SP_DEFAULT", "CPUSET_SP_RESTRICTED"};
|
|
|
|
if (policy < SP_DEFAULT || policy >= SP_CNT) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return kCpusetProfiles[policy + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* get_sched_policy_profile_name(SchedPolicy policy) {
|
|
|
|
/*
|
|
|
|
* sched profile array for:
|
|
|
|
* SP_DEFAULT(-1), SP_BACKGROUND(0), SP_FOREGROUND(1),
|
|
|
|
* SP_SYSTEM(2), SP_AUDIO_APP(3), SP_AUDIO_SYS(4),
|
|
|
|
* SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7)
|
|
|
|
* index is policy + 1
|
|
|
|
* this need keep in sync with SchedPolicy enum
|
|
|
|
*/
|
|
|
|
static constexpr const char* kSchedProfiles[SP_CNT + 1] = {
|
|
|
|
"SCHED_SP_DEFAULT", "SCHED_SP_BACKGROUND", "SCHED_SP_FOREGROUND",
|
|
|
|
"SCHED_SP_DEFAULT", "SCHED_SP_FOREGROUND", "SCHED_SP_FOREGROUND",
|
|
|
|
"SCHED_SP_TOP_APP", "SCHED_SP_RT_APP", "SCHED_SP_DEFAULT"};
|
|
|
|
if (policy < SP_DEFAULT || policy >= SP_CNT) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return kSchedProfiles[policy + 1];
|
|
|
|
}
|