X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FMemoryMapping.cpp;h=71918c4e34ab067759aaa1a8514b5247492e7f0e;hb=6b459b753941bef25da10004f17580c18dd64af7;hp=a6ad326a09372de32080e2a27efd6f2093274c16;hpb=75f93a6620f11ebbb5453dea49a8bf201e25b390;p=folly.git diff --git a/folly/MemoryMapping.cpp b/folly/MemoryMapping.cpp index a6ad326a..71918c4e 100644 --- a/folly/MemoryMapping.cpp +++ b/folly/MemoryMapping.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,23 +14,40 @@ * limitations under the License. */ -#include "folly/MemoryMapping.h" -#include "folly/Format.h" -#include "folly/Portability.h" +#include + +#include +#include +#include + +#include +#include +#include #ifdef __linux__ -#include "folly/experimental/io/HugePages.h" +#include #endif #include -#include #include #include -#include -DEFINE_int64(mlock_chunk_size, 1 << 20, // 1MB +static constexpr ssize_t kDefaultMlockChunkSize = +#ifndef _MSC_VER + // Linux implementations of unmap/mlock/munlock take a kernel + // semaphore and block other threads from doing other memory + // operations. Split the operations in chunks. + (1 << 20) // 1MB +#else // _MSC_VER + // MSVC doesn't have this problem, and calling munmap many times + // with the same address is a bad idea with the windows implementation. + (-1) +#endif // _MSC_VER + ; + +DEFINE_int64(mlock_chunk_size, kDefaultMlockChunkSize, "Maximum bytes to mlock/munlock/munmap at once " - "(will be rounded up to PAGESIZE)"); + "(will be rounded up to PAGESIZE). Ignored if negative."); #ifndef MAP_POPULATE #define MAP_POPULATE 0 @@ -38,7 +55,7 @@ DEFINE_int64(mlock_chunk_size, 1 << 20, // 1MB namespace folly { -MemoryMapping::MemoryMapping(MemoryMapping&& other) { +MemoryMapping::MemoryMapping(MemoryMapping&& other) noexcept { swap(other); } @@ -52,7 +69,10 @@ MemoryMapping::MemoryMapping(File file, off_t offset, off_t length, MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length, Options options) - : MemoryMapping(File(name), offset, length, options) { } + : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY), + offset, + length, + options) { } MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length, Options options) @@ -204,8 +224,8 @@ off_t memOpChunkSize(off_t length, off_t pageSize) { bool memOpInChunks(std::function op, void* mem, size_t bufSize, off_t pageSize, size_t& amountSucceeded) { - // unmap/mlock/munlock take a kernel semaphore and block other threads from - // doing other memory operations. If the size of the buffer is big the + // Linux' unmap/mlock/munlock take a kernel semaphore and block other threads + // from doing other memory operations. If the size of the buffer is big the // semaphore can be down for seconds (for benchmarks see // http://kostja-osipov.livejournal.com/42963.html). Doing the operations in // chunks breaks the locking into intervals and lets other threads do memory @@ -237,12 +257,12 @@ bool MemoryMapping::mlock(LockMode lock) { return true; } - auto msg(folly::format( - "mlock({}) failed at {}", - mapLength_, amountSucceeded).str()); - - if (lock == LockMode::TRY_LOCK && (errno == EPERM || errno == ENOMEM)) { + auto msg = + folly::format("mlock({}) failed at {}", mapLength_, amountSucceeded); + if (lock == LockMode::TRY_LOCK && errno == EPERM) { PLOG(WARNING) << msg; + } else if (lock == LockMode::TRY_LOCK && errno == ENOMEM) { + VLOG(1) << msg; } else { PLOG(FATAL) << msg; } @@ -280,17 +300,36 @@ 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_; + + // Include the entire start page: round down to page boundary. + const auto offMisalign = offset % options_.pageSize; + offset -= offMisalign; + length += offMisalign; + + // Round the last page down to page boundary. + if (offset + length != size_t(mapLength_)) { + length -= length % options_.pageSize; } + + if (length == 0) { + return; + } + + char* mapStart = static_cast(mapStart_) + offset; + PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise"; } MemoryMapping& MemoryMapping::operator=(MemoryMapping other) { @@ -298,7 +337,7 @@ MemoryMapping& MemoryMapping::operator=(MemoryMapping other) { return *this; } -void MemoryMapping::swap(MemoryMapping& other) { +void MemoryMapping::swap(MemoryMapping& other) noexcept { using std::swap; swap(this->file_, other.file_); swap(this->mapStart_, other.mapStart_); @@ -308,7 +347,7 @@ void MemoryMapping::swap(MemoryMapping& other) { swap(this->data_, other.data_); } -void swap(MemoryMapping& a, MemoryMapping& b) { a.swap(b); } +void swap(MemoryMapping& a, MemoryMapping& b) noexcept { a.swap(b); } void alignedForwardMemcpy(void* dst, const void* src, size_t size) { assert(reinterpret_cast(src) % alignof(unsigned long) == 0);