diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2022-02-11 14:09:12 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-11 14:09:12 +0100 |
commit | ca7f13cf185e47216b4dc84961c3e25707baab02 (patch) | |
tree | 5cc98741ca8e8b065af2ab2eacc1e14e23d33e33 | |
parent | 662eb8a1c2ed6e4fbe0442beae38a5962faa05f5 (diff) | |
parent | 3adf32e361332b9207a627a9f8d19a57d970f4f0 (diff) |
Merge pull request #21146 from vespa-engine/balder/add-mmappool
Balder/add mmappool
-rw-r--r-- | vespamalloc/src/tests/stacktrace/stacktrace.cpp | 4 | ||||
-rw-r--r-- | vespamalloc/src/tests/test1/new_test.cpp | 15 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/CMakeLists.txt | 4 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/common.h | 2 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/datasegment.h | 6 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/datasegment.hpp | 32 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/malloc.h | 23 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/mmappool.cpp | 103 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/mmappool.h | 33 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/overload.h | 16 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/threadlist.h | 7 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/threadlist.hpp | 7 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/threadpool.h | 13 | ||||
-rw-r--r-- | vespamalloc/src/vespamalloc/malloc/threadpool.hpp | 36 |
14 files changed, 253 insertions, 48 deletions
diff --git a/vespamalloc/src/tests/stacktrace/stacktrace.cpp b/vespamalloc/src/tests/stacktrace/stacktrace.cpp index 2f0d2eb2277..40d77b20e27 100644 --- a/vespamalloc/src/tests/stacktrace/stacktrace.cpp +++ b/vespamalloc/src/tests/stacktrace/stacktrace.cpp @@ -28,7 +28,7 @@ void verify_that_vespamalloc_datasegment_size_exists() { assert(info.keepcost == 0); assert(info.ordblks == 0); assert(info.smblks == 0); - assert(info.uordblks == 0); + assert(info.uordblks > 0); assert(info.usmblks == 0); #else struct mallinfo info = mallinfo(); @@ -42,7 +42,7 @@ void verify_that_vespamalloc_datasegment_size_exists() { assert(info.keepcost == 0); assert(info.ordblks == 0); assert(info.smblks == 0); - assert(info.uordblks == 0); + assert(info.uordblks > 0); assert(info.usmblks == 0); #endif } diff --git a/vespamalloc/src/tests/test1/new_test.cpp b/vespamalloc/src/tests/test1/new_test.cpp index 0723f8cca85..77c07a52918 100644 --- a/vespamalloc/src/tests/test1/new_test.cpp +++ b/vespamalloc/src/tests/test1/new_test.cpp @@ -1,5 +1,6 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/util/size_literals.h> #include <vespa/log/log.h> #include <malloc.h> #include <dlfcn.h> @@ -170,7 +171,19 @@ TEST("verify mallopt") { if (env == MallocLibrary::UNKNOWN) return; EXPECT_EQUAL(0, mallopt(M_MMAP_MAX, 0x1000000)); EXPECT_EQUAL(1, mallopt(M_MMAP_THRESHOLD, 0x1000000)); - EXPECT_EQUAL(1, mallopt(M_MMAP_THRESHOLD, -1)); + EXPECT_EQUAL(1, mallopt(M_MMAP_THRESHOLD, 1_Gi)); +} + +TEST("verify mmap_limit") { + MallocLibrary env = detectLibrary(); + if (env == MallocLibrary::UNKNOWN) return; + EXPECT_EQUAL(1, mallopt(M_MMAP_THRESHOLD, 0x100000)); + auto small = std::make_unique<char[]>(16_Ki); + auto large_1 = std::make_unique<char[]>(1200_Ki); + EXPECT_GREATER(size_t(labs(small.get() - large_1.get())), 1_Ti); + EXPECT_EQUAL(1, mallopt(M_MMAP_THRESHOLD, 1_Gi)); + auto large_2 = std::make_unique<char[]>(1200_Ki); + EXPECT_LESS(size_t(labs(small.get() - large_2.get())), 1_Ti); } diff --git a/vespamalloc/src/vespamalloc/malloc/CMakeLists.txt b/vespamalloc/src/vespamalloc/malloc/CMakeLists.txt index cfa8018e25f..acac1aa5b85 100644 --- a/vespamalloc/src/vespamalloc/malloc/CMakeLists.txt +++ b/vespamalloc/src/vespamalloc/malloc/CMakeLists.txt @@ -4,6 +4,7 @@ vespa_add_library(vespamalloc_malloc OBJECT malloc.cpp allocchunk.cpp common.cpp + mmappool.cpp threadproxy.cpp memblock.cpp datasegment.cpp @@ -17,6 +18,7 @@ vespa_add_library(vespamalloc_mallocd OBJECT mallocd.cpp allocchunk.cpp common.cpp + mmappool.cpp threadproxy.cpp memblockboundscheck.cpp memblockboundscheck_d.cpp @@ -31,6 +33,7 @@ vespa_add_library(vespamalloc_mallocdst16 OBJECT mallocdst16.cpp allocchunk.cpp common.cpp + mmappool.cpp threadproxy.cpp memblockboundscheck.cpp memblockboundscheck_dst.cpp @@ -46,6 +49,7 @@ vespa_add_library(vespamalloc_mallocdst16_nl OBJECT mallocdst16_nl.cpp allocchunk.cpp common.cpp + mmappool.cpp threadproxy.cpp memblockboundscheck.cpp memblockboundscheck_dst.cpp diff --git a/vespamalloc/src/vespamalloc/malloc/common.h b/vespamalloc/src/vespamalloc/malloc/common.h index 4b0af3199a1..65a86b89bf6 100644 --- a/vespamalloc/src/vespamalloc/malloc/common.h +++ b/vespamalloc/src/vespamalloc/malloc/common.h @@ -55,7 +55,7 @@ static constexpr uint32_t NUM_THREADS = 16384; using OSMemory = MmapMemory; using SizeClassT = int; -constexpr size_t ALWAYS_REUSE_LIMIT = 0x200000ul; +constexpr size_t ALWAYS_REUSE_LIMIT = 0x100000ul; inline constexpr int msbIdx(uint64_t v) { return (sizeof(v)*8 - 1) - __builtin_clzl(v); diff --git a/vespamalloc/src/vespamalloc/malloc/datasegment.h b/vespamalloc/src/vespamalloc/malloc/datasegment.h index dc81178150a..d03a585ccc2 100644 --- a/vespamalloc/src/vespamalloc/malloc/datasegment.h +++ b/vespamalloc/src/vespamalloc/malloc/datasegment.h @@ -21,13 +21,14 @@ public: void * getBlock(size_t & oldBlockSize, SizeClassT sc) __attribute__((noinline)); void returnBlock(void *ptr) __attribute__((noinline)); SizeClassT sizeClass(const void * ptr) const { return _blockList[blockId(ptr)].sizeClass(); } + bool containsPtr(const void * ptr) const { return blockId(ptr) < BlockCount; } size_t getMaxSize(const void * ptr) const { return _blockList[blockId(ptr)].getMaxSize(); } const void * start() const { return _osMemory.getStart(); } const void * end() const { return _osMemory.getEnd(); } static SizeClassT adjustedSizeClass(size_t sz) { return (sz >> 16) + 0x400; } static size_t adjustedClassSize(SizeClassT sc) { return (sc > 0x400) ? (sc - 0x400) << 16 : sc; } size_t dataSize() const { return (const char*)end() - (const char*)start(); } - size_t textSize() const { return size_t(start()); } + size_t freeSize() const; size_t infoThread(FILE * os, int level, uint32_t thread, SizeClassT sct, uint32_t maxThreadId=0) const __attribute__((noinline)); void info(FILE * os, size_t level) __attribute__((noinline)); void setupLog(size_t bigMemLogLevel, size_t bigLimit, size_t bigIncrement, size_t allocs2Show) @@ -98,7 +99,8 @@ private: _count--; } } - size_t info(FILE * os, int level) __attribute__((noinline)); + size_t numFreeBlocks() const; + void info(FILE * os) __attribute__((noinline)); private: void * linkOut(size_t findex, size_t left) __attribute__((noinline)); BlockT *_blockList; diff --git a/vespamalloc/src/vespamalloc/malloc/datasegment.hpp b/vespamalloc/src/vespamalloc/malloc/datasegment.hpp index 75ca07a5cf4..80a70b6b5bc 100644 --- a/vespamalloc/src/vespamalloc/malloc/datasegment.hpp +++ b/vespamalloc/src/vespamalloc/malloc/datasegment.hpp @@ -39,6 +39,12 @@ DataSegment<MemBlockPtrT>::DataSegment() : } template<typename MemBlockPtrT> +size_t +DataSegment<MemBlockPtrT>::freeSize() const { + return _freeList.numFreeBlocks() * BlockSize; +} + +template<typename MemBlockPtrT> void * DataSegment<MemBlockPtrT>::getBlock(size_t & oldBlockSize, SizeClassT sc) { const size_t minBlockSize = std::max(size_t(BlockSize), _osMemory.getMinBlockSize()); @@ -273,12 +279,10 @@ void DataSegment<MemBlockPtrT>::info(FILE * os, size_t level) { fprintf(os, "Start at %p, End at %p(%p) size(%ld) partialExtension(%ld) NextLogLimit(%lx) logLevel(%ld)\n", _osMemory.getStart(), _osMemory.getEnd(), sbrk(0), dataSize(), _partialExtension, _nextLogLimit, level); - size_t numFreeBlocks(0), numAllocatedBlocks(0); - { - // Guard sync(_mutex); - numFreeBlocks = _freeList.info(os, level); - _unMappedList.info(os, level); - } + size_t numAllocatedBlocks(0); + size_t numFreeBlocks = _freeList.numFreeBlocks(); + _freeList.info(os); + _unMappedList.info(os); if (level >= 1) { #ifdef PRINT_ALOT SizeClassT oldSc(-17); @@ -430,16 +434,26 @@ size_t DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::lastBlock(size_t nextBloc template<typename MemBlockPtrT> template <int MaxCount> -size_t DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::info(FILE * os, int UNUSED(level)) +void DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::info(FILE * os) { - size_t freeBlockCount(0); for (size_t i=0; i < _count; i++) { size_t index(_freeStartIndex[i]); const BlockT & b = _blockList[index]; - freeBlockCount += b.freeChainLength(); fprintf(os, "Free #%3ld block #%5ld chainlength %5d size %10lu\n", i, index, b.freeChainLength(), size_t(b.freeChainLength())*BlockSize); } +} + +template<typename MemBlockPtrT> +template <int MaxCount> +size_t DataSegment<MemBlockPtrT>::FreeListT<MaxCount>::numFreeBlocks() const +{ + size_t freeBlockCount(0); + for (size_t i=0; i < _count; i++) { + size_t index(_freeStartIndex[i]); + const BlockT & b = _blockList[index]; + freeBlockCount += b.freeChainLength(); + } return freeBlockCount; } diff --git a/vespamalloc/src/vespamalloc/malloc/malloc.h b/vespamalloc/src/vespamalloc/malloc/malloc.h index 2fb0f81826d..f35184cc581 100644 --- a/vespamalloc/src/vespamalloc/malloc/malloc.h +++ b/vespamalloc/src/vespamalloc/malloc/malloc.h @@ -30,13 +30,25 @@ public: void *malloc(size_t sz, std::align_val_t); void *realloc(void *oldPtr, size_t sz); void free(void *ptr) { - freeSC(ptr, _segment.sizeClass(ptr)); + if (_segment.containsPtr(ptr)) { + freeSC(ptr, _segment.sizeClass(ptr)); + } else { + _mmapPool.unmap(MemBlockPtrT(ptr).rawPtr()); + } } void free(void *ptr, size_t sz) { - freeSC(ptr, MemBlockPtrT::sizeClass(MemBlockPtrT::adjustSize(sz))); + if (_segment.containsPtr(ptr)) { + freeSC(ptr, MemBlockPtrT::sizeClass(MemBlockPtrT::adjustSize(sz))); + } else { + _mmapPool.unmap(MemBlockPtrT(ptr).rawPtr()); + } } void free(void *ptr, size_t sz, std::align_val_t alignment) { - freeSC(ptr, MemBlockPtrT::sizeClass(MemBlockPtrT::adjustSize(sz, alignment))); + if (_segment.containsPtr(ptr)) { + freeSC(ptr, MemBlockPtrT::sizeClass(MemBlockPtrT::adjustSize(sz, alignment))); + } else { + _mmapPool.unmap(MemBlockPtrT(ptr).rawPtr()); + } } size_t getMinSizeForAlignment(size_t align, size_t sz) const { return MemBlockPtrT::getMinSizeForAlignment(align, sz); } size_t sizeClass(const void *ptr) const { return _segment.sizeClass(ptr); } @@ -65,6 +77,7 @@ public: _allocPool.setParams(threadCacheLimit); } const DataSegment<MemBlockPtrT> & dataSegment() const { return _segment; } + const MMapPool & mmapPool() const { return _mmapPool; } private: void freeSC(void *ptr, SizeClassT sc); void crash() __attribute__((noinline));; @@ -73,6 +86,7 @@ private: size_t _prAllocLimit; DataSegment<MemBlockPtrT> _segment; AllocPool _allocPool; + MMapPool _mmapPool; ThreadListT _threadList; }; @@ -82,7 +96,8 @@ MemoryManager<MemBlockPtrT, ThreadListT>::MemoryManager(size_t logLimitAtStart) _prAllocLimit(logLimitAtStart), _segment(), _allocPool(_segment), - _threadList(_allocPool) + _mmapPool(), + _threadList(_allocPool, _mmapPool) { setAllocatorForThreads(this); initThisThread(); diff --git a/vespamalloc/src/vespamalloc/malloc/mmappool.cpp b/vespamalloc/src/vespamalloc/malloc/mmappool.cpp new file mode 100644 index 00000000000..296471e54a2 --- /dev/null +++ b/vespamalloc/src/vespamalloc/malloc/mmappool.cpp @@ -0,0 +1,103 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespamalloc/malloc/mmappool.h> +#include <vespamalloc/malloc/common.h> +#include <cassert> +#include <sys/mman.h> + +namespace vespamalloc { + +MMapPool::MMapPool() + : _page_size(getpagesize()), + _huge_flags((getenv("VESPA_USE_HUGEPAGES") != nullptr) ? MAP_HUGETLB : 0), + _count(0), + _mutex(), + _mappings() +{ + +} + +MMapPool::~MMapPool() { + assert(_mappings.empty()); +} + +size_t +MMapPool::getNumMappings() const { + std::lock_guard guard(_mutex); + return _mappings.size(); +} + +size_t +MMapPool::getMmappedBytes() const { + std::lock_guard guard(_mutex); + size_t sum(0); + std::for_each(_mappings.begin(), _mappings.end(), [&sum](const auto & e){ sum += e.second._sz; }); + return sum; +} + +void * +MMapPool::mmap(size_t sz) { + void * buf(nullptr); + assert((sz & (_page_size - 1)) == 0); + if (sz > 0) { + const int flags(MAP_ANON | MAP_PRIVATE); + const int prot(PROT_READ | PROT_WRITE); + size_t mmapId = _count.fetch_add(1); + if (sz >= _G_bigBlockLimit) { + fprintf(_G_logFile, "mmap %ld of size %ld from : ", mmapId, sz); + logStackTrace(); + } + buf = ::mmap(nullptr, sz, prot, flags | _huge_flags, -1, 0); + if (buf == MAP_FAILED) { + if (!_has_hugepage_failure_just_happened) { + _has_hugepage_failure_just_happened = true; + } + buf = ::mmap(nullptr, sz, prot, flags, -1, 0); + if (buf == MAP_FAILED) { + fprintf(_G_logFile, "Failed mmaping anonymous of size %ld errno(%d) from : ", sz, errno); + logStackTrace(); + abort(); + } + } else { + if (_has_hugepage_failure_just_happened) { + _has_hugepage_failure_just_happened = false; + } + } +#ifdef __linux__ + if (sz >= _G_bigBlockLimit) { + if (madvise(buf, sz, MADV_DONTDUMP) != 0) { + std::error_code ec(errno, std::system_category()); + fprintf(_G_logFile, "Failed madvise(%p, %ld, MADV_DONTDUMP) = '%s'\n", buf, sz, + ec.message().c_str()); + } + } +#endif + std::lock_guard guard(_mutex); + auto [it, inserted] = _mappings.insert(std::make_pair(buf, MMapInfo(mmapId, sz))); + assert(inserted); + if (sz >= _G_bigBlockLimit) { + size_t sum(0); + std::for_each(_mappings.begin(), _mappings.end(), [&sum](const auto & e){ sum += e.second._sz; }); + fprintf(_G_logFile, "%ld mappings of accumulated size %ld\n", _mappings.size(), sum); + } + } + return buf; +} + +void +MMapPool::unmap(void * ptr) { + size_t sz; + { + std::lock_guard guard(_mutex); + auto found = _mappings.find(ptr); + if (found == _mappings.end()) { + fprintf(_G_logFile, "Not able to unmap %p as it is not registered: ", ptr); + logStackTrace(); + abort(); + } + sz = found->second._sz; + } + int munmap_ok = ::munmap(ptr, sz); + assert(munmap_ok == 0); +} + +} diff --git a/vespamalloc/src/vespamalloc/malloc/mmappool.h b/vespamalloc/src/vespamalloc/malloc/mmappool.h new file mode 100644 index 00000000000..c07ef9dce15 --- /dev/null +++ b/vespamalloc/src/vespamalloc/malloc/mmappool.h @@ -0,0 +1,33 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <atomic> +#include <unordered_map> + +namespace vespamalloc { + +class MMapPool { +public: + MMapPool(); + MMapPool(const MMapPool &) = delete; + MMapPool & operator =(const MMapPool &) = delete; + ~MMapPool(); + void * mmap(size_t sz); + void unmap(void *); + size_t getNumMappings() const; + size_t getMmappedBytes() const; +private: + struct MMapInfo { + MMapInfo(size_t id, size_t sz) : _id(id), _sz(sz) { } + size_t _id; + size_t _sz; + }; + const size_t _page_size; + const int _huge_flags; + std::atomic<size_t> _count; + std::atomic<bool> _has_hugepage_failure_just_happened; + mutable std::mutex _mutex; + std::unordered_map<const void *, MMapInfo> _mappings; +}; + +} diff --git a/vespamalloc/src/vespamalloc/malloc/overload.h b/vespamalloc/src/vespamalloc/malloc/overload.h index 7d9c2b9c72e..6650f107ca9 100644 --- a/vespamalloc/src/vespamalloc/malloc/overload.h +++ b/vespamalloc/src/vespamalloc/malloc/overload.h @@ -113,12 +113,12 @@ struct mallinfo2 mallinfo2() __THROW { info.arena = vespamalloc::_GmemP->dataSegment().dataSize(); info.ordblks = 0; info.smblks = 0; - info.hblks = 0; - info.hblkhd = 0; + info.hblkhd = vespamalloc::_GmemP->mmapPool().getNumMappings(); + info.hblks = vespamalloc::_GmemP->mmapPool().getMmappedBytes(); info.usmblks = 0; info.fsmblks = 0; - info.uordblks = 0; - info.fordblks = 0; + info.fordblks = vespamalloc::_GmemP->dataSegment().freeSize(); + info.uordblks = info.arena + info.hblks - info.fordblks; info.keepcost = 0; return info; } @@ -129,12 +129,12 @@ struct mallinfo mallinfo() __THROW { info.arena = (vespamalloc::_GmemP->dataSegment().dataSize() >> 20); // Note reporting in 1M blocks info.ordblks = 0; info.smblks = 0; - info.hblks = 0; - info.hblkhd = 0; + info.hblkhd = vespamalloc::_GmemP->mmapPool().getNumMappings(); + info.hblks = (vespamalloc::_GmemP->mmapPool().getMmappedBytes() >> 20); info.usmblks = 0; info.fsmblks = 0; - info.uordblks = 0; - info.fordblks = 0; + info.fordblks = (vespamalloc::_GmemP->dataSegment().freeSize() >> 20); + info.uordblks = info.arena + info.hblks - info.fordblks; info.keepcost = 0; return info; } diff --git a/vespamalloc/src/vespamalloc/malloc/threadlist.h b/vespamalloc/src/vespamalloc/malloc/threadlist.h index c95760dc015..ca3a58483c9 100644 --- a/vespamalloc/src/vespamalloc/malloc/threadlist.h +++ b/vespamalloc/src/vespamalloc/malloc/threadlist.h @@ -17,7 +17,9 @@ class ThreadListT public: using ThreadPool = ThreadPoolT<MemBlockPtrT, ThreadStatT >; using AllocPool = AllocPoolT<MemBlockPtrT>; - ThreadListT(AllocPool & pool); + ThreadListT(AllocPool & allocPool, MMapPool & mmapPool); + ThreadListT(const ThreadListT & tl) = delete; + ThreadListT & operator = (const ThreadListT & tl) = delete; ~ThreadListT(); void setParams(size_t threadCacheLimit) { ThreadPool::setParams(threadCacheLimit); @@ -33,13 +35,12 @@ public: void info(FILE * os, size_t level=0); size_t getMaxNumThreads() const { return NELEMS(_threadVector); } private: - ThreadListT(const ThreadListT & tl); - ThreadListT & operator = (const ThreadListT & tl); std::atomic_flag _isThreaded; std::atomic<uint32_t> _threadCount; std::atomic<uint32_t> _threadCountAccum; ThreadPool _threadVector[NUM_THREADS]; AllocPoolT<MemBlockPtrT> & _allocPool; + MMapPool & _mmapPool; static thread_local ThreadPool * _myPool TLS_LINKAGE; }; diff --git a/vespamalloc/src/vespamalloc/malloc/threadlist.hpp b/vespamalloc/src/vespamalloc/malloc/threadlist.hpp index 8a2cb1de879..5f65e98d0ac 100644 --- a/vespamalloc/src/vespamalloc/malloc/threadlist.hpp +++ b/vespamalloc/src/vespamalloc/malloc/threadlist.hpp @@ -6,14 +6,15 @@ namespace vespamalloc { template <typename MemBlockPtrT, typename ThreadStatT> -ThreadListT<MemBlockPtrT, ThreadStatT>::ThreadListT(AllocPool & pool) : +ThreadListT<MemBlockPtrT, ThreadStatT>::ThreadListT(AllocPool & allocPool, MMapPool & mmapPool) : _isThreaded(false), _threadCount(0), _threadCountAccum(0), - _allocPool(pool) + _allocPool(allocPool), + _mmapPool(mmapPool) { for (size_t i = 0; i < getMaxNumThreads(); i++) { - _threadVector[i].setPool(_allocPool); + _threadVector[i].setPool(_allocPool, _mmapPool); } } diff --git a/vespamalloc/src/vespamalloc/malloc/threadpool.h b/vespamalloc/src/vespamalloc/malloc/threadpool.h index ec89079a415..1276d0129b5 100644 --- a/vespamalloc/src/vespamalloc/malloc/threadpool.h +++ b/vespamalloc/src/vespamalloc/malloc/threadpool.h @@ -5,6 +5,7 @@ #include <vespamalloc/malloc/common.h> #include <vespamalloc/malloc/allocchunk.h> #include <vespamalloc/malloc/globalpool.h> +#include <vespamalloc/malloc/mmappool.h> namespace vespamalloc { @@ -12,12 +13,13 @@ template <typename MemBlockPtrT, typename ThreadStatT > class ThreadPoolT { public: - typedef AFList<MemBlockPtrT> ChunkSList; - typedef AllocPoolT<MemBlockPtrT> AllocPool; + using ChunkSList = AFList<MemBlockPtrT>; + using AllocPool = AllocPoolT<MemBlockPtrT>; ThreadPoolT(); ~ThreadPoolT(); - void setPool(AllocPool & pool) { - _allocPool = & pool; + void setPool(AllocPool & allocPool, MMapPool & mmapPool) { + _allocPool = & allocPool; + _mmapPool = & mmapPool; } int mallopt(int param, int value); void malloc(size_t sz, MemBlockPtrT & mem); @@ -66,7 +68,8 @@ private: static constexpr bool alwaysReuse(SizeClassT sc) { return sc > ALWAYS_REUSE_SC_LIMIT; } AllocPool * _allocPool; - ssize_t _mmapLimit; + MMapPool * _mmapPool; + size_t _mmapLimit; AllocFree _memList[NUM_SIZE_CLASSES]; ThreadStatT _stat[NUM_SIZE_CLASSES]; uint32_t _threadId; diff --git a/vespamalloc/src/vespamalloc/malloc/threadpool.hpp b/vespamalloc/src/vespamalloc/malloc/threadpool.hpp index e9b9fabebdc..31ed1296a9e 100644 --- a/vespamalloc/src/vespamalloc/malloc/threadpool.hpp +++ b/vespamalloc/src/vespamalloc/malloc/threadpool.hpp @@ -6,11 +6,17 @@ namespace vespamalloc { +namespace { + constexpr size_t MMAP_LIMIT_MIN = 0x100000; // 1M + constexpr size_t MMAP_LIMIT_MAX = 0x40000000; // 1G +} + template <typename MemBlockPtrT, typename ThreadStatT> size_t ThreadPoolT<MemBlockPtrT, ThreadStatT>::_threadCacheLimit __attribute__((visibility("hidden"))) = 0x10000; template <typename MemBlockPtrT, typename ThreadStatT> -void ThreadPoolT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level, const DataSegment<MemBlockPtrT> & ds) const { +void +ThreadPoolT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level, const DataSegment<MemBlockPtrT> & ds) const { if (level > 0) { for (size_t i=0; i < NELEMS(_stat); i++) { const ThreadStatT & s = _stat[i]; @@ -50,7 +56,8 @@ void ThreadPoolT<MemBlockPtrT, ThreadStatT>::info(FILE * os, size_t level, const } template <typename MemBlockPtrT, typename ThreadStatT > -void ThreadPoolT<MemBlockPtrT, ThreadStatT>:: +void +ThreadPoolT<MemBlockPtrT, ThreadStatT>:: mallocHelper(size_t exactSize, SizeClassT sc, typename ThreadPoolT<MemBlockPtrT, ThreadStatT>::AllocFree & af, @@ -71,13 +78,20 @@ mallocHelper(size_t exactSize, PARANOID_CHECK2( *(int *)2 = 2; ); } } else { - af._allocFrom = _allocPool->exactAlloc(exactSize, sc, af._allocFrom); - _stat[sc].incExactAlloc(); - if (af._allocFrom) { - af._allocFrom->sub(mem); - PARANOID_CHECK2( if (!mem.ptr()) { *(int *)3 = 3; } ); + if (exactSize > _mmapLimit) { + mem = MemBlockPtrT(_mmapPool->mmap(MemBlockPtrT::classSize(sc)), MemBlockPtrT::classSize(sc)); + // The below settings are to allow the sanity checks conducted at the call site to succeed + mem.setExact(exactSize); + mem.free(); } else { - PARANOID_CHECK2( *(int *)4 = 4; ); + af._allocFrom = _allocPool->exactAlloc(exactSize, sc, af._allocFrom); + _stat[sc].incExactAlloc(); + if (af._allocFrom) { + af._allocFrom->sub(mem); + PARANOID_CHECK2(if (!mem.ptr()) { *(int *) 3 = 3; }); + } else { + PARANOID_CHECK2(*(int *) 4 = 4;); + } } } } @@ -86,7 +100,8 @@ mallocHelper(size_t exactSize, template <typename MemBlockPtrT, typename ThreadStatT > ThreadPoolT<MemBlockPtrT, ThreadStatT>::ThreadPoolT() : _allocPool(nullptr), - _mmapLimit(0x40000000), + _mmapPool(nullptr), + _mmapLimit(MMAP_LIMIT_MAX), _threadId(0), _osThreadId(0) { @@ -97,8 +112,9 @@ ThreadPoolT<MemBlockPtrT, ThreadStatT>::~ThreadPoolT() = default; template <typename MemBlockPtrT, typename ThreadStatT > int ThreadPoolT<MemBlockPtrT, ThreadStatT>::mallopt(int param, int value) { + size_t limit = value; if (param == M_MMAP_THRESHOLD) { - _mmapLimit = value; + _mmapLimit = std::min(MMAP_LIMIT_MAX, std::max(MMAP_LIMIT_MIN, limit)); return 1; } return 0; |