folly: MemoryMapping: add offset/size params to advise
authorLucian Grijincu <lucian@fb.com>
Wed, 8 Apr 2015 18:14:28 +0000 (11:14 -0700)
committerViswanath Sivakumar <viswanath@fb.com>
Fri, 10 Apr 2015 03:34:38 +0000 (20:34 -0700)
Test Plan: ran it

Reviewed By: philipp@fb.com

Subscribers: folly-diffs@, yfeldblum, chalfant

FB internal diff: D1974936

Signature: t1:1974936:1428453023:1a83ed8336f75b745bffc633b8471231423b0fb0

folly/MemoryMapping.cpp
folly/MemoryMapping.h
folly/test/MemoryMappingTest.cpp

index 43889257b5aa6c307a4cc9785264f4d1ab95e0f6..3d8e3a55bf2aeaef44477261133c40a353fbe98f 100644 (file)
  */
 
 #include <folly/MemoryMapping.h>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
 #include <folly/Format.h>
-#include <folly/Portability.h>
 
 #ifdef __linux__
 #include <folly/experimental/io/HugePages.h>
@@ -240,9 +244,8 @@ bool MemoryMapping::mlock(LockMode lock) {
     return true;
   }
 
-  auto msg(folly::format(
-    "mlock({}) failed at {}",
-    mapLength_, amountSucceeded).str());
+  auto msg =
+    folly::sformat("mlock({}) failed at {}", mapLength_, amountSucceeded);
 
   if (lock == LockMode::TRY_LOCK && (errno == EPERM || errno == ENOMEM)) {
     PLOG(WARNING) << msg;
@@ -283,17 +286,35 @@ MemoryMapping::~MemoryMapping() {
     size_t amountSucceeded = 0;
     if (!memOpInChunks(::munmap, mapStart_, mapLength_, options_.pageSize,
                        amountSucceeded)) {
-      PLOG(FATAL) << folly::format(
-        "munmap({}) failed at {}",
-        mapLength_, amountSucceeded).str();
+      PLOG(FATAL) << folly::format("munmap({}) failed at {}",
+                                   mapLength_, amountSucceeded);
     }
   }
 }
 
-void MemoryMapping::advise(int advice) const {
-  if (mapLength_ && ::madvise(mapStart_, mapLength_, advice)) {
-    PLOG(WARNING) << "madvise()";
+void MemoryMapping::advise(int advice) const { advise(advice, 0, mapLength_); }
+
+void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
+  CHECK_LE(offset + length, mapLength_)
+    << " offset: " << offset
+    << " length: " << length
+    << " mapLength_: " << mapLength_;
+
+  if (length == 0) {
+    return;
+  }
+
+  auto offMisalign = offset % options_.pageSize;
+  if (offMisalign != 0) {
+    offset -= offMisalign;
+    length += offMisalign;
   }
+
+  length = (length + options_.pageSize - 1) & ~(options_.pageSize - 1);
+  length = std::min(length, mapLength_ - offset);
+
+  char* mapStart = static_cast<char*>(mapStart_) + offset;
+  PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
 }
 
 MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {
index 158b62ac6a129fce9ee555226096bdcdb7f28ed8..a1ca74440ae1a247ba76029e885894025939a2dd 100644 (file)
@@ -157,6 +157,7 @@ class MemoryMapping : boost::noncopyable {
    * Advise the kernel about memory access.
    */
   void advise(int advice) const;
+  void advise(int advice, size_t offset, size_t length) const;
 
   /**
    * A bitwise cast of the mapped bytes as range of values. Only intended for
index 9d11fbb339e93d7fcc579656e545bbee9747ec5f..70ecc719e1385d8f5b24e9b3a5069392d9dee345 100644 (file)
  * limitations under the License.
  */
 
+#include <sys/mman.h>
 #include <cstdlib>
-#include <gtest/gtest.h>
+#include <folly/FileUtil.h>
 #include <folly/MemoryMapping.h>
+#include <gtest/gtest.h>
 
 namespace folly {
 
@@ -145,4 +147,29 @@ TEST(MemoryMapping, ZeroLength) {
   EXPECT_EQ(0, m.data().size());
 }
 
+TEST(MemoryMapping, Advise) {
+  File f = File::temporary();
+  size_t kPageSize = 4096;
+  size_t size = kPageSize + 10;  // unaligned file size
+  PCHECK(ftruncateNoInt(f.fd(), size) == 0) << size;
+
+  MemoryMapping m(File(f.fd()));
+
+  // NOTE: advise crashes on bad input.
+
+  m.advise(MADV_NORMAL, 0, kPageSize);
+  m.advise(MADV_NORMAL, 1, kPageSize);
+  m.advise(MADV_NORMAL, 0, 2);
+  m.advise(MADV_NORMAL, 1, 2);
+
+  m.advise(MADV_NORMAL, kPageSize, 0);
+  m.advise(MADV_NORMAL, kPageSize, 1);
+  m.advise(MADV_NORMAL, kPageSize, size - kPageSize);
+
+  auto off = kPageSize + 1;
+  m.advise(MADV_NORMAL, off, size - off);
+
+  EXPECT_DEATH(m.advise(MADV_NORMAL, off, size - off + 1), "");
+}
+
 } // namespace folly