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 a64260202 [cgroups2] Add an interface to read and write the CPU 
bandwidth limit.
a64260202 is described below

commit a642602029cfd2666715d328882615d68e3ce3e1
Author: Devin Leamy <[email protected]>
AuthorDate: Mon Apr 1 13:56:27 2024 -0400

    [cgroups2] Add an interface to read and write the CPU bandwidth limit.
    
    In cgroups v2, the CPU bandwidth and bandwidth period (duration over
    which the bandwidth can be spent) are set in `cpu.max`. This patch
    introduces an interface to read and update these values.
    
    A `BandwidthLimit` object is introduced, which represents a snapshot
    of the `cpu.max` control file.
    
    Note: This stands in contrast to cgroups v1 where the period and
    bandwidth were set in separate control files, `cpu.cfs_period_us`
    and `cpu.cfs_quota_us` respectively.
    
    This closes #541
---
 src/linux/cgroups2.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/linux/cgroups2.hpp | 28 +++++++++++++++
 2 files changed, 125 insertions(+)

diff --git a/src/linux/cgroups2.cpp b/src/linux/cgroups2.cpp
index 1c4063be8..5241d65c2 100644
--- a/src/linux/cgroups2.cpp
+++ b/src/linux/cgroups2.cpp
@@ -22,6 +22,7 @@
 #include <string>
 #include <vector>
 
+#include <stout/none.hpp>
 #include <stout/numify.hpp>
 #include <stout/os.hpp>
 #include <stout/path.hpp>
@@ -482,6 +483,47 @@ Try<set<string>> enabled(const string& cgroup)
 
 namespace cpu {
 
+BandwidthLimit::BandwidthLimit(Duration _limit, Duration _period)
+  : limit{_limit},
+    period{_period} {}
+
+
+Try<BandwidthLimit> parse_bandwidth(const string& content)
+{
+  // Format
+  // -----------------------------
+  // $MAX $PERIOD
+  // -----------------------------
+  // $MAX        Maximum CPU time, in microseconds, processes in the cgroup can
+  //             collectively use during one $PERIOD. If set to "max" then 
there
+  //             is no limit.
+  //
+  // $PERIOD     Length of one period, in microseconds.
+  vector<string> split = strings::split(content, " ");
+  if (split.size() != 2) {
+    return Error("Expected format '$MAX $PERIOD'"
+                 " but received '" + content + "'");
+  }
+
+  if (split[0] == "max") {
+    return cpu::BandwidthLimit();
+  }
+
+  Try<Duration> limit = Duration::parse(split[0] + "us");
+  if (limit.isError()) {
+    return Error("Failed to parse cpu.max's limit of '" + split[0] + "': "
+                 + limit.error());
+  }
+
+  Try<Duration> period = Duration::parse(split[1] + "us");
+  if (period.isError()) {
+    return Error("Failed to parse cpu.max's period of '" + split[1] + "': "
+                 + period.error());
+  }
+
+  return BandwidthLimit(*limit, *period);
+}
+
 namespace control {
 
 const std::string IDLE = "cpu.idle";
@@ -538,6 +580,7 @@ Try<Stats> parse(const string& content)
 
 } // namespace control {
 
+
 Try<Nothing> weight(const string& cgroup, uint64_t weight)
 {
   if (cgroup == ROOT_CGROUP) {
@@ -571,6 +614,60 @@ Try<cpu::Stats> stats(const string& cgroup)
   return cpu::control::stat::parse(*content);
 }
 
+
+Try<Nothing> set_max(const string& cgroup, const cpu::BandwidthLimit& limit)
+{
+  if (cgroup == ROOT_CGROUP) {
+    return Error("Operation not supported for the root cgroup");
+  }
+
+  if (limit.limit.isNone()) {
+    return cgroups2::write(cgroup, cpu::control::MAX, "max");
+  }
+
+  if (limit.period.isNone()) {
+    return Error("Invalid bandwidth limit: period can only be None"
+                 " for a limitless bandwidth limit");
+  }
+
+  if (limit.period->ns() < 0 || limit.limit->ns() < 0
+      || limit.period->ns() % 1000 > 0 || limit.limit->ns() % 1000 > 0) {
+    return Error("Invalid bandwidth limit: period and limit must be"
+                 " positive and microsecond level granularity, received"
+                 " period=" + stringify(*limit.period)
+                 + " limit=" + stringify(*limit.limit));
+  }
+
+  return cgroups2::write(
+      cgroup,
+      cpu::control::MAX,
+      stringify(static_cast<uint64_t>(limit.limit->us()))
+        + " "
+        + stringify(static_cast<uint64_t>(limit.period->us())));
+}
+
+
+Try<cpu::BandwidthLimit> max(const string& cgroup)
+{
+  if (cgroup == ROOT_CGROUP) {
+    return Error("Operation not supported for the root cgroup");
+  }
+
+  Try<string> content = cgroups2::read<string>(cgroup, cpu::control::MAX);
+  if (content.isError()) {
+    return Error("Failed the read 'cpu.max' for cgroup '" + cgroup + "': "
+                 + content.error());
+  }
+
+  Try<BandwidthLimit> limit = parse_bandwidth(*content);
+  if (limit.isError()) {
+    return Error("Failed to parse '" + *content + "' as a bandwidth limit: "
+                 + limit.error());
+  }
+
+  return *limit;
+}
+
 } // namespace cpu {
 
 namespace devices {
diff --git a/src/linux/cgroups2.hpp b/src/linux/cgroups2.hpp
index 024b271a5..17b9b1af8 100644
--- a/src/linux/cgroups2.hpp
+++ b/src/linux/cgroups2.hpp
@@ -168,9 +168,37 @@ struct Stats
 };
 
 
+// Specifies the maximum CPU bandwidth available over a given period.
+// Represents a snapshot of the 'cpu.max' control file.
+struct BandwidthLimit
+{
+  // Constructs a limitless bandwidth limit.
+  BandwidthLimit() = default;
+
+  // Create a bandwidth limit of `limit` every time `period`.
+  BandwidthLimit(Duration limit, Duration period);
+
+  // Maximum CPU time quota (AKA bandwidth) per period.
+  Option<Duration> limit;
+
+  // Period where the limit can be used. Can only be None if `limit`
+  // is also None, implying that there is no bandwidth limit.
+  Option<Duration> period;
+};
+
 // Get the CPU usage statistics for a cgroup.
 Try<Stats> stats(const std::string& cgroup);
 
+
+// Set the bandwidth limit for a cgroup.
+// Cannot be used for the root cgroup.
+Try<Nothing> set_max(const std::string& cgroup, const BandwidthLimit& limit);
+
+
+// Determine the bandwidth limit for a cgroup.
+// Cannot be used for the root cgroup.
+Try<BandwidthLimit> max(const std::string& cgroup);
+
 } // namespace cpu {
 
 namespace devices {

Reply via email to