Merge "libprocessgroup: Add SetSchedulerPolicy Action" into main

This commit is contained in:
T.J. Mercier 2024-10-15 00:02:39 +00:00 committed by Gerrit Code Review
commit 5424402b13
2 changed files with 136 additions and 4 deletions

View file

@ -17,11 +17,16 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "libprocessgroup"
#include <task_profiles.h>
#include <map>
#include <string>
#include <dirent.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/resource.h>
#include <unistd.h>
#include <task_profiles.h>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
@ -30,13 +35,13 @@
#include <android-base/strings.h>
#include <android-base/threads.h>
#include <build_flags.h>
#include <cutils/android_filesystem_config.h>
#include <json/reader.h>
#include <json/value.h>
#include <build_flags.h>
using android::base::GetThreadId;
using android::base::GetUintProperty;
using android::base::StringPrintf;
@ -649,6 +654,57 @@ bool WriteFileAction::IsValidForTask(int) const {
return access(task_path_.c_str(), W_OK) == 0;
}
bool SetSchedulerPolicyAction::isNormalPolicy(int policy) {
return policy == SCHED_OTHER || policy == SCHED_BATCH || policy == SCHED_IDLE;
}
bool SetSchedulerPolicyAction::toPriority(int policy, int virtual_priority, int& priority_out) {
constexpr int VIRTUAL_PRIORITY_MIN = 1;
constexpr int VIRTUAL_PRIORITY_MAX = 99;
if (virtual_priority < VIRTUAL_PRIORITY_MIN || virtual_priority > VIRTUAL_PRIORITY_MAX) {
LOG(WARNING) << "SetSchedulerPolicy: invalid priority (" << virtual_priority
<< ") for policy (" << policy << ")";
return false;
}
const int min = sched_get_priority_min(policy);
if (min == -1) {
PLOG(ERROR) << "SetSchedulerPolicy: Cannot get min sched priority for policy " << policy;
return false;
}
const int max = sched_get_priority_max(policy);
if (max == -1) {
PLOG(ERROR) << "SetSchedulerPolicy: Cannot get max sched priority for policy " << policy;
return false;
}
priority_out = min + (virtual_priority - VIRTUAL_PRIORITY_MIN) * (max - min) /
(VIRTUAL_PRIORITY_MAX - VIRTUAL_PRIORITY_MIN);
return true;
}
bool SetSchedulerPolicyAction::ExecuteForTask(pid_t tid) const {
struct sched_param param = {};
param.sched_priority = isNormalPolicy(policy_) ? 0 : *priority_or_nice_;
if (sched_setscheduler(tid, policy_, &param) == -1) {
PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply scheduler policy (" << policy_
<< ") with priority (" << *priority_or_nice_ << ") to tid " << tid;
return false;
}
if (isNormalPolicy(policy_) && priority_or_nice_ &&
setpriority(PRIO_PROCESS, tid, *priority_or_nice_) == -1) {
PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply nice (" << *priority_or_nice_
<< ") to tid " << tid;
return false;
}
return true;
}
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
profile->ExecuteForProcess(uid, pid);
@ -936,6 +992,62 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty value";
}
} else if (action_name == "SetSchedulerPolicy") {
const std::map<std::string, int> POLICY_MAP = {
{"SCHED_OTHER", SCHED_OTHER},
{"SCHED_BATCH", SCHED_BATCH},
{"SCHED_IDLE", SCHED_IDLE},
{"SCHED_FIFO", SCHED_FIFO},
{"SCHED_RR", SCHED_RR},
};
const std::string policy_str = params_val["Policy"].asString();
const auto it = POLICY_MAP.find(policy_str);
if (it == POLICY_MAP.end()) {
LOG(WARNING) << "SetSchedulerPolicy: invalid policy " << policy_str;
continue;
}
const int policy = it->second;
if (SetSchedulerPolicyAction::isNormalPolicy(policy)) {
if (params_val.isMember("Priority")) {
LOG(WARNING) << "SetSchedulerPolicy: Normal policies (" << policy_str
<< ") use Nice values, not Priority values";
}
if (params_val.isMember("Nice")) {
// If present, this optional value will be passed in an additional syscall
// to setpriority(), since the sched_priority value must be 0 for calls to
// sched_setscheduler() with "normal" policies.
const int nice = params_val["Nice"].asInt();
const int LINUX_MIN_NICE = -20;
const int LINUX_MAX_NICE = 19;
if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) {
LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice
<< ") appears out of range.";
}
profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy, nice));
} else {
profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy));
}
} else {
if (params_val.isMember("Nice")) {
LOG(WARNING) << "SetSchedulerPolicy: Real-time policies (" << policy_str
<< ") use Priority values, not Nice values";
}
// This is a "virtual priority" as described by `man 2 sched_get_priority_min`
// that will be mapped onto the following range for the provided policy:
// [sched_get_priority_min(), sched_get_priority_max()]
const int virtual_priority = params_val["Priority"].asInt();
int priority;
if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) {
profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy, priority));
}
}
} else {
LOG(WARNING) << "Unknown profile action: " << action_name;
}

View file

@ -21,6 +21,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <span>
#include <string>
#include <string_view>
@ -187,6 +188,25 @@ class WriteFileAction : public ProfileAction {
CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};
// Set scheduler policy action
class SetSchedulerPolicyAction : public ProfileAction {
public:
SetSchedulerPolicyAction(int policy)
: policy_(policy) {}
SetSchedulerPolicyAction(int policy, int priority_or_nice)
: policy_(policy), priority_or_nice_(priority_or_nice) {}
const char* Name() const override { return "SetSchedulerPolicy"; }
bool ExecuteForTask(pid_t tid) const override;
static bool isNormalPolicy(int policy);
static bool toPriority(int policy, int virtual_priority, int& priority_out);
private:
int policy_;
std::optional<int> priority_or_nice_;
};
class TaskProfile {
public:
TaskProfile(const std::string& name) : name_(name), res_cached_(false) {}