public:
explicit Arena(const Alloc& alloc,
size_t minBlockSize = kDefaultMinBlockSize)
- : allocAndSize_(alloc, minBlockSize),
- ptr_(nullptr),
- end_(nullptr),
- totalAllocatedSize_(0) {
+ : allocAndSize_(alloc, minBlockSize)
+ , ptr_(nullptr)
+ , end_(nullptr)
+ , totalAllocatedSize_(0)
+ , bytesUsed_(0) {
}
~Arena();
void* allocate(size_t size) {
size = roundUp(size);
+ bytesUsed_ += size;
if (LIKELY(end_ - ptr_ >= size)) {
// Fast path: there's enough room in the current block
return totalAllocatedSize_ + sizeof(Arena);
}
+ // Gets the total number of "used" bytes, i.e. bytes that the arena users
+ // allocated via the calls to `allocate`. Doesn't include fragmentation, e.g.
+ // if block size is 4KB and you allocate 2 objects of 3KB in size,
+ // `bytesUsed()` will be 6KB, while `totalSize()` will be 8KB+.
+ size_t bytesUsed() const {
+ return bytesUsed_;
+ }
+
private:
// not copyable
Arena(const Arena&) = delete;
char* ptr_;
char* end_;
size_t totalAllocatedSize_;
+ size_t bytesUsed_;
};
/**
<< maximum_size;
}
+TEST(Arena, BytesUsedSanity) {
+ static const size_t smallChunkSize = 1024;
+ static const size_t blockSize = goodMallocSize(16 * smallChunkSize);
+ const size_t bigChunkSize = blockSize - 4 * smallChunkSize;
+
+ size_t bytesUsed = 0;
+
+ SysArena arena(blockSize);
+ EXPECT_EQ(arena.bytesUsed(), bytesUsed);
+
+ // Insert 2 small chunks
+ arena.allocate(smallChunkSize);
+ arena.allocate(smallChunkSize);
+ bytesUsed += 2 * smallChunkSize;
+ EXPECT_EQ(arena.bytesUsed(), bytesUsed);
+ EXPECT_TRUE(arena.totalSize() >= blockSize);
+ EXPECT_TRUE(arena.totalSize() <= 2 * blockSize);
+
+ // Insert big chunk, should still fit in one block
+ arena.allocate(bigChunkSize);
+ bytesUsed += bigChunkSize;
+ EXPECT_EQ(arena.bytesUsed(), bytesUsed);
+ EXPECT_TRUE(arena.totalSize() >= blockSize);
+ EXPECT_TRUE(arena.totalSize() <= 2 * blockSize);
+
+ // Insert big chunk once more, should trigger new block allocation
+ arena.allocate(bigChunkSize);
+ bytesUsed += bigChunkSize;
+ EXPECT_EQ(arena.bytesUsed(), bytesUsed);
+ EXPECT_TRUE(arena.totalSize() >= 2 * blockSize);
+ EXPECT_TRUE(arena.totalSize() <= 3 * blockSize);
+
+ // Test that bytesUsed() accounts for alignment
+ static const size_t tinyChunkSize = 7;
+ arena.allocate(tinyChunkSize);
+ EXPECT_TRUE(arena.bytesUsed() >= bytesUsed + tinyChunkSize);
+ size_t delta = arena.bytesUsed() - bytesUsed;
+ EXPECT_EQ(delta & (delta - 1), 0);
+}
+
TEST(Arena, Vector) {
static const size_t requestedBlockSize = 64;
SysArena arena(requestedBlockSize);