This is an automated email from the ASF dual-hosted git repository.

bmahler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git


The following commit(s) were added to refs/heads/master by this push:
     new 3642cf9f1 [cgroups2] Add a subset of memory usage statistics.
3642cf9f1 is described below

commit 3642cf9f1ff7e93db99973dab9552609a498e5c1
Author: Devin Leamy <[email protected]>
AuthorDate: Fri Apr 19 18:56:44 2024 -0400

    [cgroups2] Add a subset of memory usage statistics.
    
    Cgroups v2 exposes memory statistics through the 'memory.stat' control.
    
    Here we introduce `cgroups2::memory::stats` to read a subset of the memory
    usage statistics into a new `memory::Stats` object. These statistics will
    be used by the `MemoryControllerProcess` to populate a `ResourceStatistics`
    object, like is done by the `MemorySubsystemProcess` in cgroups v1.
    
    Additional statistics from the 'memory.stat' control can be included as
    they are required.
    
    This closes #564
---
 src/linux/cgroups2.cpp                     | 54 +++++++++++++++++++++++++++++-
 src/linux/cgroups2.hpp                     | 45 +++++++++++++++++++++++++
 src/tests/containerizer/cgroups2_tests.cpp | 10 ++++++
 3 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index 2dd197c4c..f309d604d 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -811,6 +811,48 @@ const string LOW = "memory.low";
 const string HIGH = "memory.high";
 const string MAX = "memory.max";
 const string MIN = "memory.min";
+const string STAT = "memory.stat";
+
+namespace stat {
+
+Try<Stats> parse(const string& content)
+{
+  Stats stats;
+
+  foreach (const string& line, strings::split(content, "\n")) {
+    if (line.empty()) {
+      continue;
+    }
+
+    vector<string> tokens = strings::split(line, " ");
+    if (tokens.size() != 2) {
+      return Error("Invalid line format in 'memory.stat'; expected "
+                   "<key> <value> received: '" + line + "'");
+    }
+
+    const string& key = tokens[0];
+    const string& value = tokens[1];
+
+    Try<uint64_t> n = numify<uint64_t>(value);
+    if (n.isError()) {
+      return Error("Failed to numify '" + value + "': " + n.error());
+    }
+    const Bytes bytes(*n);
+
+    if      (key == "anon")         { stats.anon          = bytes; }
+    else if (key == "file")         { stats.file          = bytes; }
+    else if (key == "kernel")       { stats.kernel        = bytes; }
+    else if (key == "kernel_stack") { stats.kernel_stack  = bytes; }
+    else if (key == "pagetables")   { stats.pagetables    = bytes; }
+    else if (key == "sock")         { stats.sock          = bytes; }
+    else if (key == "vmalloc")      { stats.vmalloc       = bytes; }
+    else if (key == "file_mapped")  { stats.file_mapped   = bytes; }
+  }
+
+  return stats;
+}
+
+} // namespace stat {
 
 } // namespace control {
 
@@ -852,7 +894,6 @@ Try<Events> parse(const string& content)
 
 } // namespace events {
 
-
 Future<Nothing> oom(const string& cgroup)
 {
   // TODO(dleamy): Update this to use inotify, rather than polling.
@@ -964,6 +1005,17 @@ Result<Bytes> high(const string& cgroup)
   return internal::parse_bytelimit(*contents);
 }
 
+
+Try<Stats> stats(const string& cgroup)
+{
+  Try<string> contents = cgroups2::read<string>(cgroup, control::STAT);
+  if (contents.isError()) {
+    return Error("Failed to read 'memory.stat': " + contents.error());
+  }
+
+  return control::stat::parse(*contents);
+}
+
 } // namespace memory {
 
 namespace devices {
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index 91f8d65e6..7060573a4 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -243,6 +243,45 @@ Try<BandwidthLimit> max(const std::string& cgroup);
 // See: https://docs.kernel.org/admin-guide/cgroup-v2.html
 namespace memory {
 
+// Memory usage statistics.
+//
+// Snapshot of the 'memory.stat' control file.
+//
+// Note:
+// We only record a subset of the memory statistics; a complete list can be
+// found in the kernel documentation.
+// https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files
+struct Stats
+{
+  // Amount of memory used in anonymous mappings such as brk(), sbrk(),
+  // and mmap(MAP_ANONYMOUS)
+  Bytes anon;
+
+  // Amount of memory used to cache filesystem data, including tmpfs and
+  // shared memory.
+  Bytes file;
+
+  // Amount of total kernel memory, including (kernel_stack, pagetables,
+  // percpu, vmalloc, slab) in addition to other kernel memory use cases.
+  Bytes kernel;
+
+  // Amount of memory allocated to kernel stacks.
+  Bytes kernel_stack;
+
+  // Amount of memory allocated for page tables.
+  Bytes pagetables;
+
+  // Amount of memory used in network transmission buffers.
+  Bytes sock;
+
+  // Amount of memory used for vmap backed memory.
+  Bytes vmalloc;
+
+  // Amount of cached filesystem data mapped with mmap().
+  Bytes file_mapped;
+};
+
+
 // Cgroup memory controller events.
 //
 // Snapshot of the 'memory.events' or 'memory.local.events' control files.
@@ -358,6 +397,12 @@ Try<Nothing> set_high(
 // Cannot be used for the root cgroup.
 Result<Bytes> high(const std::string& cgroup);
 
+
+// Get the memory usage statistics for a cgroup.
+//
+// Cannot be used for the root cgroup.
+Try<Stats> stats(const std::string& cgroup);
+
 } // namespace memory {
 
 namespace devices {
diff --git a/src/tests/containerizer/cgroups2_tests.cpp 
b/src/tests/containerizer/cgroups2_tests.cpp
index 4cffa80f1..592c4bce6 100644
--- a/src/tests/containerizer/cgroups2_tests.cpp
+++ b/src/tests/containerizer/cgroups2_tests.cpp
@@ -331,6 +331,16 @@ TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryUsage)
 }
 
 
+TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryStats)
+{
+  ASSERT_SOME(enable_controllers({"memory"}));
+
+  ASSERT_SOME(cgroups2::create(TEST_CGROUP));
+  ASSERT_SOME(cgroups2::controllers::enable(TEST_CGROUP, {"memory"}));
+  ASSERT_SOME(cgroups2::memory::stats(TEST_CGROUP));
+}
+
+
 TEST_F(Cgroups2Test, ROOT_CGROUPS2_MemoryLow)
 {
   ASSERT_SOME(enable_controllers({"memory"}));

Reply via email to