LCOV - code coverage report
Current view: top level - test/unittests/base - region-allocator-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 117 157 74.5 %
Date: 2019-03-21 Functions: 18 31 58.1 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/base/region-allocator.h"
       6             : #include "test/unittests/test-utils.h"
       7             : 
       8             : #include "testing/gtest/include/gtest/gtest.h"
       9             : 
      10             : namespace v8 {
      11             : namespace base {
      12             : 
      13             : using Address = RegionAllocator::Address;
      14             : using v8::internal::KB;
      15             : using v8::internal::MB;
      16             : 
      17           0 : class RegionAllocatorTest : public ::testing::TestWithParam<int> {};
      18             : 
      19       15373 : TEST(RegionAllocatorTest, SimpleAllocateRegionAt) {
      20             :   const size_t kPageSize = 4 * KB;
      21             :   const size_t kPageCount = 16;
      22             :   const size_t kSize = kPageSize * kPageCount;
      23             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
      24             :   const Address kEnd = kBegin + kSize;
      25             : 
      26           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
      27             : 
      28             :   // Allocate the whole region.
      29          33 :   for (Address address = kBegin; address < kEnd; address += kPageSize) {
      30          16 :     CHECK_EQ(ra.free_size(), kEnd - address);
      31          16 :     CHECK(ra.AllocateRegionAt(address, kPageSize));
      32             :   }
      33             : 
      34             :   // No free regions left, the allocation should fail.
      35           1 :   CHECK_EQ(ra.free_size(), 0);
      36           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
      37             : 
      38             :   // Free one region and then the allocation should succeed.
      39           1 :   CHECK_EQ(ra.FreeRegion(kBegin), kPageSize);
      40           1 :   CHECK_EQ(ra.free_size(), kPageSize);
      41           1 :   CHECK(ra.AllocateRegionAt(kBegin, kPageSize));
      42             : 
      43             :   // Free all the pages.
      44          33 :   for (Address address = kBegin; address < kEnd; address += kPageSize) {
      45          16 :     CHECK_EQ(ra.FreeRegion(address), kPageSize);
      46             :   }
      47             : 
      48             :   // Check that the whole region is free and can be fully allocated.
      49           1 :   CHECK_EQ(ra.free_size(), kSize);
      50           1 :   CHECK_EQ(ra.AllocateRegion(kSize), kBegin);
      51           1 : }
      52             : 
      53       15373 : TEST(RegionAllocatorTest, SimpleAllocateRegion) {
      54             :   const size_t kPageSize = 4 * KB;
      55             :   const size_t kPageCount = 16;
      56             :   const size_t kSize = kPageSize * kPageCount;
      57             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
      58             :   const Address kEnd = kBegin + kSize;
      59             : 
      60           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
      61             : 
      62             :   // Allocate the whole region.
      63          33 :   for (size_t i = 0; i < kPageCount; i++) {
      64          16 :     CHECK_EQ(ra.free_size(), kSize - kPageSize * i);
      65          16 :     Address address = ra.AllocateRegion(kPageSize);
      66          16 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
      67          16 :     CHECK_EQ(address, kBegin + kPageSize * i);
      68             :   }
      69             : 
      70             :   // No free regions left, the allocation should fail.
      71           1 :   CHECK_EQ(ra.free_size(), 0);
      72           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
      73             : 
      74             :   // Try to free one page and ensure that we are able to allocate it again.
      75          33 :   for (Address address = kBegin; address < kEnd; address += kPageSize) {
      76          16 :     CHECK_EQ(ra.FreeRegion(address), kPageSize);
      77          16 :     CHECK_EQ(ra.AllocateRegion(kPageSize), address);
      78             :   }
      79           1 :   CHECK_EQ(ra.free_size(), 0);
      80           1 : }
      81             : 
      82       18444 : TEST_P(RegionAllocatorTest, AllocateRegionRandom) {
      83             :   const size_t kPageSize = 8 * KB;
      84             :   const size_t kPageCountLog = 16;
      85             :   const size_t kPageCount = (size_t{1} << kPageCountLog);
      86             :   const size_t kSize = kPageSize * kPageCount;
      87             :   const Address kBegin = static_cast<Address>(153 * MB);
      88             :   const Address kEnd = kBegin + kSize;
      89             : 
      90           0 :   base::RandomNumberGenerator rng(GetParam());
      91           0 :   RegionAllocator ra(kBegin, kSize, kPageSize);
      92             : 
      93             :   std::set<Address> allocated_pages;
      94             :   // The page addresses must be randomized this number of allocated pages.
      95           0 :   const size_t kRandomizationLimit = ra.max_load_for_randomization_ / kPageSize;
      96           0 :   CHECK_LT(kRandomizationLimit, kPageCount);
      97             : 
      98             :   Address last_address = kBegin;
      99             :   bool saw_randomized_pages = false;
     100             : 
     101           0 :   for (size_t i = 0; i < kPageCount; i++) {
     102           0 :     Address address = ra.AllocateRegion(&rng, kPageSize);
     103           0 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
     104           0 :     CHECK(IsAligned(address, kPageSize));
     105           0 :     CHECK_LE(kBegin, address);
     106           0 :     CHECK_LT(address, kEnd);
     107           0 :     CHECK_EQ(allocated_pages.find(address), allocated_pages.end());
     108             :     allocated_pages.insert(address);
     109             : 
     110           0 :     saw_randomized_pages |= (address < last_address);
     111             :     last_address = address;
     112             : 
     113           0 :     if (i == kRandomizationLimit) {
     114             :       // We must evidence allocation randomization till this point.
     115             :       // The rest of the allocations may still be randomized depending on
     116             :       // the free ranges distribution, however it is not guaranteed.
     117           0 :       CHECK(saw_randomized_pages);
     118             :     }
     119             :   }
     120             : 
     121             :   // No free regions left, the allocation should fail.
     122           0 :   CHECK_EQ(ra.free_size(), 0);
     123           0 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     124           0 : }
     125             : 
     126       15373 : TEST(RegionAllocatorTest, AllocateBigRegions) {
     127             :   const size_t kPageSize = 4 * KB;
     128             :   const size_t kPageCountLog = 10;
     129             :   const size_t kPageCount = (size_t{1} << kPageCountLog) - 1;
     130             :   const size_t kSize = kPageSize * kPageCount;
     131             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     132             : 
     133           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     134             : 
     135             :   // Allocate the whole region.
     136          21 :   for (size_t i = 0; i < kPageCountLog; i++) {
     137          10 :     Address address = ra.AllocateRegion(kPageSize * (size_t{1} << i));
     138          10 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
     139          10 :     CHECK_EQ(address, kBegin + kPageSize * ((size_t{1} << i) - 1));
     140             :   }
     141             : 
     142             :   // No free regions left, the allocation should fail.
     143           1 :   CHECK_EQ(ra.free_size(), 0);
     144           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     145             : 
     146             :   // Try to free one page and ensure that we are able to allocate it again.
     147          21 :   for (size_t i = 0; i < kPageCountLog; i++) {
     148          10 :     const size_t size = kPageSize * (size_t{1} << i);
     149          10 :     Address address = kBegin + kPageSize * ((size_t{1} << i) - 1);
     150          10 :     CHECK_EQ(ra.FreeRegion(address), size);
     151          10 :     CHECK_EQ(ra.AllocateRegion(size), address);
     152             :   }
     153           1 :   CHECK_EQ(ra.free_size(), 0);
     154           1 : }
     155             : 
     156       15373 : TEST(RegionAllocatorTest, MergeLeftToRightCoalecsingRegions) {
     157             :   const size_t kPageSize = 4 * KB;
     158             :   const size_t kPageCountLog = 10;
     159             :   const size_t kPageCount = (size_t{1} << kPageCountLog);
     160             :   const size_t kSize = kPageSize * kPageCount;
     161             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     162             : 
     163           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     164             : 
     165             :   // Allocate the whole region using the following page size pattern:
     166             :   // |0|1|22|3333|...
     167           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), kBegin);
     168          21 :   for (size_t i = 0; i < kPageCountLog; i++) {
     169          10 :     Address address = ra.AllocateRegion(kPageSize * (size_t{1} << i));
     170          10 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
     171          10 :     CHECK_EQ(address, kBegin + kPageSize * (size_t{1} << i));
     172             :   }
     173             : 
     174             :   // No free regions left, the allocation should fail.
     175           1 :   CHECK_EQ(ra.free_size(), 0);
     176           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     177             : 
     178             :   // Try to free two coalescing regions and ensure the new page of bigger size
     179             :   // can be allocated.
     180             :   size_t current_size = kPageSize;
     181          21 :   for (size_t i = 0; i < kPageCountLog; i++) {
     182          10 :     CHECK_EQ(ra.FreeRegion(kBegin), current_size);
     183          20 :     CHECK_EQ(ra.FreeRegion(kBegin + current_size), current_size);
     184          10 :     current_size += current_size;
     185          10 :     CHECK_EQ(ra.AllocateRegion(current_size), kBegin);
     186             :   }
     187           1 :   CHECK_EQ(ra.free_size(), 0);
     188           1 : }
     189             : 
     190       18444 : TEST_P(RegionAllocatorTest, MergeRightToLeftCoalecsingRegions) {
     191           0 :   base::RandomNumberGenerator rng(GetParam());
     192             :   const size_t kPageSize = 4 * KB;
     193             :   const size_t kPageCountLog = 10;
     194             :   const size_t kPageCount = (size_t{1} << kPageCountLog);
     195             :   const size_t kSize = kPageSize * kPageCount;
     196             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     197             : 
     198           0 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     199             : 
     200             :   // Allocate the whole region.
     201           0 :   for (size_t i = 0; i < kPageCount; i++) {
     202           0 :     Address address = ra.AllocateRegion(kPageSize);
     203           0 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
     204           0 :     CHECK_EQ(address, kBegin + kPageSize * i);
     205             :   }
     206             : 
     207             :   // No free regions left, the allocation should fail.
     208           0 :   CHECK_EQ(ra.free_size(), 0);
     209           0 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     210             : 
     211             :   // Free pages with even indices left-to-right.
     212           0 :   for (size_t i = 0; i < kPageCount; i += 2) {
     213           0 :     Address address = kBegin + kPageSize * i;
     214           0 :     CHECK_EQ(ra.FreeRegion(address), kPageSize);
     215             :   }
     216             : 
     217             :   // Free pages with odd indices right-to-left.
     218           0 :   for (size_t i = 1; i < kPageCount; i += 2) {
     219           0 :     Address address = kBegin + kPageSize * (kPageCount - i);
     220           0 :     CHECK_EQ(ra.FreeRegion(address), kPageSize);
     221             :     // Now we should be able to allocate a double-sized page.
     222           0 :     CHECK_EQ(ra.AllocateRegion(kPageSize * 2), address - kPageSize);
     223             :     // .. but there's a window for only one such page.
     224           0 :     CHECK_EQ(ra.AllocateRegion(kPageSize * 2),
     225             :              RegionAllocator::kAllocationFailure);
     226             :   }
     227             : 
     228             :   // Free all the double-sized pages.
     229           0 :   for (size_t i = 0; i < kPageCount; i += 2) {
     230           0 :     Address address = kBegin + kPageSize * i;
     231           0 :     CHECK_EQ(ra.FreeRegion(address), kPageSize * 2);
     232             :   }
     233             : 
     234             :   // Check that the whole region is free and can be fully allocated.
     235           0 :   CHECK_EQ(ra.free_size(), kSize);
     236           0 :   CHECK_EQ(ra.AllocateRegion(kSize), kBegin);
     237           0 : }
     238             : 
     239       15373 : TEST(RegionAllocatorTest, Fragmentation) {
     240             :   const size_t kPageSize = 64 * KB;
     241             :   const size_t kPageCount = 9;
     242             :   const size_t kSize = kPageSize * kPageCount;
     243             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     244             : 
     245           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     246             : 
     247             :   // Allocate the whole region.
     248          19 :   for (size_t i = 0; i < kPageCount; i++) {
     249           9 :     Address address = ra.AllocateRegion(kPageSize);
     250           9 :     CHECK_NE(address, RegionAllocator::kAllocationFailure);
     251           9 :     CHECK_EQ(address, kBegin + kPageSize * i);
     252             :   }
     253             : 
     254             :   // No free regions left, the allocation should fail.
     255           1 :   CHECK_EQ(ra.free_size(), 0);
     256           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     257             : 
     258             :   // Free pages in the following order and check the freed size.
     259             :   struct {
     260             :     size_t page_index_to_free;
     261             :     size_t expected_page_count;
     262             :   } testcase[] = {          // .........
     263             :                   {0, 9},   // x........
     264             :                   {2, 9},   // x.x......
     265             :                   {4, 9},   // x.x.x....
     266             :                   {6, 9},   // x.x.x.x..
     267             :                   {8, 9},   // x.x.x.x.x
     268             :                   {1, 7},   // xxx.x.x.x
     269             :                   {7, 5},   // xxx.x.xxx
     270             :                   {3, 3},   // xxxxx.xxx
     271           1 :                   {5, 1}};  // xxxxxxxxx
     272             :   CHECK_EQ(kPageCount, arraysize(testcase));
     273             : 
     274           1 :   CHECK_EQ(ra.all_regions_.size(), kPageCount);
     275          19 :   for (size_t i = 0; i < kPageCount; i++) {
     276           9 :     Address address = kBegin + kPageSize * testcase[i].page_index_to_free;
     277           9 :     CHECK_EQ(ra.FreeRegion(address), kPageSize);
     278           9 :     CHECK_EQ(ra.all_regions_.size(), testcase[i].expected_page_count);
     279             :   }
     280             : 
     281             :   // Check that the whole region is free and can be fully allocated.
     282           1 :   CHECK_EQ(ra.free_size(), kSize);
     283           1 :   CHECK_EQ(ra.AllocateRegion(kSize), kBegin);
     284           1 : }
     285             : 
     286       15373 : TEST(RegionAllocatorTest, FindRegion) {
     287             :   const size_t kPageSize = 4 * KB;
     288             :   const size_t kPageCount = 16;
     289             :   const size_t kSize = kPageSize * kPageCount;
     290             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     291             :   const Address kEnd = kBegin + kSize;
     292             : 
     293           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     294             : 
     295             :   // Allocate the whole region.
     296          33 :   for (Address address = kBegin; address < kEnd; address += kPageSize) {
     297          16 :     CHECK_EQ(ra.free_size(), kEnd - address);
     298          16 :     CHECK(ra.AllocateRegionAt(address, kPageSize));
     299             :   }
     300             : 
     301             :   // No free regions left, the allocation should fail.
     302           1 :   CHECK_EQ(ra.free_size(), 0);
     303           1 :   CHECK_EQ(ra.AllocateRegion(kPageSize), RegionAllocator::kAllocationFailure);
     304             : 
     305             :   // The out-of region requests must return end iterator.
     306           2 :   CHECK_EQ(ra.FindRegion(kBegin - 1), ra.all_regions_.end());
     307           2 :   CHECK_EQ(ra.FindRegion(kBegin - kPageSize), ra.all_regions_.end());
     308           2 :   CHECK_EQ(ra.FindRegion(kBegin / 2), ra.all_regions_.end());
     309           2 :   CHECK_EQ(ra.FindRegion(kEnd), ra.all_regions_.end());
     310           2 :   CHECK_EQ(ra.FindRegion(kEnd + kPageSize), ra.all_regions_.end());
     311           2 :   CHECK_EQ(ra.FindRegion(kEnd * 2), ra.all_regions_.end());
     312             : 
     313         129 :   for (Address address = kBegin; address < kEnd; address += kPageSize / 4) {
     314             :     RegionAllocator::AllRegionsSet::iterator region_iter =
     315          64 :         ra.FindRegion(address);
     316          64 :     CHECK_NE(region_iter, ra.all_regions_.end());
     317          64 :     RegionAllocator::Region* region = *region_iter;
     318             :     Address region_start = RoundDown(address, kPageSize);
     319          64 :     CHECK_EQ(region->begin(), region_start);
     320          64 :     CHECK_LE(region->begin(), address);
     321          64 :     CHECK_LT(address, region->end());
     322             :   }
     323           1 : }
     324             : 
     325       15373 : TEST(RegionAllocatorTest, TrimRegion) {
     326             :   const size_t kPageSize = 4 * KB;
     327             :   const size_t kPageCount = 64;
     328             :   const size_t kSize = kPageSize * kPageCount;
     329             :   const Address kBegin = static_cast<Address>(kPageSize * 153);
     330             : 
     331           2 :   RegionAllocator ra(kBegin, kSize, kPageSize);
     332             : 
     333             :   Address address = kBegin + 13 * kPageSize;
     334           1 :   size_t size = 37 * kPageSize;
     335             :   size_t free_size = kSize - size;
     336           1 :   CHECK(ra.AllocateRegionAt(address, size));
     337             : 
     338           1 :   size_t trim_size = kPageSize;
     339             :   do {
     340           6 :     CHECK_EQ(ra.CheckRegion(address), size);
     341           6 :     CHECK_EQ(ra.free_size(), free_size);
     342             : 
     343           6 :     trim_size = std::min(size, trim_size);
     344           6 :     size -= trim_size;
     345           6 :     free_size += trim_size;
     346           6 :     CHECK_EQ(ra.TrimRegion(address, size), trim_size);
     347           6 :     trim_size *= 2;
     348           6 :   } while (size != 0);
     349             : 
     350             :   // Check that the whole region is free and can be fully allocated.
     351           1 :   CHECK_EQ(ra.free_size(), kSize);
     352           1 :   CHECK_EQ(ra.AllocateRegion(kSize), kBegin);
     353           1 : }
     354             : 
     355             : }  // namespace base
     356        9222 : }  // namespace v8

Generated by: LCOV version 1.10