diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2016-10-07 00:02:10 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-07 00:02:10 +0200 |
commit | 1b331fb8a78d5688dd9157cac1bfbd8a25702868 (patch) | |
tree | 046e66a4f3ecb57ca9aee1dc6902fba1f39987c1 /vespalib | |
parent | 84586d72795718ca76c8e61a60f9452db3636d9f (diff) | |
parent | 3128e223b95996aaf22f0aba54be11692a12f89b (diff) |
Merge pull request #771 from yahoo/balder/use-constructor-argument-instead-of-template-argument
Balder/use constructor argument instead of template argument
Diffstat (limited to 'vespalib')
-rw-r--r-- | vespalib/src/tests/alloc/alloc_test.cpp | 26 | ||||
-rw-r--r-- | vespalib/src/tests/alloc/allocate_and_core.cpp | 6 | ||||
-rw-r--r-- | vespalib/src/tests/array/array_test.cpp | 8 | ||||
-rw-r--r-- | vespalib/src/tests/exception_classes/mmap.cpp | 6 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/data/memorydatastore.cpp | 10 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/data/memorydatastore.h | 8 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/objects/nbostream.h | 5 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/stllike/hashtable.h | 2 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/alloc.cpp | 250 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/alloc.h | 181 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/array.h | 72 |
11 files changed, 369 insertions, 205 deletions
diff --git a/vespalib/src/tests/alloc/alloc_test.cpp b/vespalib/src/tests/alloc/alloc_test.cpp index 5f1ba897f61..b16afbcc7a6 100644 --- a/vespalib/src/tests/alloc/alloc_test.cpp +++ b/vespalib/src/tests/alloc/alloc_test.cpp @@ -8,6 +8,7 @@ LOG_SETUP("alloc_test"); #include <vespa/vespalib/util/exceptions.h> using namespace vespalib; +using namespace vespalib::alloc; class Test : public TestApp { @@ -36,7 +37,7 @@ Test::testSwap(T & a, T & b) void * tmpB(b.get()); EXPECT_EQUAL(100u, a.size()); EXPECT_EQUAL(200u, b.size()); - swap(a, b); + std::swap(a, b); EXPECT_EQUAL(100u, b.size()); EXPECT_EQUAL(200u, a.size()); EXPECT_EQUAL(tmpA, b.get()); @@ -47,31 +48,36 @@ void Test::testBasic() { { - HeapAlloc h(100); + Alloc h = HeapAllocFactory::create(100); EXPECT_EQUAL(100u, h.size()); EXPECT_TRUE(h.get() != NULL); } { - EXPECT_EXCEPTION(AlignedHeapAlloc(100, 0), IllegalArgumentException, "posix_memalign(100, 0) failed with code 22"); - AlignedHeapAlloc h(100, 1024); + EXPECT_EXCEPTION(AlignedHeapAllocFactory::create(100, 7), IllegalArgumentException, "AlignedHeapAllocFactory::create(100, 7) does not support 7 alignment"); + Alloc h = AlignedHeapAllocFactory::create(100, 1024); EXPECT_EQUAL(100u, h.size()); EXPECT_TRUE(h.get() != NULL); } { - MMapAlloc h(100); + Alloc h = MMapAllocFactory::create(100); EXPECT_EQUAL(100u, h.size()); EXPECT_TRUE(h.get() != NULL); } { - HeapAlloc a(100), b(200); + Alloc a = HeapAllocFactory::create(100), b = HeapAllocFactory::create(200); testSwap(a, b); } { - MMapAlloc a(100), b(200); + Alloc a = MMapAllocFactory::create(100), b = MMapAllocFactory::create(200); testSwap(a, b); } { - AlignedHeapAlloc a(100, 1024), b(200, 1024); + Alloc a = AlignedHeapAllocFactory::create(100, 1024), b = AlignedHeapAllocFactory::create(200, 1024); + testSwap(a, b); + } + { + Alloc a = HeapAllocFactory::create(100); + Alloc b = MMapAllocFactory::create(200); testSwap(a, b); } } @@ -80,13 +86,13 @@ void Test::testAlignedAllocation() { { - AutoAlloc<2048, 1024> buf(10); + Alloc buf = AutoAllocFactory::create(10, MemoryAllocator::HUGEPAGE_SIZE, 1024); EXPECT_TRUE(reinterpret_cast<ptrdiff_t>(buf.get()) % 1024 == 0); } { // Mmapped pointers are page-aligned, but sanity test anyway. - AutoAlloc<1024, 512> buf(3000); + Alloc buf = AutoAllocFactory::create(3000000, MemoryAllocator::HUGEPAGE_SIZE, 512); EXPECT_TRUE(reinterpret_cast<ptrdiff_t>(buf.get()) % 512 == 0); } } diff --git a/vespalib/src/tests/alloc/allocate_and_core.cpp b/vespalib/src/tests/alloc/allocate_and_core.cpp index 2cb4d447fd1..f0a0669eb42 100644 --- a/vespalib/src/tests/alloc/allocate_and_core.cpp +++ b/vespalib/src/tests/alloc/allocate_and_core.cpp @@ -1,14 +1,14 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/vespalib/util/alloc.h> -using namespace vespalib; +using namespace vespalib::alloc; int main(int argc, char *argv[]) { (void) argc; (void) argv; - MMapAlloc small( 0x400000); //4M + Alloc small(MMapAllocFactory::create(0x400000)); //4M memset(small.get(), 0x55, small.size()); - MMapAlloc large(0x4000000); //640M + Alloc large(MMapAllocFactory::create(0x4000000)); //640M memset(large.get(), 0x66, large.size()); assert(false); } diff --git a/vespalib/src/tests/array/array_test.cpp b/vespalib/src/tests/array/array_test.cpp index 03b00769e7a..231bc00611a 100644 --- a/vespalib/src/tests/array/array_test.cpp +++ b/vespalib/src/tests/array/array_test.cpp @@ -28,8 +28,8 @@ private: namespace vespalib { -template <typename T, typename B> -std::ostream & operator << (std::ostream & os, const Array<T,B> & a) +template <typename T> +std::ostream & operator << (std::ostream & os, const Array<T> & a) { os << '{'; if (! a.empty()) { @@ -118,7 +118,7 @@ Test::Main() void Test::testThatOrganicGrowthIsBy2InNAndReserveResizeAreExact() { - Array<char, DefaultAlloc> c(256); + Array<char> c(256); EXPECT_EQUAL(256u, c.size()); EXPECT_EQUAL(256u, c.capacity()); c.reserve(258); @@ -157,7 +157,7 @@ void Test::testArray(const T & a, const T & b) { Array<T> array; - ASSERT_EQUAL(sizeof(array), 24u); + ASSERT_EQUAL(sizeof(array), 32u); ASSERT_EQUAL(array.size(), 0u); ASSERT_EQUAL(array.capacity(), 0u); for(size_t i(0); i < 5; i++) { diff --git a/vespalib/src/tests/exception_classes/mmap.cpp b/vespalib/src/tests/exception_classes/mmap.cpp index 56c2b5d8d67..fe0a8fc4556 100644 --- a/vespalib/src/tests/exception_classes/mmap.cpp +++ b/vespalib/src/tests/exception_classes/mmap.cpp @@ -1,6 +1,6 @@ #include <vespa/vespalib/util/alloc.h> -using vespalib::MMapAlloc; +using namespace vespalib::alloc; int main(int argc, char *argv[]) { if (argc != 4) { @@ -13,9 +13,9 @@ int main(int argc, char *argv[]) { virtualLimit.rlim_cur = virt; virtualLimit.rlim_max = virt; assert(setrlimit(RLIMIT_AS, &virtualLimit) == 0); - std::vector<MMapAlloc> mappings; + std::vector<Alloc> mappings; for (size_t i(0); i < numBlocks; i++) { - mappings.emplace_back(blockSize); + mappings.emplace_back(MMapAllocFactory::create(blockSize)); memset(mappings.back().get(), 0xa5, mappings.back().size()); } return 0; diff --git a/vespalib/src/vespa/vespalib/data/memorydatastore.cpp b/vespalib/src/vespa/vespalib/data/memorydatastore.cpp index e6b22aa9e3f..791ea0cea50 100644 --- a/vespalib/src/vespa/vespalib/data/memorydatastore.cpp +++ b/vespalib/src/vespa/vespalib/data/memorydatastore.cpp @@ -3,13 +3,15 @@ namespace vespalib { -MemoryDataStore::MemoryDataStore(size_t initialSize, Lock * lock) : +using alloc::Alloc; + +MemoryDataStore::MemoryDataStore(Alloc && initialAlloc, Lock * lock) : _buffers(), _writePos(0), _lock(lock) { _buffers.reserve(24); - _buffers.emplace_back(initialSize); + _buffers.emplace_back(std::move(initialAlloc)); } MemoryDataStore::~MemoryDataStore() @@ -26,7 +28,7 @@ MemoryDataStore::push_back(const void * data, const size_t sz) const Alloc & b = _buffers.back(); if ((sz + _writePos) > b.size()) { size_t newSize(std::max(sz, _buffers.back().size()*2)); - _buffers.emplace_back(newSize); + _buffers.emplace_back(b.create(newSize)); _writePos = 0; } Alloc & buf = _buffers.back(); @@ -39,7 +41,7 @@ MemoryDataStore::push_back(const void * data, const size_t sz) VariableSizeVector::VariableSizeVector(size_t initialSize) : _vector(), - _store(initialSize) + _store(DefaultAlloc::create(initialSize)) { } diff --git a/vespalib/src/vespa/vespalib/data/memorydatastore.h b/vespalib/src/vespa/vespalib/data/memorydatastore.h index 9fa56d64a31..b61fa3665ad 100644 --- a/vespalib/src/vespa/vespalib/data/memorydatastore.h +++ b/vespalib/src/vespa/vespalib/data/memorydatastore.h @@ -23,7 +23,7 @@ public: private: void * _data; }; - MemoryDataStore(size_t initialSize=256, Lock * lock=nullptr); + MemoryDataStore(alloc::Alloc && initialAlloc=DefaultAlloc::create(256), Lock * lock=nullptr); MemoryDataStore(const MemoryDataStore &) = delete; MemoryDataStore & operator = (const MemoryDataStore &) = delete; ~MemoryDataStore(); @@ -38,12 +38,12 @@ public: _buffers.clear(); } private: - std::vector<DefaultAlloc> _buffers; + std::vector<alloc::Alloc> _buffers; size_t _writePos; Lock * _lock; }; -class VariableSizeVector : public noncopyable +class VariableSizeVector { public: class Reference { @@ -96,6 +96,8 @@ public: const vespalib::Array<Reference> * _vector; size_t _index; }; + VariableSizeVector(const VariableSizeVector &) = delete; + VariableSizeVector & operator = (const VariableSizeVector &) = delete; VariableSizeVector(size_t initialSize=256); ~VariableSizeVector(); iterator begin() { return iterator(_vector, 0); } diff --git a/vespalib/src/vespa/vespalib/objects/nbostream.h b/vespalib/src/vespa/vespalib/objects/nbostream.h index af5ac47fcb5..cb15db018fc 100644 --- a/vespalib/src/vespa/vespalib/objects/nbostream.h +++ b/vespalib/src/vespa/vespalib/objects/nbostream.h @@ -36,7 +36,8 @@ private: class nbostream { public: - typedef Array<char, DefaultAlloc> Buffer; + using Buffer = Array<char>; + using Alloc = alloc::Alloc; enum State { ok=0, eof=0x01}; nbostream(size_t initialSize=1024) : _wbuf(), @@ -59,7 +60,7 @@ class nbostream { } - nbostream(DefaultAlloc && buf, size_t sz) : + nbostream(Alloc && buf, size_t sz) : _wbuf(std::move(buf), sz), _rbuf(&_wbuf[0], sz), _rp(0), diff --git a/vespalib/src/vespa/vespalib/stllike/hashtable.h b/vespalib/src/vespa/vespalib/stllike/hashtable.h index e038c9f40d9..a1eeb289c31 100644 --- a/vespalib/src/vespa/vespalib/stllike/hashtable.h +++ b/vespalib/src/vespa/vespalib/stllike/hashtable.h @@ -132,7 +132,7 @@ class hashtable : public hashtable_base private: using Node=hash_node<Value>; protected: - typedef vespalib::Array<Node, vespalib::DefaultAlloc > NodeStore; + typedef vespalib::Array<Node> NodeStore; virtual void move(NodeStore && oldStore); public: class const_iterator; diff --git a/vespalib/src/vespa/vespalib/util/alloc.cpp b/vespalib/src/vespa/vespalib/util/alloc.cpp index 66f40366f52..b037535a635 100644 --- a/vespalib/src/vespa/vespalib/util/alloc.cpp +++ b/vespalib/src/vespa/vespalib/util/alloc.cpp @@ -13,26 +13,12 @@ #include <vespa/log/log.h> #include <map> #include <atomic> +#include <unordered_map> LOG_SETUP(".vespalib.alloc"); namespace vespalib { -void * AlignedHeapAlloc::alloc(size_t sz, size_t alignment) -{ - if (!sz) { - return 0; - } - void* ptr; - int result = posix_memalign(&ptr, alignment, sz); - if (result != 0) { - throw IllegalArgumentException( - make_string("posix_memalign(%zu, %zu) failed with code %d", - sz, alignment, result)); - } - return ptr; -} - namespace { volatile bool _G_hasHugePageFailureJustHappened(false); @@ -99,9 +85,178 @@ size_t sum(const MMapStore & s) return sum; } +class MMapLimitAndAlignment { +public: + MMapLimitAndAlignment(size_t mmapLimit, size_t alignment); + uint32_t hash() const { return _key; } + bool operator == (MMapLimitAndAlignment rhs) const { return _key == rhs._key; } +private: + uint32_t _key; +}; + +void verifyMMapLimitAndAlignment(size_t mmapLimit, size_t alignment) __attribute__((noinline)); + +void verifyMMapLimitAndAlignment(size_t mmapLimit, size_t alignment) { + if ((0x01ul << Optimized::msbIdx(mmapLimit)) != mmapLimit) { + throw IllegalArgumentException(make_string("We only support mmaplimit(%0lx) to be a power of 2", mmapLimit)); + } + if ((alignment != 0) && (0x01ul << Optimized::msbIdx(alignment)) != alignment) { + throw IllegalArgumentException(make_string("We only support alignment(%0lx) to be a power of 2", alignment)); + } } -void * MMapAlloc::alloc(size_t sz) +MMapLimitAndAlignment::MMapLimitAndAlignment(size_t mmapLimit, size_t alignment) : + _key(Optimized::msbIdx(mmapLimit) | Optimized::msbIdx(alignment) << 6) +{ + verifyMMapLimitAndAlignment(mmapLimit, alignment); +} +} + +namespace alloc { + +class HeapAllocator : public MemoryAllocator { +public: + void * alloc(size_t sz) const override; + void free(void * buf, size_t sz) const override; + static void * salloc(size_t sz); + static void sfree(void * buf, size_t sz); + static MemoryAllocator & getDefault(); +}; + +class AlignedHeapAllocator : public HeapAllocator { +public: + AlignedHeapAllocator(size_t alignment) : _alignment(alignment) { } + void * alloc(size_t sz) const override; + static MemoryAllocator & get4K(); + static MemoryAllocator & get1K(); + static MemoryAllocator & get512B(); +private: + size_t _alignment; +}; + +class MMapAllocator : public MemoryAllocator { +public: + void * alloc(size_t sz) const override; + void free(void * buf, size_t sz) const override; + static void * salloc(size_t sz); + static void sfree(void * buf, size_t sz); + static MemoryAllocator & getDefault(); +}; + +class AutoAllocator : public MemoryAllocator { +public: + AutoAllocator(size_t mmapLimit, size_t alignment) : _mmapLimit(mmapLimit), _alignment(alignment) { } + void * alloc(size_t sz) const override; + void free(void * buf, size_t sz) const override; + static MemoryAllocator & getDefault(); + static MemoryAllocator & getAllocator(size_t mmapLimit, size_t alignment); +private: + size_t roundUpToHugePages(size_t sz) const { + return (_mmapLimit >= MemoryAllocator::HUGEPAGE_SIZE) + ? MMapAllocator::roundUpToHugePages(sz) + : sz; + } + bool useMMap(size_t sz) const { return (sz >= _mmapLimit); } + size_t _mmapLimit; + size_t _alignment; +}; + + +namespace { + +struct MMapLimitAndAlignmentHash { + std::size_t operator ()(MMapLimitAndAlignment key) const { return key.hash(); } +}; + +using AutoAllocatorsMap = std::unordered_map<MMapLimitAndAlignment, AutoAllocator::UP, MMapLimitAndAlignmentHash>; + +AutoAllocatorsMap createAutoAllocators() { + AutoAllocatorsMap map; + map.reserve(15); + for (size_t alignment : {0,0x200, 0x400, 0x1000}) { + for (size_t pages : {1,2,4,8,16}) { + size_t mmapLimit = pages * MemoryAllocator::HUGEPAGE_SIZE; + MMapLimitAndAlignment key(mmapLimit, alignment); + auto result = map.emplace(key, AutoAllocator::UP(new AutoAllocator(mmapLimit, alignment))); + assert( result.second ); + } + } + return map; +} + +AutoAllocatorsMap _G_availableAutoAllocators = createAutoAllocators(); +alloc::HeapAllocator _G_heapAllocatorDefault; +alloc::AlignedHeapAllocator _G_4KalignedHeapAllocator(1024); +alloc::AlignedHeapAllocator _G_1KalignedHeapAllocator(4096); +alloc::AlignedHeapAllocator _G_512BalignedHeapAllocator(512); +alloc::MMapAllocator _G_mmapAllocatorDefault; + +} + +MemoryAllocator & HeapAllocator::getDefault() { + return _G_heapAllocatorDefault; +} + +MemoryAllocator & AlignedHeapAllocator::get4K() { + return _G_4KalignedHeapAllocator; +} + +MemoryAllocator & AlignedHeapAllocator::get1K() { + return _G_1KalignedHeapAllocator; +} + +MemoryAllocator & AlignedHeapAllocator::get512B() { + return _G_512BalignedHeapAllocator; +} + +MemoryAllocator & MMapAllocator::getDefault() { + return _G_mmapAllocatorDefault; +} + +MemoryAllocator & AutoAllocator::getDefault() { + return getAllocator(1 * MemoryAllocator::HUGEPAGE_SIZE, 0); +} + +MemoryAllocator & AutoAllocator::getAllocator(size_t mmapLimit, size_t alignment) { + MMapLimitAndAlignment key(mmapLimit, alignment); + auto found = _G_availableAutoAllocators.find(key); + if (found == _G_availableAutoAllocators.end()) { + throw IllegalArgumentException(make_string("We currently have no support for mmapLimit(%0lx) and alignment(%0lx)", mmapLimit, alignment)); + } + return *(found->second); +} + +void * HeapAllocator::alloc(size_t sz) const { + return salloc(sz); +} + +void * HeapAllocator::salloc(size_t sz) { + return (sz > 0) ? malloc(sz) : 0; +} + +void HeapAllocator::free(void * p, size_t sz) const { + sfree(p, sz); +} + +void HeapAllocator::sfree(void * p, size_t sz) { + (void) sz; if (p) { ::free(p); } +} + +void * AlignedHeapAllocator::alloc(size_t sz) const { + if (!sz) { return 0; } + void* ptr; + int result = posix_memalign(&ptr, _alignment, sz); + if (result != 0) { + throw IllegalArgumentException(make_string("posix_memalign(%zu, %zu) failed with code %d", sz, _alignment, result)); + } + return ptr; +} + +void * MMapAllocator::alloc(size_t sz) const { + return salloc(sz); +} + +void * MMapAllocator::salloc(size_t sz) { void * buf(nullptr); if (sz > 0) { @@ -152,7 +307,11 @@ void * MMapAlloc::alloc(size_t sz) return buf; } -void MMapAlloc::free(void * buf, size_t sz) +void MMapAllocator::free(void * buf, size_t sz) const { + sfree(buf, sz); +} + +void MMapAllocator::sfree(void * buf, size_t sz) { if (buf != nullptr) { madvise(buf, sz, MADV_DONTNEED); @@ -167,4 +326,61 @@ void MMapAlloc::free(void * buf, size_t sz) } } +void * AutoAllocator::alloc(size_t sz) const { + if (useMMap(sz)) { + sz = roundUpToHugePages(sz); + return MMapAllocator::salloc(sz); + } else { + if (_alignment == 0) { + return HeapAllocator::salloc(sz); + } else { + return AlignedHeapAllocator(_alignment).alloc(sz); + } + } +} + +void AutoAllocator::free(void *p, size_t sz) const { + if (useMMap(sz)) { + return MMapAllocator::sfree(p, sz); + } else { + return HeapAllocator::sfree(p, sz); + } +} + +Alloc +HeapAllocFactory::create(size_t sz) +{ + return Alloc(&HeapAllocator::getDefault(), sz); +} + +Alloc +AlignedHeapAllocFactory::create(size_t sz, size_t alignment) +{ + if (alignment == 0) { + return Alloc(&AlignedHeapAllocator::getDefault(), sz); + } else if (alignment == 0x200) { + return Alloc(&AlignedHeapAllocator::get512B(), sz); + } else if (alignment == 0x400) { + return Alloc(&AlignedHeapAllocator::get1K(), sz); + } else if (alignment == 0x1000) { + return Alloc(&AlignedHeapAllocator::get4K(), sz); + } else { + throw IllegalArgumentException(make_string("AlignedHeapAllocFactory::create(%zu, %zu) does not support %zu alignment", sz, alignment, alignment)); + } +} + +Alloc +MMapAllocFactory::create(size_t sz) +{ + return Alloc(&MMapAllocator::getDefault(), sz); +} + +Alloc +AutoAllocFactory::create(size_t sz, size_t mmapLimit, size_t alignment) +{ + return Alloc(&AutoAllocator::getAllocator(mmapLimit, alignment), sz); +} + +} + } diff --git a/vespalib/src/vespa/vespalib/util/alloc.h b/vespalib/src/vespa/vespalib/util/alloc.h index 559076c7acd..74366439f2c 100644 --- a/vespalib/src/vespa/vespalib/util/alloc.h +++ b/vespalib/src/vespa/vespalib/util/alloc.h @@ -4,126 +4,98 @@ #include <sys/types.h> #include <algorithm> #include <vespa/vespalib/util/linkedptr.h> -#include <vespa/vespalib/util/noncopyable.hpp> #include <vespa/vespalib/util/optimized.h> namespace vespalib { -inline size_t roundUp2inN(size_t minimum) { - return 2ul << Optimized::msbIdx(minimum - 1); -} +namespace alloc { + +class MemoryAllocator { +public: + enum {HUGEPAGE_SIZE=0x200000}; + using UP = std::unique_ptr<MemoryAllocator>; + MemoryAllocator(const MemoryAllocator &) = delete; + MemoryAllocator & operator = (const MemoryAllocator &) = delete; + MemoryAllocator() { } + virtual ~MemoryAllocator() { } + virtual void * alloc(size_t sz) const = 0; + virtual void free(void * buf, size_t sz) const = 0; + static size_t roundUpToHugePages(size_t sz) { + return (sz+(HUGEPAGE_SIZE-1)) & ~(HUGEPAGE_SIZE-1); + } +}; + /** - * This is an allocated buffer interface that does not accept virtual inheritance. + * This represents an allocation. + * It can be created, moved, swapped. + * The allocation strategy is decided upon creation. + * It can also create create additional allocations with the same allocation strategy. **/ -class Alloc : public noncopyable +class Alloc { public: + using MemoryAllocator = alloc::MemoryAllocator; size_t size() const { return _sz; } void * get() { return _buf; } const void * get() const { return _buf; } void * operator -> () { return _buf; } const void * operator -> () const { return _buf; } -protected: + Alloc(const Alloc &) = delete; + Alloc & operator = (const Alloc &) = delete; Alloc(Alloc && rhs) : _buf(rhs._buf), - _sz(rhs._sz) + _sz(rhs._sz), + _allocator(rhs._allocator) { rhs._buf = nullptr; rhs._sz = 0; + rhs._allocator = 0; } Alloc & operator=(Alloc && rhs) { if (this != & rhs) { - internalSwap(rhs); + swap(rhs); } return *this; } - Alloc(void * buf, size_t sz) : _buf(buf), _sz(sz) { } - ~Alloc() { _buf = 0; } - void internalSwap(Alloc & rhs) { + Alloc() : _buf(nullptr), _sz(0), _allocator(nullptr) { } + Alloc(const MemoryAllocator * allocator, size_t sz) : _buf(allocator->alloc(sz)), _sz(sz), _allocator(allocator) { } + ~Alloc() { + if (_buf != nullptr) { + _allocator->free(_buf, _sz); + _buf = nullptr; + } + } + void swap(Alloc & rhs) { std::swap(_buf, rhs._buf); std::swap(_sz, rhs._sz); + std::swap(_allocator, rhs._allocator); } -private: - void * _buf; - size_t _sz; + Alloc create(size_t sz) const { + return Alloc(_allocator, sz); + } +protected: + void * _buf; + size_t _sz; + const MemoryAllocator * _allocator; }; -class HeapAlloc : public Alloc +class HeapAllocFactory { public: - typedef std::unique_ptr<HeapAlloc> UP; - HeapAlloc() : Alloc(NULL, 0) { } - HeapAlloc(size_t sz) : Alloc(HeapAlloc::alloc(sz), sz) { } - ~HeapAlloc() { HeapAlloc::free(get(), size()); } - HeapAlloc(HeapAlloc && rhs) : Alloc(std::move(rhs)) { } - - HeapAlloc & operator=(HeapAlloc && rhs) { - Alloc::operator=(std::move(rhs)); - return *this; - } - void swap(HeapAlloc & rhs) { internalSwap(rhs); } -public: - static void * alloc(size_t sz) { return (sz > 0) ? malloc(sz) : 0; } - static void free(void * buf, size_t sz) { (void) sz; if (buf) { ::free(buf); } } + static Alloc create(size_t sz=0); }; -class AlignedHeapAlloc : public Alloc +class AlignedHeapAllocFactory { public: - typedef std::unique_ptr<AlignedHeapAlloc> UP; - AlignedHeapAlloc() : Alloc(NULL, 0) { } - AlignedHeapAlloc(size_t sz, size_t alignment) - : Alloc(AlignedHeapAlloc::alloc(sz, alignment), sz) { } - AlignedHeapAlloc(AlignedHeapAlloc && rhs) : Alloc(std::move(rhs)) { } - - AlignedHeapAlloc & operator=(AlignedHeapAlloc && rhs) { - Alloc::operator=(std::move(rhs)); - return *this; - } - ~AlignedHeapAlloc() { AlignedHeapAlloc::free(get(), size()); } - void swap(AlignedHeapAlloc & rhs) { internalSwap(rhs); } -public: - static void * alloc(size_t sz, size_t alignment); - static void free(void * buf, size_t sz) { (void) sz; if (buf) { ::free(buf); } } + static Alloc create(size_t sz, size_t alignment); }; - -class MMapAlloc : public Alloc +class MMapAllocFactory { public: enum {HUGEPAGE_SIZE=0x200000}; - typedef std::unique_ptr<MMapAlloc> UP; - MMapAlloc() : Alloc(NULL, 0) { } - MMapAlloc(size_t sz) : Alloc(MMapAlloc::alloc(sz), sz) { } - MMapAlloc(MMapAlloc && rhs) : Alloc(std::move(rhs)) { } - - MMapAlloc & operator=(MMapAlloc && rhs) { - Alloc::operator=(std::move(rhs)); - return *this; - } - ~MMapAlloc() { MMapAlloc::free(get(), size()); } - void swap(MMapAlloc & rhs) { internalSwap(rhs); } -public: - static void * alloc(size_t sz); - static void free(void * buf, size_t sz); -}; - -// Alignment requirement is != 0, use posix_memalign -template <size_t Alignment> -struct ChooseHeapAlloc -{ - static inline void* alloc(size_t sz) { - return AlignedHeapAlloc::alloc(sz, Alignment); - } -}; - -// No alignment required, use regular malloc -template <> -struct ChooseHeapAlloc<0> -{ - static inline void* alloc(size_t sz) { - return HeapAlloc::alloc(sz); - } + static Alloc create(size_t sz=0); }; /** @@ -131,53 +103,18 @@ struct ChooseHeapAlloc<0> * is always used when size is above limit. */ -template <size_t Lim=MMapAlloc::HUGEPAGE_SIZE, size_t Alignment=0> -class AutoAlloc : public Alloc +class AutoAllocFactory { public: - typedef std::unique_ptr<AutoAlloc> UP; - typedef vespalib::LinkedPtr<AutoAlloc> LP; - AutoAlloc() : Alloc(NULL, 0) { } - AutoAlloc(size_t sz) - : Alloc(useMMap(sz) - ? MMapAlloc::alloc(roundUpToHugePages(sz)) - : ChooseHeapAlloc<Alignment>::alloc(sz), - useMMap(sz) - ? roundUpToHugePages(sz) - : sz) - { } - AutoAlloc(AutoAlloc && rhs) : Alloc(std::move(rhs)) { } - - AutoAlloc & operator=(AutoAlloc && rhs) { - Alloc::operator=(std::move(rhs)); - return *this; - } - - ~AutoAlloc() { - if (useMMap(size())) { - MMapAlloc::free(get(), size()); - } else { - HeapAlloc::free(get(), size()); - } - } - void swap(AutoAlloc & rhs) { internalSwap(rhs); } -private: - static size_t roundUpToHugePages(size_t sz) { - return (Lim >= MMapAlloc::HUGEPAGE_SIZE) - ? (sz+(MMapAlloc::HUGEPAGE_SIZE-1)) & ~(MMapAlloc::HUGEPAGE_SIZE-1) - : sz; - } - static bool useMMap(size_t sz) { return (sz >= Lim); } + static Alloc create(size_t sz=0, size_t mmapLimit=MemoryAllocator::HUGEPAGE_SIZE, size_t alignment=0); }; -template <size_t Lim> -inline void swap(AutoAlloc<Lim> & a, AutoAlloc<Lim> & b) { a.swap(b); } +} -inline void swap(HeapAlloc & a, HeapAlloc & b) { a.swap(b); } -inline void swap(AlignedHeapAlloc & a, AlignedHeapAlloc & b) { a.swap(b); } -inline void swap(MMapAlloc & a, MMapAlloc & b) { a.swap(b); } +inline size_t roundUp2inN(size_t minimum) { + return 2ul << Optimized::msbIdx(minimum - 1); +} -typedef AutoAlloc<> DefaultAlloc; +using DefaultAlloc = alloc::AutoAllocFactory; } - diff --git a/vespalib/src/vespa/vespalib/util/array.h b/vespalib/src/vespa/vespalib/util/array.h index 8f40d4de0c7..f2546e46e22 100644 --- a/vespalib/src/vespa/vespalib/util/array.h +++ b/vespalib/src/vespa/vespalib/util/array.h @@ -35,7 +35,7 @@ private: * it generates more efficient code. * It only supports simple objects without constructors/destructors. **/ -template <typename T, typename B=HeapAlloc> +template <typename T> class Array { public: class reverse_iterator { @@ -101,18 +101,19 @@ public: friend size_t operator -(const_reverse_iterator a, const_reverse_iterator b) { return b._p - a._p; } const T * _p; }; + using Alloc = alloc::Alloc; typedef const T * const_iterator; typedef T * iterator; typedef const T & const_reference; typedef T value_type; typedef size_t size_type; - Array() : _array(), _sz(0) { } - Array(size_t sz); - Array(B && buf, size_t sz); + Array(const Alloc & initial=DefaultAlloc::create()) : _array(initial.create(0)), _sz(0) { } + Array(size_t sz, const Alloc & initial=DefaultAlloc::create()); + Array(Alloc && buf, size_t sz); Array(Array &&rhs); - Array(size_t sz, T value); - Array(const_iterator begin, const_iterator end); + Array(size_t sz, T value, const Alloc & initial=DefaultAlloc::create()); + Array(const_iterator begin, const_iterator end, const Alloc & initial=DefaultAlloc::create()); Array(const Array & rhs); Array & operator =(const Array & rhs) { if (&rhs != this) { @@ -185,7 +186,7 @@ private: reserve(roundUp2inN(n)); } } - B _array; + Alloc _array; size_t _sz; }; @@ -236,16 +237,16 @@ void construct(T * dest, size_t sz, T val, std::tr1::true_type) } } -template <typename T, typename B> -Array<T, B>::Array(const Array & rhs) - : _array(rhs.size() * sizeof(T)), +template <typename T> +Array<T>::Array(const Array & rhs) + : _array(rhs._array.create(rhs.size() * sizeof(T))), _sz(rhs.size()) { construct(array(0), rhs.array(0), _sz, std::tr1::has_trivial_destructor<T>()); } -template <typename T, typename B> -bool Array<T, B>::operator ==(const Array & rhs) const +template <typename T> +bool Array<T>::operator ==(const Array & rhs) const { bool retval(size() == rhs.size()); for (size_t i(0); retval && (i < _sz); i++) { @@ -256,8 +257,8 @@ bool Array<T, B>::operator ==(const Array & rhs) const return retval; } -template <typename T, typename B> -void Array<T, B>::resize(size_t n) +template <typename T> +void Array<T>::resize(size_t n) { if (n > capacity()) { reserve(n); @@ -285,69 +286,68 @@ void move(T * dest, const T * source, size_t sz, std::tr1::true_type) memcpy(dest, source, sz*sizeof(T)); } -template <typename T, typename B> -void Array<T, B>::increase(size_t n) +template <typename T> +void Array<T>::increase(size_t n) { - B newArray(sizeof(T)*n); + Alloc newArray(_array.create(sizeof(T)*n)); if (capacity() > 0) { move(static_cast<T *>(newArray.get()), array(0), _sz, std::tr1::has_trivial_destructor<T>()); } _array.swap(newArray); } -template <typename T, typename B> -Array<T, B>::Array(B && buf, size_t sz) : +template <typename T> +Array<T>::Array(Alloc && buf, size_t sz) : _array(std::move(buf)), _sz(sz) { } -template <typename T, typename B> -Array<T, B>::Array(Array &&rhs) +template <typename T> +Array<T>::Array(Array &&rhs) : _array(std::move(rhs._array)), _sz(rhs._sz) { rhs._sz = 0; } -template <typename T, typename B> -Array<T, B>::Array(size_t sz) : - _array(sz * sizeof(T)), +template <typename T> +Array<T>::Array(size_t sz, const Alloc & initial) : + _array(initial.create(sz * sizeof(T))), _sz(sz) { construct(array(0), _sz, std::tr1::has_trivial_destructor<T>()); } -template <typename T, typename B> -Array<T, B>::Array(size_t sz, T value) : - _array(sz * sizeof(T)), +template <typename T> +Array<T>::Array(size_t sz, T value, const Alloc & initial) : + _array(initial.create(sz * sizeof(T))), _sz(sz) { construct(array(0), _sz, value, std::tr1::has_trivial_destructor<T>()); } -template <typename T, typename B> -Array<T, B>::Array(const_iterator begin_, const_iterator end_) : - _array(begin_ != end_ ? sizeof(T) * (end_-begin_) : 0), +template <typename T> +Array<T>::Array(const_iterator begin_, const_iterator end_, const Alloc & initial) : + _array(initial.create(begin_ != end_ ? sizeof(T) * (end_-begin_) : 0)), _sz(end_-begin_) { construct(array(0), begin_, _sz, std::tr1::has_trivial_destructor<T>()); } -template <typename T, typename B> -Array<T, B>::~Array() +template <typename T> +Array<T>::~Array() { cleanup(); } -template <typename T, typename B> -void Array<T, B>::cleanup() +template <typename T> +void Array<T>::cleanup() { std::_Destroy(array(0), array(_sz)); _sz = 0; - B tmp; - tmp.swap(_array); + Alloc().swap(_array); } } |