1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 #include "base/arena_allocator-inl.h" 18 #include "base/arena_bit_vector.h" 19 #include "base/memory_tool.h" 20 #include "gtest/gtest.h" 21 22 namespace art { 23 24 class ArenaAllocatorTest : public testing::Test { 25 protected: 26 size_t NumberOfArenas(ArenaAllocator* allocator) { 27 size_t result = 0u; 28 for (Arena* a = allocator->arena_head_; a != nullptr; a = a->next_) { 29 ++result; 30 } 31 return result; 32 } 33 }; 34 35 TEST_F(ArenaAllocatorTest, Test) { 36 ArenaPool pool; 37 ArenaAllocator allocator(&pool); 38 ArenaBitVector bv(&allocator, 10, true); 39 bv.SetBit(5); 40 EXPECT_EQ(1U, bv.GetStorageSize()); 41 bv.SetBit(35); 42 EXPECT_EQ(2U, bv.GetStorageSize()); 43 } 44 45 TEST_F(ArenaAllocatorTest, MakeDefined) { 46 // Regression test to make sure we mark the allocated area defined. 47 ArenaPool pool; 48 static constexpr size_t kSmallArraySize = 10; 49 static constexpr size_t kLargeArraySize = 50; 50 uint32_t* small_array; 51 { 52 // Allocate a small array from an arena and release it. 53 ArenaAllocator allocator(&pool); 54 small_array = allocator.AllocArray<uint32_t>(kSmallArraySize); 55 ASSERT_EQ(0u, small_array[kSmallArraySize - 1u]); 56 } 57 { 58 // Reuse the previous arena and allocate more than previous allocation including red zone. 59 ArenaAllocator allocator(&pool); 60 uint32_t* large_array = allocator.AllocArray<uint32_t>(kLargeArraySize); 61 ASSERT_EQ(0u, large_array[kLargeArraySize - 1u]); 62 // Verify that the allocation was made on the same arena. 63 ASSERT_EQ(small_array, large_array); 64 } 65 } 66 67 TEST_F(ArenaAllocatorTest, LargeAllocations) { 68 if (arena_allocator::kArenaAllocatorPreciseTracking) { 69 printf("WARNING: TEST DISABLED FOR precise arena tracking\n"); 70 return; 71 } 72 73 { 74 ArenaPool pool; 75 ArenaAllocator allocator(&pool); 76 // Note: Leaving some space for memory tool red zones. 77 void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 8); 78 void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 2 / 8); 79 ASSERT_NE(alloc1, alloc2); 80 ASSERT_EQ(1u, NumberOfArenas(&allocator)); 81 } 82 { 83 ArenaPool pool; 84 ArenaAllocator allocator(&pool); 85 void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16); 86 void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 11 / 16); 87 ASSERT_NE(alloc1, alloc2); 88 ASSERT_EQ(2u, NumberOfArenas(&allocator)); 89 void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 7 / 16); 90 ASSERT_NE(alloc1, alloc3); 91 ASSERT_NE(alloc2, alloc3); 92 ASSERT_EQ(3u, NumberOfArenas(&allocator)); 93 } 94 { 95 ArenaPool pool; 96 ArenaAllocator allocator(&pool); 97 void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16); 98 void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16); 99 ASSERT_NE(alloc1, alloc2); 100 ASSERT_EQ(2u, NumberOfArenas(&allocator)); 101 // Note: Leaving some space for memory tool red zones. 102 void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16); 103 ASSERT_NE(alloc1, alloc3); 104 ASSERT_NE(alloc2, alloc3); 105 ASSERT_EQ(2u, NumberOfArenas(&allocator)); 106 } 107 { 108 ArenaPool pool; 109 ArenaAllocator allocator(&pool); 110 void* alloc1 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 9 / 16); 111 void* alloc2 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 13 / 16); 112 ASSERT_NE(alloc1, alloc2); 113 ASSERT_EQ(2u, NumberOfArenas(&allocator)); 114 // Note: Leaving some space for memory tool red zones. 115 void* alloc3 = allocator.Alloc(arena_allocator::kArenaDefaultSize * 5 / 16); 116 ASSERT_NE(alloc1, alloc3); 117 ASSERT_NE(alloc2, alloc3); 118 ASSERT_EQ(2u, NumberOfArenas(&allocator)); 119 } 120 { 121 ArenaPool pool; 122 ArenaAllocator allocator(&pool); 123 // Note: Leaving some space for memory tool red zones. 124 for (size_t i = 0; i != 15; ++i) { 125 // Allocate 15 times from the same arena. 126 allocator.Alloc(arena_allocator::kArenaDefaultSize * 1 / 16); 127 ASSERT_EQ(i + 1u, NumberOfArenas(&allocator)); 128 // Allocate a separate arena. 129 allocator.Alloc(arena_allocator::kArenaDefaultSize * 17 / 16); 130 ASSERT_EQ(i + 2u, NumberOfArenas(&allocator)); 131 } 132 } 133 } 134 135 TEST_F(ArenaAllocatorTest, AllocAlignment) { 136 ArenaPool pool; 137 ArenaAllocator allocator(&pool); 138 for (size_t iterations = 0; iterations <= 10; ++iterations) { 139 for (size_t size = 1; size <= ArenaAllocator::kAlignment + 1; ++size) { 140 void* allocation = allocator.Alloc(size); 141 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(allocation)) 142 << reinterpret_cast<uintptr_t>(allocation); 143 } 144 } 145 } 146 147 TEST_F(ArenaAllocatorTest, ReallocReuse) { 148 // Realloc does not reuse arenas when running under sanitization. So we cannot do those 149 if (RUNNING_ON_MEMORY_TOOL != 0) { 150 printf("WARNING: TEST DISABLED FOR MEMORY_TOOL\n"); 151 return; 152 } 153 154 { 155 // Case 1: small aligned allocation, aligned extend inside arena. 156 ArenaPool pool; 157 ArenaAllocator allocator(&pool); 158 159 const size_t original_size = ArenaAllocator::kAlignment * 2; 160 void* original_allocation = allocator.Alloc(original_size); 161 162 const size_t new_size = ArenaAllocator::kAlignment * 3; 163 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 164 EXPECT_EQ(original_allocation, realloc_allocation); 165 } 166 167 { 168 // Case 2: small aligned allocation, non-aligned extend inside arena. 169 ArenaPool pool; 170 ArenaAllocator allocator(&pool); 171 172 const size_t original_size = ArenaAllocator::kAlignment * 2; 173 void* original_allocation = allocator.Alloc(original_size); 174 175 const size_t new_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 176 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 177 EXPECT_EQ(original_allocation, realloc_allocation); 178 } 179 180 { 181 // Case 3: small non-aligned allocation, aligned extend inside arena. 182 ArenaPool pool; 183 ArenaAllocator allocator(&pool); 184 185 const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 186 void* original_allocation = allocator.Alloc(original_size); 187 188 const size_t new_size = ArenaAllocator::kAlignment * 4; 189 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 190 EXPECT_EQ(original_allocation, realloc_allocation); 191 } 192 193 { 194 // Case 4: small non-aligned allocation, aligned non-extend inside arena. 195 ArenaPool pool; 196 ArenaAllocator allocator(&pool); 197 198 const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 199 void* original_allocation = allocator.Alloc(original_size); 200 201 const size_t new_size = ArenaAllocator::kAlignment * 3; 202 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 203 EXPECT_EQ(original_allocation, realloc_allocation); 204 } 205 206 // The next part is brittle, as the default size for an arena is variable, and we don't know about 207 // sanitization. 208 209 { 210 // Case 5: large allocation, aligned extend into next arena. 211 ArenaPool pool; 212 ArenaAllocator allocator(&pool); 213 214 const size_t original_size = arena_allocator::kArenaDefaultSize - 215 ArenaAllocator::kAlignment * 5; 216 void* original_allocation = allocator.Alloc(original_size); 217 218 const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2; 219 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 220 EXPECT_NE(original_allocation, realloc_allocation); 221 } 222 223 { 224 // Case 6: large allocation, non-aligned extend into next arena. 225 ArenaPool pool; 226 ArenaAllocator allocator(&pool); 227 228 const size_t original_size = arena_allocator::kArenaDefaultSize - 229 ArenaAllocator::kAlignment * 4 - 230 ArenaAllocator::kAlignment / 2; 231 void* original_allocation = allocator.Alloc(original_size); 232 233 const size_t new_size = arena_allocator::kArenaDefaultSize + 234 ArenaAllocator::kAlignment * 2 + 235 ArenaAllocator::kAlignment / 2; 236 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 237 EXPECT_NE(original_allocation, realloc_allocation); 238 } 239 } 240 241 TEST_F(ArenaAllocatorTest, ReallocAlignment) { 242 { 243 // Case 1: small aligned allocation, aligned extend inside arena. 244 ArenaPool pool; 245 ArenaAllocator allocator(&pool); 246 247 const size_t original_size = ArenaAllocator::kAlignment * 2; 248 void* original_allocation = allocator.Alloc(original_size); 249 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 250 251 const size_t new_size = ArenaAllocator::kAlignment * 3; 252 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 253 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 254 255 void* after_alloc = allocator.Alloc(1); 256 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 257 } 258 259 { 260 // Case 2: small aligned allocation, non-aligned extend inside arena. 261 ArenaPool pool; 262 ArenaAllocator allocator(&pool); 263 264 const size_t original_size = ArenaAllocator::kAlignment * 2; 265 void* original_allocation = allocator.Alloc(original_size); 266 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 267 268 const size_t new_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 269 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 270 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 271 272 void* after_alloc = allocator.Alloc(1); 273 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 274 } 275 276 { 277 // Case 3: small non-aligned allocation, aligned extend inside arena. 278 ArenaPool pool; 279 ArenaAllocator allocator(&pool); 280 281 const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 282 void* original_allocation = allocator.Alloc(original_size); 283 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 284 285 const size_t new_size = ArenaAllocator::kAlignment * 4; 286 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 287 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 288 289 void* after_alloc = allocator.Alloc(1); 290 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 291 } 292 293 { 294 // Case 4: small non-aligned allocation, aligned non-extend inside arena. 295 ArenaPool pool; 296 ArenaAllocator allocator(&pool); 297 298 const size_t original_size = ArenaAllocator::kAlignment * 2 + (ArenaAllocator::kAlignment / 2); 299 void* original_allocation = allocator.Alloc(original_size); 300 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 301 302 const size_t new_size = ArenaAllocator::kAlignment * 3; 303 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 304 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 305 306 void* after_alloc = allocator.Alloc(1); 307 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 308 } 309 310 // The next part is brittle, as the default size for an arena is variable, and we don't know about 311 // sanitization. 312 313 { 314 // Case 5: large allocation, aligned extend into next arena. 315 ArenaPool pool; 316 ArenaAllocator allocator(&pool); 317 318 const size_t original_size = arena_allocator::kArenaDefaultSize - 319 ArenaAllocator::kAlignment * 5; 320 void* original_allocation = allocator.Alloc(original_size); 321 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 322 323 const size_t new_size = arena_allocator::kArenaDefaultSize + ArenaAllocator::kAlignment * 2; 324 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 325 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 326 327 void* after_alloc = allocator.Alloc(1); 328 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 329 } 330 331 { 332 // Case 6: large allocation, non-aligned extend into next arena. 333 ArenaPool pool; 334 ArenaAllocator allocator(&pool); 335 336 const size_t original_size = arena_allocator::kArenaDefaultSize - 337 ArenaAllocator::kAlignment * 4 - 338 ArenaAllocator::kAlignment / 2; 339 void* original_allocation = allocator.Alloc(original_size); 340 ASSERT_TRUE(IsAligned<ArenaAllocator::kAlignment>(original_allocation)); 341 342 const size_t new_size = arena_allocator::kArenaDefaultSize + 343 ArenaAllocator::kAlignment * 2 + 344 ArenaAllocator::kAlignment / 2; 345 void* realloc_allocation = allocator.Realloc(original_allocation, original_size, new_size); 346 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(realloc_allocation)); 347 348 void* after_alloc = allocator.Alloc(1); 349 EXPECT_TRUE(IsAligned<ArenaAllocator::kAlignment>(after_alloc)); 350 } 351 } 352 353 354 } // namespace art 355