2 * Copyright 2014 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/Arena.h>
18 #include <folly/Memory.h>
23 #include <glog/logging.h>
24 #include <gtest/gtest.h>
26 using namespace folly;
28 static_assert(IsArenaAllocator<SysArena>::value, "");
30 TEST(Arena, SizeSanity) {
31 std::set<size_t*> allocatedItems;
33 static const size_t requestedBlockSize = 64;
34 SysArena arena(requestedBlockSize);
35 size_t minimum_size = sizeof(SysArena), maximum_size = minimum_size;
36 EXPECT_EQ(arena.totalSize(), minimum_size);
38 // Insert a single small element to get a new block
39 size_t* ptr = static_cast<size_t*>(arena.allocate(sizeof(long)));
40 allocatedItems.insert(ptr);
41 minimum_size += requestedBlockSize;
42 maximum_size += goodMallocSize(requestedBlockSize + 1);
43 EXPECT_TRUE(arena.totalSize() >= minimum_size);
44 EXPECT_TRUE(arena.totalSize() <= maximum_size);
45 VLOG(4) << minimum_size << " < " << arena.totalSize() << " < "
48 // Insert a larger element, size should be the same
49 ptr = static_cast<size_t*>(arena.allocate(requestedBlockSize / 2));
50 allocatedItems.insert(ptr);
51 EXPECT_TRUE(arena.totalSize() >= minimum_size);
52 EXPECT_TRUE(arena.totalSize() <= maximum_size);
53 VLOG(4) << minimum_size << " < " << arena.totalSize() << " < "
56 // Insert 10 full block sizes to get 10 new blocks
57 for (int i = 0; i < 10; i++) {
58 ptr = static_cast<size_t*>(arena.allocate(requestedBlockSize));
59 allocatedItems.insert(ptr);
61 minimum_size += 10 * requestedBlockSize;
62 maximum_size += 10 * goodMallocSize(requestedBlockSize + 1);
63 EXPECT_TRUE(arena.totalSize() >= minimum_size);
64 EXPECT_TRUE(arena.totalSize() <= maximum_size);
65 VLOG(4) << minimum_size << " < " << arena.totalSize() << " < "
68 // Insert something huge
69 ptr = static_cast<size_t*>(arena.allocate(10 * requestedBlockSize));
70 allocatedItems.insert(ptr);
71 minimum_size += 10 * requestedBlockSize;
72 maximum_size += goodMallocSize(10 * requestedBlockSize + 1);
73 EXPECT_TRUE(arena.totalSize() >= minimum_size);
74 EXPECT_TRUE(arena.totalSize() <= maximum_size);
75 VLOG(4) << minimum_size << " < " << arena.totalSize() << " < "
79 for (const auto& item : allocatedItems) {
80 arena.deallocate(item);
82 //The total size should be the same
83 EXPECT_TRUE(arena.totalSize() >= minimum_size);
84 EXPECT_TRUE(arena.totalSize() <= maximum_size);
85 VLOG(4) << minimum_size << " < " << arena.totalSize() << " < "
89 TEST(Arena, BytesUsedSanity) {
90 static const size_t smallChunkSize = 1024;
91 static const size_t blockSize = goodMallocSize(16 * smallChunkSize);
92 const size_t bigChunkSize = blockSize - 4 * smallChunkSize;
96 SysArena arena(blockSize);
97 EXPECT_EQ(arena.bytesUsed(), bytesUsed);
99 // Insert 2 small chunks
100 arena.allocate(smallChunkSize);
101 arena.allocate(smallChunkSize);
102 bytesUsed += 2 * smallChunkSize;
103 EXPECT_EQ(arena.bytesUsed(), bytesUsed);
104 EXPECT_TRUE(arena.totalSize() >= blockSize);
105 EXPECT_TRUE(arena.totalSize() <= 2 * blockSize);
107 // Insert big chunk, should still fit in one block
108 arena.allocate(bigChunkSize);
109 bytesUsed += bigChunkSize;
110 EXPECT_EQ(arena.bytesUsed(), bytesUsed);
111 EXPECT_TRUE(arena.totalSize() >= blockSize);
112 EXPECT_TRUE(arena.totalSize() <= 2 * blockSize);
114 // Insert big chunk once more, should trigger new block allocation
115 arena.allocate(bigChunkSize);
116 bytesUsed += bigChunkSize;
117 EXPECT_EQ(arena.bytesUsed(), bytesUsed);
118 EXPECT_TRUE(arena.totalSize() >= 2 * blockSize);
119 EXPECT_TRUE(arena.totalSize() <= 3 * blockSize);
121 // Test that bytesUsed() accounts for alignment
122 static const size_t tinyChunkSize = 7;
123 arena.allocate(tinyChunkSize);
124 EXPECT_TRUE(arena.bytesUsed() >= bytesUsed + tinyChunkSize);
125 size_t delta = arena.bytesUsed() - bytesUsed;
126 EXPECT_EQ(delta & (delta - 1), 0);
129 TEST(Arena, Vector) {
130 static const size_t requestedBlockSize = 64;
131 SysArena arena(requestedBlockSize);
133 EXPECT_EQ(arena.totalSize(), sizeof(SysArena));
135 std::vector<size_t, StlAllocator<SysArena, size_t>>
136 vec { {}, StlAllocator<SysArena, size_t>(&arena) };
138 for (size_t i = 0; i < 1000; i++) {
142 for (size_t i = 0; i < 1000; i++) {
143 EXPECT_EQ(i, vec[i]);
147 TEST(Arena, SizeLimit) {
148 static const size_t requestedBlockSize = sizeof(size_t);
149 static const size_t maxSize = 10 * requestedBlockSize;
151 SysArena arena(requestedBlockSize, maxSize);
153 void* a = arena.allocate(sizeof(size_t));
154 EXPECT_TRUE(a != nullptr);
155 EXPECT_THROW(arena.allocate(maxSize + 1), std::bad_alloc);
158 int main(int argc, char *argv[]) {
159 testing::InitGoogleTest(&argc, argv);
160 gflags::ParseCommandLineFlags(&argc, &argv, true);
161 auto ret = RUN_ALL_TESTS();