You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by gi...@apache.org on 2017/07/31 22:46:14 UTC

[3/5] mesos git commit: Added stats/control helpers for the Blkio cgroup subsystem.

Added stats/control helpers for the Blkio cgroup subsystem.

- Data structure for Blkio entities
- Stats helpers for blkio.throttle.io* (generic blkio stats)
- Stats helpers for blkio.io* (CFQ related stats)
- Comments from the kernel blkio doc for helper functions

Review: https://reviews.apache.org/r/60933/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1b89fb07
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1b89fb07
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1b89fb07

Branch: refs/heads/master
Commit: 1b89fb07419aa53cae661a1715b3258a8e75c140
Parents: 9ed6840
Author: Gilbert Song <so...@gmail.com>
Authored: Mon Jul 31 15:45:36 2017 -0700
Committer: Gilbert Song <so...@gmail.com>
Committed: Mon Jul 31 15:45:36 2017 -0700

----------------------------------------------------------------------
 src/linux/cgroups.cpp | 345 +++++++++++++++++++++++++++++++++++++++++++++
 src/linux/cgroups.hpp | 237 +++++++++++++++++++++++++++++++
 2 files changed, 582 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1b89fb07/src/linux/cgroups.cpp
----------------------------------------------------------------------
diff --git a/src/linux/cgroups.cpp b/src/linux/cgroups.cpp
index 334005a..28c31f6 100644
--- a/src/linux/cgroups.cpp
+++ b/src/linux/cgroups.cpp
@@ -1925,6 +1925,351 @@ Result<string> cgroup(pid_t pid, const string& subsystem)
 } // namespace internal {
 
 
+namespace blkio {
+
+Result<string> cgroup(pid_t pid)
+{
+  return internal::cgroup(pid, "blkio");
+}
+
+
+Try<Device> Device::parse(const string& s)
+{
+  vector<string> device = strings::tokenize(s, ":");
+  if (device.size() != 2) {
+    return Error("Invalid major:minor device number: '" + s + "'");
+  }
+
+  Try<unsigned int> major = numify<unsigned int>(device[0]);
+  if (major.isError()) {
+    return Error("Invalid device major number: '" + device[0] + "'");
+  }
+
+  Try<unsigned int> minor = numify<unsigned int>(device[1]);
+  if (minor.isError()) {
+    return Error("Invalid device minor number: '" + device[1] + "'");
+  }
+
+  return Device(makedev(major.get(), minor.get()));
+}
+
+
+static bool isOperation(const string& s)
+{
+  return (s == "Total" ||
+          s == "Read" ||
+          s == "Write" ||
+          s == "Sync" ||
+          s == "Async");
+}
+
+
+static Try<Operation> parseOperation(const string& s)
+{
+  if (s == "Total") {
+    return Operation::TOTAL;
+  } else if (s == "Read") {
+    return Operation::READ;
+  } else if (s == "Write") {
+    return Operation::WRITE;
+  } else if (s == "Sync") {
+    return Operation::SYNC;
+  } else if (s == "Async") {
+    return Operation::ASYNC;
+  }
+
+  return Error("Invalid Operation value: '" + s + "'");
+}
+
+
+Try<Value> Value::parse(const string& s)
+{
+  vector<string> tokens = strings::tokenize(s, " ");
+  if (tokens.size() == 1) {
+    Try<uint64_t> value = numify<uint64_t>(tokens[0]);
+    if (value.isError()) {
+      return Error("Value is not a number: '" + tokens[0] + "'");
+    }
+
+    return Value{None(), None(), value.get()};
+  }
+
+  Option<Device> device;
+  int offset = 0;
+
+  if (tokens.size() == 3) {
+    Try<Device> dev = Device::parse(tokens[0]);
+    if (dev.isError()) {
+      return Error(dev.error());
+    }
+
+    device = dev.get();
+    offset++;
+  } else if (tokens.size() != 2) {
+    return Error("Invalid blkio value: '" + s + "'");
+  }
+
+  if (!isOperation(tokens[offset])) {
+    Try<Device> dev = Device::parse(tokens[offset]);
+    if (dev.isError()) {
+      return Error(dev.error());
+    }
+
+    Try<uint64_t> value = numify<uint64_t>(tokens[offset + 1]);
+    if (value.isError()) {
+      return Error("Value is not a number: '" + tokens[offset + 1] + "'");
+    }
+
+    return Value{dev.get(), None(), value.get()};
+  }
+
+  Try<Operation> operation = parseOperation(tokens[offset]);
+  if (operation.isError()) {
+    return Error(operation.error());
+  }
+
+  Try<uint64_t> value = numify<uint64_t>(tokens[offset + 1]);
+  if (value.isError()) {
+    return Error("Value is not a number: " + value.error());
+  }
+
+  return Value{device, operation.get(), value.get()};
+}
+
+
+static Try<vector<Value>> readEntries(
+    const string& hierarchy,
+    const string& cgroup,
+    const string& control)
+{
+  Try<string> read = cgroups::read(hierarchy, cgroup, control);
+  if (read.isError()) {
+    return Error("Failed to read from '" + control + "': " + read.error());
+  }
+
+  vector<Value> entries;
+
+  foreach (const string& s, strings::tokenize(read.get(), "\n")) {
+    Try<Value> value = Value::parse(s);
+    if (value.isError()) {
+      return Error("Failed to parse blkio value '" + s + "' from '" +
+                   control + "': " + value.error());
+    }
+
+    entries.push_back(value.get());
+  }
+
+  return entries;
+}
+
+
+namespace cfq {
+
+Try<vector<Value>> time(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.time");
+}
+
+
+Try<vector<Value>> time_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.time_recursive");
+}
+
+
+Try<vector<Value>> sectors(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.sectors");
+}
+
+
+Try<vector<Value>> sectors_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.sectors_recursive");
+}
+
+
+Try<vector<Value>> io_merged(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_merged");
+}
+
+
+Try<vector<Value>> io_merged_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_merged_recursive");
+}
+
+
+Try<vector<Value>> io_queued(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_queued");
+}
+
+
+Try<vector<Value>> io_queued_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_queued_recursive");
+}
+
+
+Try<vector<Value>> io_service_bytes(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_service_bytes");
+}
+
+
+Try<vector<Value>> io_service_bytes_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_service_bytes_recursive");
+}
+
+
+Try<vector<Value>> io_service_time(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_service_time");
+}
+
+
+Try<vector<Value>> io_service_time_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_service_time_recursive");
+}
+
+
+Try<vector<Value>> io_serviced(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_serviced");
+}
+
+
+Try<vector<Value>> io_serviced_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_serviced_recursive");
+}
+
+
+Try<vector<Value>> io_wait_time(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_wait_time");
+}
+
+
+Try<vector<Value>> io_wait_time_recursive(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.io_wait_time_recursive");
+}
+
+} // namespace cfq {
+
+
+namespace throttle {
+
+Try<vector<Value>> io_service_bytes(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.throttle.io_service_bytes");
+}
+
+
+Try<vector<Value>> io_serviced(
+    const string& hierarchy,
+    const string& cgroup)
+{
+  return readEntries(
+      hierarchy,
+      cgroup,
+      "blkio.throttle.io_serviced");
+}
+
+} // namespace throttle {
+} // namespace blkio {
+
+
 namespace cpu {
 
 Result<string> cgroup(pid_t pid)

http://git-wip-us.apache.org/repos/asf/mesos/blob/1b89fb07/src/linux/cgroups.hpp
----------------------------------------------------------------------
diff --git a/src/linux/cgroups.hpp b/src/linux/cgroups.hpp
index eaf0dca..964543c 100644
--- a/src/linux/cgroups.hpp
+++ b/src/linux/cgroups.hpp
@@ -401,6 +401,243 @@ Try<hashmap<std::string, uint64_t>> stat(
     const std::string& file);
 
 
+// Blkio subsystem.
+namespace blkio {
+
+// Returns the cgroup that the specified pid is a member of within the
+// hierarchy that the 'blkio' subsystem is mounted, or None if the subsystem
+// is not mounted or the pid is not a member of a cgroup.
+Result<std::string> cgroup(pid_t pid);
+
+
+// Wrapper class for dev_t.
+class Device
+{
+public:
+  constexpr Device(dev_t device) : value(device) {}
+  inline unsigned int getMajor() const { return major(value); }
+  inline unsigned int getMinor() const { return minor(value); }
+
+  inline bool operator==(const Device& that) const
+  {
+    return value == that.value;
+  }
+
+  inline bool operator!=(const Device& that) const
+  {
+    return value != that.value;
+  }
+
+  inline operator dev_t() const { return value; }
+
+public:
+  static Try<Device> parse(const std::string& s);
+
+private:
+  dev_t value;
+};
+
+
+enum class Operation {
+  TOTAL,
+  READ,
+  WRITE,
+  SYNC,
+  ASYNC,
+};
+
+
+// Entry for a blkio file. The format of each entry can either be:
+// 1. <value>
+// 2. <dev> <value>
+// 3. <dev> <op> <value>
+// 4. <op> <value>
+//
+// For details:
+// https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt
+struct Value
+{
+  Option<Device> device;
+  Option<Operation> op;
+  uint64_t value;
+
+  static Try<Value> parse(const std::string& s);
+};
+
+
+namespace cfq {
+
+Try<std::vector<Value>> time(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+Try<std::vector<Value>> time_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+Try<std::vector<Value>> sectors(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+Try<std::vector<Value>> sectors_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total number of bios/requests merged into requests
+// belonging to the given cgroup from blkio.io_merged.
+Try<std::vector<Value>> io_merged(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total number of bios/requests merged into requests
+// belonging to the given cgroup and all its descendants from
+// blkio.io_merged_recursive.
+Try<std::vector<Value>> io_merged_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total number of requests queued up in the given
+// cgroup from blkio.io_queued.
+Try<std::vector<Value>> io_queued(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total number of requests queued up in the given
+// cgroup and all its descendants from blkio.io_queued_recursive.
+Try<std::vector<Value>> io_queued_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the number of bytes transferred to/from the disk by
+// the given cgroup from blkio.io_service_bytes.
+Try<std::vector<Value>> io_service_bytes(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the number of bytes transferred to/from the disk by
+// the given cgroup and all its descendants from
+// blkio.io_service_bytes_recursive.
+Try<std::vector<Value>> io_service_bytes_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total amount of time between request dispatch and
+// completion by the IOs done by the given cgroup from
+// blkio.io_service_time.
+Try<std::vector<Value>> io_service_time(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total amount of time between request dispatch and
+// completion by the IOs done by the given cgroup and all its
+// descendants from blkio.io_service_time_recursive.
+Try<std::vector<Value>> io_service_time_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the number of IOs (bio) issued to the disk by the given
+// cgroup from blkio.io_serviced.
+Try<std::vector<Value>> io_serviced(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the number of IOs (bio) issued to the disk by the given
+// cgroup and all its descendants from blkio.io_serviced_recursive.
+Try<std::vector<Value>> io_serviced_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total amount of time the IOs for the given cgroup
+// spent waiting in the schedule queues for service from
+// blkio.io_wait_time.
+Try<std::vector<Value>> io_wait_time(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the total amount of time the IOs for the given cgroup
+// and all its descendants spent waiting in the scheduler queues
+// for service from blkio.io_wait_time_recursive.
+Try<std::vector<Value>> io_wait_time_recursive(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+} // namespace cfq {
+
+
+namespace throttle {
+
+// Returns the numbers of bytes transferred to/from the disk for
+// the given cgroup from blkio.throttle.io_service_bytes.
+Try<std::vector<Value>> io_service_bytes(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+
+// Returns the numbers of IOs (bio) issued to the disk for the
+// given cgroup from blkio.throttle.io_serviced.
+Try<std::vector<Value>> io_serviced(
+    const std::string& hierarchy,
+    const std::string& cgroup);
+
+} // namespace throttle {
+
+
+inline std::ostream& operator<<(std::ostream& stream, const Device& device)
+{
+  return stream << device.getMajor() << ':' << device.getMinor();
+}
+
+
+inline std::ostream& operator<<(std::ostream& stream, const Operation op)
+{
+  switch (op) {
+    case Operation::TOTAL:
+      return stream << "Total";
+    case Operation::READ:
+      return stream << "Read";
+    case Operation::WRITE:
+      return stream << "Write";
+    case Operation::SYNC:
+      return stream << "Sync";
+    case Operation::ASYNC:
+      return stream << "Async";
+  }
+
+  UNREACHABLE();
+}
+
+
+inline std::ostream& operator<<(std::ostream& stream, const Value& value)
+{
+  if (value.device.isSome()) {
+    stream << value.device.get() << ' ';
+  }
+
+  if (value.op.isSome()) {
+    stream << value.op.get() << ' ';
+  }
+
+  return stream << value.value;
+}
+
+} // namespace blkio {
+
+
 // Cpu controls.
 namespace cpu {