Loading libprocessgroup/task_profiles.cpp +116 −4 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -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_, ¶m) == -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); Loading Loading @@ -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; } Loading libprocessgroup/task_profiles.h +20 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <map> #include <memory> #include <mutex> #include <optional> #include <span> #include <string> #include <string_view> Loading Loading @@ -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) {} Loading Loading
libprocessgroup/task_profiles.cpp +116 −4 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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; Loading Loading @@ -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_, ¶m) == -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); Loading Loading @@ -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; } Loading
libprocessgroup/task_profiles.h +20 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <map> #include <memory> #include <mutex> #include <optional> #include <span> #include <string> #include <string_view> Loading Loading @@ -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) {} Loading