aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2016-10-07 00:02:10 +0200
committerGitHub <noreply@github.com>2016-10-07 00:02:10 +0200
commit1b331fb8a78d5688dd9157cac1bfbd8a25702868 (patch)
tree046e66a4f3ecb57ca9aee1dc6902fba1f39987c1 /vespalib
parent84586d72795718ca76c8e61a60f9452db3636d9f (diff)
parent3128e223b95996aaf22f0aba54be11692a12f89b (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.cpp26
-rw-r--r--vespalib/src/tests/alloc/allocate_and_core.cpp6
-rw-r--r--vespalib/src/tests/array/array_test.cpp8
-rw-r--r--vespalib/src/tests/exception_classes/mmap.cpp6
-rw-r--r--vespalib/src/vespa/vespalib/data/memorydatastore.cpp10
-rw-r--r--vespalib/src/vespa/vespalib/data/memorydatastore.h8
-rw-r--r--vespalib/src/vespa/vespalib/objects/nbostream.h5
-rw-r--r--vespalib/src/vespa/vespalib/stllike/hashtable.h2
-rw-r--r--vespalib/src/vespa/vespalib/util/alloc.cpp250
-rw-r--r--vespalib/src/vespa/vespalib/util/alloc.h181
-rw-r--r--vespalib/src/vespa/vespalib/util/array.h72
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);
}
}