You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bb...@apache.org on 2018/03/06 14:28:14 UTC

mesos git commit: Simplified system requirements of balloon executor.

Repository: mesos
Updated Branches:
  refs/heads/master 8f4552e37 -> 477d49a2f


Simplified system requirements of balloon executor.

The ballon executor demonstrates that if memory is isolated, executors
can get terminated should they exceed limits. For that the executor
allocates increasing amounts of memory. To make sure that the isolator
measurement is not skewed in the presence of swap, the executor
additionally locks the memory to make sure all allocated memory is
accounted for by the isolator.

Since the amount of memory a process can restricted on the system
level with `RLIMIT_MEMLOCK`, running this example can be impossible on
some setups.

This patch removes unneeded locking of memory on systems not using
swap. With that this example can be run on more setups, e.g., under
restricted accounts if no swap is used.

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


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

Branch: refs/heads/master
Commit: 477d49a2f01c3a604e43af9efbf1332b864bfc70
Parents: 8f4552e
Author: Benjamin Bannier <be...@mesosphere.io>
Authored: Tue Mar 6 15:17:06 2018 +0100
Committer: Benjamin Bannier <bb...@apache.org>
Committed: Tue Mar 6 15:17:06 2018 +0100

----------------------------------------------------------------------
 src/examples/balloon_executor.cpp | 59 +++++++++++++++++++++++++++++++---
 1 file changed, 55 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/477d49a2/src/examples/balloon_executor.cpp
----------------------------------------------------------------------
diff --git a/src/examples/balloon_executor.cpp b/src/examples/balloon_executor.cpp
index 941cbe7..5281db1 100644
--- a/src/examples/balloon_executor.cpp
+++ b/src/examples/balloon_executor.cpp
@@ -23,6 +23,7 @@
 
 #include <sys/mman.h>
 
+#include <fstream>
 #include <iostream>
 #include <string>
 #include <thread>
@@ -39,9 +40,44 @@
 using namespace mesos;
 
 
+// Helper function to check whether the system uses swap.
+//
+// TODO(bbannier): Augment this implementation to explicitly check for swap
+// on platforms other than Linux as well. It might make sense to move this
+// function to stout once the implementation becomes more complete.
+Try<bool> hasSwap() {
+  // We read `/proc/swaps` and check whether any active swap
+  // partitions are listed. The format of that file is e.g.,
+  //
+  //     Filename  Type      Size       Used Priority
+  //     /dev/sda4 partition 1234567890 348  -1
+  //     /dev/sdb4 partition 1234567890 0    -2
+  //
+  // If we find more than one line (including the header) the
+  // system likely uses swap.
+  int numberOfLines = 0;
+
+  std::ifstream swaps("/proc/swaps");
+  std::string line;
+
+  while (std::getline(swaps, line)) {
+    ++numberOfLines;
+  }
+
+  // Check for read errors. This provides a default implementation
+  // for platforms without proc filesystem as well.
+  if (!swaps.eof()) {
+    return Error("Could not determine whether this system uses swap");
+  }
+
+  return numberOfLines > 1;
+}
+
+
 // The amount of memory in MB each balloon step consumes.
 const static size_t BALLOON_STEP_MB = 64;
 
+
 // This function will increase the memory footprint gradually.
 // `TaskInfo.data` specifies the upper limit (in MB) of the memory
 // footprint. The upper limit can be larger than the amount of memory
@@ -61,6 +97,19 @@ void run(ExecutorDriver* driver, const TaskInfo& task)
   CHECK(_limit.isSome());
   const size_t limit = _limit->bytes() / Bytes::MEGABYTES;
 
+  // On systems with swap partitions we explicitly prevent memory used by the
+  // executor from being swapped out with `mlock`. Since the amount of memory a
+  // process can lock is controlled by an rlimit, we only `mlock` when
+  // strictly necessary to prevent complicating the test setup.
+  Try<bool> hasSwap_ = hasSwap();
+  const bool lockMemory = hasSwap_.isError() || hasSwap_.get();
+
+  if (lockMemory) {
+    LOG(INFO)
+      << "System might use swap partitions, will explicitly"
+      << " lock memory to prevent swapping";
+  }
+
   const size_t chunk = BALLOON_STEP_MB * 1024 * 1024;
   for (size_t i = 0; i < limit / BALLOON_STEP_MB; i++) {
     LOG(INFO)
@@ -73,14 +122,16 @@ void run(ExecutorDriver* driver, const TaskInfo& task)
           "Failed to allocate page-aligned memory, posix_memalign").message;
     }
 
-    // We use memset and mlock here to make sure that the memory
-    // actually gets paged in and thus accounted for.
+    // We use `memset` and possibly `mlock` here to make sure that the
+    // memory actually gets paged in and thus accounted for.
     if (memset(buffer, 1, chunk) != buffer) {
       LOG(FATAL) << ErrnoError("Failed to fill memory, memset").message;
     }
 
-    if (mlock(buffer, chunk) != 0) {
-      LOG(FATAL) << ErrnoError("Failed to lock memory, mlock").message;
+    if (lockMemory) {
+      if (mlock(buffer, chunk) != 0) {
+        LOG(FATAL) << ErrnoError("Failed to lock memory, mlock").message;
+      }
     }
 
     // Try not to increase the memory footprint too fast.