Windows: Added `os::set_job_cpu_limit` to stout.

This is used to set a hard cap on the CPU usage for a job object.

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


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

Branch: refs/heads/master
Commit: 8ac83688aa47ad584ba1866c8876aefccdc88156
Parents: c76ddee
Author: Andrew Schwartzmeyer <[email protected]>
Authored: Fri Oct 20 12:01:44 2017 -0700
Committer: Andrew Schwartzmeyer <[email protected]>
Committed: Thu Nov 30 15:54:53 2017 -0800

----------------------------------------------------------------------
 3rdparty/stout/include/stout/windows/os.hpp | 54 ++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/8ac83688/3rdparty/stout/include/stout/windows/os.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/windows/os.hpp 
b/3rdparty/stout/include/stout/windows/os.hpp
index 09469e9..4b95594 100644
--- a/3rdparty/stout/include/stout/windows/os.hpp
+++ b/3rdparty/stout/include/stout/windows/os.hpp
@@ -723,6 +723,60 @@ inline Try<SharedHandle> create_job(const std::wstring& 
name)
 }
 
 
+// `set_job_cpu_limit` sets a CPU limit for the process represented by
+// `pid`, assuming it is assigned to a job object. This function will fail
+// otherwise. This limit is a hard cap enforced by the OS.
+//
+// 
https://msdn.microsoft.com/en-us/library/windows/desktop/hh448384(v=vs.85).aspx 
// NOLINT(whitespace/line_length)
+inline Try<Nothing> set_job_cpu_limit(pid_t pid, double cpus)
+{
+  JOBOBJECT_CPU_RATE_CONTROL_INFORMATION control_info = {};
+  control_info.ControlFlags =
+    JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
+    JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP;
+
+  // This `CpuRate` is the number of cycles per 10,000 cycles, or a percentage
+  // times 100, e.g. 20% yields 20 * 100 = 2,000. However, the `cpus` argument
+  // represents 1 CPU core with `1.0`, so a 100% CPU limit on a quad-core
+  // machine would be `4.0 cpus`. Thus a mapping of `cpus` to `CpuRate` is
+  // `(cpus / os::cpus()) * 100 * 100`, or the requested `cpus` divided by the
+  // number of CPUs to obtain a fractional representation, multiplied by 100 to
+  // make it a percentage, multiplied again by 100 to become a `CpuRate`.
+  Try<long> total_cpus = os::cpus();
+  control_info.CpuRate =
+    static_cast<DWORD>((cpus / total_cpus.get()) * 100 * 100);
+  // This must not be set to 0, so 1 is the minimum.
+  if (control_info.CpuRate < 1) {
+    control_info.CpuRate = 1;
+  }
+
+  Try<std::wstring> name = os::name_job(pid);
+  if (name.isError()) {
+    return Error(name.error());
+  }
+
+  Try<SharedHandle> job_handle = os::open_job(
+      JOB_OBJECT_SET_ATTRIBUTES,
+      false,
+      name.get());
+  if (job_handle.isError()) {
+    return Error(job_handle.error());
+  }
+
+  BOOL result = ::SetInformationJobObject(
+    job_handle.get().get_handle(),
+    JobObjectCpuRateControlInformation,
+    &control_info,
+    sizeof(control_info));
+  if (result == FALSE) {
+    return WindowsError(
+      "os::set_job_cpu_limit: call to `SetInformationJobObject` failed");
+  }
+
+  return Nothing();
+}
+
+
 // `assign_job` assigns a process with `pid` to the job object `job_handle`.
 // Every process started by the `pid` process using `CreateProcess`
 // will also be owned by the job object.

Reply via email to