You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2014/02/28 07:54:50 UTC

git commit: Added a test for CFS cpu limits in the cpu isolator.

Repository: mesos
Updated Branches:
  refs/heads/master bb6f1e01e -> 5c1d2fb91


Added a test for CFS cpu limits in the cpu isolator.

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


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

Branch: refs/heads/master
Commit: 5c1d2fb91be90c337e64647b04607dac99b36fc4
Parents: bb6f1e0
Author: Ian Downes <ia...@gmail.com>
Authored: Thu Feb 27 22:32:48 2014 -0800
Committer: Vinod Kone <vi...@twitter.com>
Committed: Thu Feb 27 22:47:40 2014 -0800

----------------------------------------------------------------------
 src/tests/isolator_tests.cpp | 97 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/5c1d2fb9/src/tests/isolator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/isolator_tests.cpp b/src/tests/isolator_tests.cpp
index 13f425b..2aa06ca 100644
--- a/src/tests/isolator_tests.cpp
+++ b/src/tests/isolator_tests.cpp
@@ -38,6 +38,9 @@
 #include "slave/flags.hpp"
 #include "slave/slave.hpp"
 
+#ifdef __linux__
+#include "slave/containerizer/cgroups_launcher.hpp"
+#endif // __linux__
 #include "slave/containerizer/isolator.hpp"
 #include "slave/containerizer/launcher.hpp"
 
@@ -59,6 +62,7 @@ using namespace process;
 using mesos::internal::master::Master;
 #ifdef __linux__
 using mesos::internal::slave::CgroupsCpushareIsolatorProcess;
+using mesos::internal::slave::CgroupsLauncher;
 using mesos::internal::slave::CgroupsMemIsolatorProcess;
 #endif // __linux__
 using mesos::internal::slave::Isolator;
@@ -90,8 +94,11 @@ int execute(const std::string& command, int pipes[2])
 
   execl("/bin/sh", "sh", "-c", command.c_str(), (char*) NULL);
 
-  std::cerr << "Should not reach here!" << std::endl;
-  abort();
+  const char* message = "Child failed to exec";
+  while (write(STDERR_FILENO, message, strlen(message)) == -1 &&
+         errno == EINTR);
+
+  _exit(1);
 }
 
 
@@ -294,6 +301,92 @@ TYPED_TEST(CpuIsolatorTest, SystemCpuUsage)
 }
 
 
+#ifdef __linux__
+class LimitedCpuIsolatorTest : public MesosTest {};
+
+TEST_F(LimitedCpuIsolatorTest, CgroupsCfs)
+{
+  Flags flags;
+
+  // Enable CFS to cap CPU utilization.
+  flags.cgroups_enable_cfs = true;
+
+  Try<Isolator*> isolator = CgroupsCpushareIsolatorProcess::create(flags);
+  CHECK_SOME(isolator);
+
+  Try<Launcher*> launcher = CgroupsLauncher::create(flags);
+  CHECK_SOME(launcher);
+
+  // Set the executor's resources to 0.5 cpu.
+  ExecutorInfo executorInfo;
+  executorInfo.mutable_resources()->CopyFrom(
+      Resources::parse("cpus:0.5").get());
+
+  ContainerID containerId;
+  containerId.set_value("mesos_test_cfs_cpu_limit");
+
+  AWAIT_READY(isolator.get()->prepare(containerId, executorInfo));
+
+  // Generate random numbers to max out a single core. We'll run this for 0.5
+  // seconds of wall time so it should consume approximately 250 ms of total
+  // cpu time when limited to 0.5 cpu. We use /dev/urandom to prevent blocking
+  // on Linux when there's insufficient entropy.
+  string command = "cat /dev/urandom > /dev/null & "
+    "export MESOS_TEST_PID=$! && "
+    "sleep 0.5 && "
+    "kill $MESOS_TEST_PID";
+
+  int pipes[2];
+  ASSERT_NE(-1, ::pipe(pipes));
+
+  lambda::function<int()> inChild = lambda::bind(&execute, command, pipes);
+
+  Try<pid_t> pid = launcher.get()->fork(containerId, inChild);
+  ASSERT_SOME(pid);
+
+  // Reap the forked child.
+  Future<Option<int> > status = process::reap(pid.get());
+
+  // Continue in the parent.
+  ::close(pipes[0]);
+
+  // Isolate the forked child.
+  AWAIT_READY(isolator.get()->isolate(containerId, pid.get()));
+
+  // Now signal the child to continue.
+  int buf;
+  ASSERT_LT(0, ::write(pipes[1],  &buf, sizeof(buf)));
+  ::close(pipes[1]);
+
+  // Wait for the command to complete.
+  AWAIT_READY(process::reap(pid.get()));
+
+  Future<ResourceStatistics> usage = isolator.get()->usage(containerId);
+  AWAIT_READY(usage);
+
+  // Expect that no more than 300 ms of cpu time has been consumed. We also
+  // check that at least 50 ms of cpu time has been consumed so this test will
+  // fail if the host system is very heavily loaded. This behavior is correct
+  // because under such conditions we aren't actually testing the CFS cpu
+  // limiter.
+  double cpuTime = usage.get().cpus_system_time_secs() +
+                   usage.get().cpus_user_time_secs();
+
+  EXPECT_GE(0.30, cpuTime);
+  EXPECT_LE(0.05, cpuTime);
+
+  // Ensure all processes are killed.
+  AWAIT_READY(launcher.get()->destroy(containerId));
+
+  // Let the isolator clean up.
+  AWAIT_READY(isolator.get()->cleanup(containerId));
+
+  delete isolator.get();
+  delete launcher.get();
+}
+#endif // __linux__
+
+
 template <typename T>
 class MemIsolatorTest : public MesosTest {};