libprocessgroup: add support to set aggregate profiles

To support setting multiple profiles with one call. The json format
is as below example.

  "AggregateProfiles": [
    ...
    {
      "Name": "SCHED_SP_BACKGROUND",
      "Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
    },
    ...
  }

Bug: 139521784
Test: SetProfile works as expected
Change-Id: Ibe14ed57d5169cafcbcbbdb054df3ed171a2f6a2
This commit is contained in:
Rick Yiu 2019-09-16 19:07:17 +08:00
parent 4b45eab15b
commit 0b211fa8b3
6 changed files with 173 additions and 80 deletions

View File

@ -117,43 +117,11 @@ void DropTaskProfilesResourceCaching() {
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
} else {
PLOG(WARNING) << "Failed to find " << name << "process profile";
}
}
return true;
return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, use_fd_cache);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
const TaskProfiles& tp = TaskProfiles::GetInstance();
for (const auto& name : profiles) {
TaskProfile* profile = tp.GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
}
} else {
PLOG(WARNING) << "Failed to find " << name << "task profile";
}
}
return true;
return TaskProfiles::GetInstance().SetTaskProfiles(tid, profiles, use_fd_cache);
}
static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {

View File

@ -15,7 +15,6 @@
"Controller": "cpuset",
"File": "top-app/cpus"
},
{
"Name": "MemLimit",
"Controller": "memory",
@ -494,5 +493,52 @@
}
]
}
],
"AggregateProfiles": [
{
"Name": "SCHED_SP_DEFAULT",
"Profiles": [ "TimerSlackNormal" ]
},
{
"Name": "SCHED_SP_BACKGROUND",
"Profiles": [ "HighEnergySaving", "LowIoPriority", "TimerSlackHigh" ]
},
{
"Name": "SCHED_SP_FOREGROUND",
"Profiles": [ "HighPerformance", "HighIoPriority", "TimerSlackNormal" ]
},
{
"Name": "SCHED_SP_TOP_APP",
"Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
},
{
"Name": "SCHED_SP_RT_APP",
"Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
},
{
"Name": "CPUSET_SP_DEFAULT",
"Profiles": [ "TimerSlackNormal" ]
},
{
"Name": "CPUSET_SP_BACKGROUND",
"Profiles": [ "HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", "TimerSlackHigh" ]
},
{
"Name": "CPUSET_SP_FOREGROUND",
"Profiles": [ "HighPerformance", "ProcessCapacityHigh", "HighIoPriority", "TimerSlackNormal" ]
},
{
"Name": "CPUSET_SP_TOP_APP",
"Profiles": [ "MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", "TimerSlackNormal" ]
},
{
"Name": "CPUSET_SP_SYSTEM",
"Profiles": [ "ServiceCapacityLow", "TimerSlackNormal" ]
},
{
"Name": "CPUSET_SP_RESTRICTED",
"Profiles": [ "ServiceCapacityRestricted", "TimerSlackNormal" ]
}
]
}

View File

@ -18,10 +18,11 @@ syntax = "proto3";
package android.profiles;
// Next: 3
// Next: 4
message TaskProfiles {
repeated Attribute attributes = 1 [json_name = "Attributes"];
repeated Profile profiles = 2 [json_name = "Profiles"];
repeated AggregateProfiles aggregateprofiles = 3 [json_name = "AggregateProfiles"];
}
// Next: 4
@ -42,3 +43,9 @@ message Action {
string name = 1 [json_name = "Name"];
map<string, string> params = 2 [json_name = "Params"];
}
// Next: 3
message AggregateProfiles {
string name = 1 [json_name = "Name"];
repeated string profiles = 2 [json_name = "Profiles"];
}

View File

@ -46,34 +46,17 @@ int set_cpuset_policy(int tid, SchedPolicy policy) {
switch (policy) {
case SP_BACKGROUND:
return SetTaskProfiles(tid,
{"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
"TimerSlackHigh"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"CPUSET_SP_BACKGROUND"}, true) ? 0 : -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
return SetTaskProfiles(tid,
{"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
"TimerSlackNormal"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND"}, true) ? 0 : -1;
case SP_TOP_APP:
return SetTaskProfiles(tid,
{"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
"TimerSlackNormal"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"CPUSET_SP_TOP_APP"}, true) ? 0 : -1;
case SP_SYSTEM:
return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}, true) ? 0 : -1;
return SetTaskProfiles(tid, {"CPUSET_SP_SYSTEM"}, true) ? 0 : -1;
case SP_RESTRICTED:
return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}, true)
? 0
: -1;
return SetTaskProfiles(tid, {"CPUSET_SP_RESTRICTED"}, true) ? 0 : -1;
default:
break;
}
@ -134,29 +117,17 @@ int set_sched_policy(int tid, SchedPolicy policy) {
switch (policy) {
case SP_BACKGROUND:
return SetTaskProfiles(tid, {"HighEnergySaving", "LowIoPriority", "TimerSlackHigh"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
case SP_FOREGROUND:
case SP_AUDIO_APP:
case SP_AUDIO_SYS:
return SetTaskProfiles(tid, {"HighPerformance", "HighIoPriority", "TimerSlackNormal"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND"}, true) ? 0 : -1;
case SP_TOP_APP:
return SetTaskProfiles(tid, {"MaxPerformance", "MaxIoPriority", "TimerSlackNormal"},
true)
? 0
: -1;
return SetTaskProfiles(tid, {"SCHED_SP_TOP_APP"}, true) ? 0 : -1;
case SP_RT_APP:
return SetTaskProfiles(
tid, {"RealtimePerformance", "MaxIoPriority", "TimerSlackNormal"}, true)
? 0
: -1;
return SetTaskProfiles(tid, {"SCHED_SP_RT_APP"}, true) ? 0 : -1;
default:
return SetTaskProfiles(tid, {"TimerSlackNormal"}, true) ? 0 : -1;
return SetTaskProfiles(tid, {"SCHED_SP_DEFAULT"}, true) ? 0 : -1;
}
return 0;

View File

@ -268,6 +268,26 @@ bool SetCgroupAction::ExecuteForTask(int tid) const {
return true;
}
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
profile->EnableResourceCaching();
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
}
}
return true;
}
bool ApplyProfileAction::ExecuteForTask(int tid) const {
for (const auto& profile : profiles_) {
profile->EnableResourceCaching();
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "ExecuteForTask failed for aggregate profile";
}
}
return true;
}
bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& element : elements_) {
if (!element->ExecuteForProcess(uid, pid)) {
@ -373,15 +393,13 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
}
}
std::map<std::string, std::string> params;
const Json::Value& profiles_val = root["Profiles"];
for (Json::Value::ArrayIndex i = 0; i < profiles_val.size(); ++i) {
const Json::Value& profile_val = profiles_val[i];
std::string profile_name = profile_val["Name"].asString();
const Json::Value& actions = profile_val["Actions"];
auto profile = std::make_unique<TaskProfile>();
auto profile = std::make_shared<TaskProfile>();
for (Json::Value::ArrayIndex act_idx = 0; act_idx < actions.size(); ++act_idx) {
const Json::Value& action_val = actions[act_idx];
@ -440,7 +458,38 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) {
LOG(WARNING) << "Unknown profile action: " << action_name;
}
}
profiles_[profile_name] = std::move(profile);
profiles_[profile_name] = profile;
}
const Json::Value& aggregateprofiles_val = root["AggregateProfiles"];
for (Json::Value::ArrayIndex i = 0; i < aggregateprofiles_val.size(); ++i) {
const Json::Value& aggregateprofile_val = aggregateprofiles_val[i];
std::string aggregateprofile_name = aggregateprofile_val["Name"].asString();
const Json::Value& aggregateprofiles = aggregateprofile_val["Profiles"];
std::vector<std::shared_ptr<TaskProfile>> profiles;
bool ret = true;
for (Json::Value::ArrayIndex pf_idx = 0; pf_idx < aggregateprofiles.size(); ++pf_idx) {
std::string profile_name = aggregateprofiles[pf_idx].asString();
if (profile_name == aggregateprofile_name) {
LOG(WARNING) << "AggregateProfiles: recursive profile name: " << profile_name;
ret = false;
break;
} else if (profiles_.find(profile_name) == profiles_.end()) {
LOG(WARNING) << "AggregateProfiles: undefined profile name: " << profile_name;
ret = false;
break;
} else {
profiles.push_back(profiles_[profile_name]);
}
}
if (ret) {
auto profile = std::make_shared<TaskProfile>();
profile->Add(std::make_unique<ApplyProfileAction>(profiles));
profiles_[aggregateprofile_name] = profile;
}
}
return true;
@ -463,3 +512,39 @@ const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) cons
}
return nullptr;
}
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
const std::vector<std::string>& profiles, bool use_fd_cache) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
} else {
PLOG(WARNING) << "Failed to find " << name << "process profile";
}
}
return true;
}
bool TaskProfiles::SetTaskProfiles(int tid, const std::vector<std::string>& profiles,
bool use_fd_cache) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
profile->EnableResourceCaching();
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
}
} else {
PLOG(WARNING) << "Failed to find " << name << "task profile";
}
}
return true;
}

View File

@ -154,6 +154,19 @@ class TaskProfile {
std::vector<std::unique_ptr<ProfileAction>> elements_;
};
// Set aggregate profile element
class ApplyProfileAction : public ProfileAction {
public:
ApplyProfileAction(const std::vector<std::shared_ptr<TaskProfile>>& profiles)
: profiles_(profiles) {}
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
private:
std::vector<std::shared_ptr<TaskProfile>> profiles_;
};
class TaskProfiles {
public:
// Should be used by all users
@ -162,9 +175,12 @@ class TaskProfiles {
TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
void DropResourceCaching() const;
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
bool use_fd_cache);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
private:
std::map<std::string, std::unique_ptr<TaskProfile>> profiles_;
std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
std::map<std::string, std::unique_ptr<ProfileAttribute>> attributes_;
TaskProfiles();