From bc077ff11048d6bd8250a0362659907f646dc7b4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 17 Feb 2022 01:26:44 +0000 Subject: [PATCH] Add support for memcg v2 attributes Some but not all memcg v1 attributes exist in the v2 hierarchy. The following information comes from Shakeel Butt and Kamil Yurtsever, "cgroup v2 migration at Google", Linux Plumbers Conference 2018 ( https://lpc.events/event/2/contributions/204/attachments/143/378/LPC2018-cgroup-v2.pdf ): v1 v2 -------------------------- ---------- memory.limit_in_bytes memory.max memory.soft_limit_in_bytes memory.low Add support for cgroup attributes that have different names in the v1 and v2 hierarchies. Also add those memcg attributes that are used in lmkd. Bug: 213617178 Test: Tested lmkd with v1 and v2 memcg. Change-Id: Ia5c5f02974f3b783d5cdaad85b33169ced8db55f Signed-off-by: Bart Van Assche --- libprocessgroup/profiles/task_profiles.json | 31 ++++++++++++++++++-- libprocessgroup/profiles/task_profiles.proto | 5 ++-- libprocessgroup/task_profiles.cpp | 16 +++++++--- libprocessgroup/task_profiles.h | 9 ++++-- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index b668dcb13..7e0396467 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -15,21 +15,48 @@ "Controller": "cpuset", "File": "top-app/cpus" }, + { + "Name": "MemStats", + "Controller": "memory", + "File": "memory.stat" + }, { "Name": "MemLimit", "Controller": "memory", - "File": "memory.limit_in_bytes" + "File": "memory.limit_in_bytes", + "FileV2": "memory.max" }, { "Name": "MemSoftLimit", "Controller": "memory", - "File": "memory.soft_limit_in_bytes" + "File": "memory.soft_limit_in_bytes", + "FileV2": "memory.low" }, { "Name": "MemSwappiness", "Controller": "memory", "File": "memory.swappiness" }, + { + "Name": "MemUsage", + "Controller": "memory", + "File": "memory.usage_in_bytes" + }, + { + "Name": "MemAndSwapUsage", + "Controller": "memory", + "File": "memory.memsw.usage_in_bytes" + }, + { + "Name": "MemPressureLevel", + "Controller": "memory", + "File": "memory.pressure_level" + }, + { + "Name": "MemCgroupEventControl", + "Controller": "memory", + "File": "cgroup.event_control" + }, { "Name": "UClampMin", "Controller": "cpu", diff --git a/libprocessgroup/profiles/task_profiles.proto b/libprocessgroup/profiles/task_profiles.proto index 2a09217ab..ebcd9b56e 100644 --- a/libprocessgroup/profiles/task_profiles.proto +++ b/libprocessgroup/profiles/task_profiles.proto @@ -25,12 +25,13 @@ message TaskProfiles { repeated AggregateProfiles aggregateprofiles = 3 [json_name = "AggregateProfiles"]; } -// Next: 5 +// Next: 6 message Attribute { string name = 1 [json_name = "Name"]; string controller = 2 [json_name = "Controller"]; string file = 3 [json_name = "File"]; - string optional = 4 [json_name = "Optional"]; + string filev2 = 4 [json_name = "FileV2"]; + string optional = 5 [json_name = "Optional"]; } // Next: 3 diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 4a2bf381b..78a316a6f 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -129,11 +129,12 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { return true; } + const std::string& file_name = + controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_; if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), - file_name_.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str()); } return true; } @@ -633,12 +634,19 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { std::string name = attr[i]["Name"].asString(); std::string controller_name = attr[i]["Controller"].asString(); std::string file_attr = attr[i]["File"].asString(); + std::string file_v2_attr = attr[i]["FileV2"].asString(); + + if (!file_v2_attr.empty() && file_attr.empty()) { + LOG(ERROR) << "Attribute " << name << " has FileV2 but no File property"; + return false; + } auto controller = cg_map.FindController(controller_name); if (controller.HasValue()) { auto iter = attributes_.find(name); if (iter == attributes_.end()) { - attributes_[name] = std::make_unique(controller, file_attr); + attributes_[name] = + std::make_unique(controller, file_attr, file_v2_attr); } else { iter->second->Reset(controller, file_attr); } diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 47475115e..df08f65c7 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -37,8 +37,12 @@ class IProfileAttribute { class ProfileAttribute : public IProfileAttribute { public: - ProfileAttribute(const CgroupController& controller, const std::string& file_name) - : controller_(controller), file_name_(file_name) {} + // Cgroup attributes may have different names in the v1 and v2 hierarchies. If `file_v2_name` is + // not empty, `file_name` is the name for the v1 hierarchy and `file_v2_name` is the name for + // the v2 hierarchy. If `file_v2_name` is empty, `file_name` is used for both hierarchies. + ProfileAttribute(const CgroupController& controller, const std::string& file_name, + const std::string& file_v2_name) + : controller_(controller), file_name_(file_name), file_v2_name_(file_v2_name) {} ~ProfileAttribute() = default; const CgroupController* controller() const override { return &controller_; } @@ -50,6 +54,7 @@ class ProfileAttribute : public IProfileAttribute { private: CgroupController controller_; std::string file_name_; + std::string file_v2_name_; }; // Abstract profile element