LCOV - code coverage report
Current view: top level - src/zone - accounting-allocator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 81 83 97.6 %
Date: 2019-02-19 Functions: 16 17 94.1 %

          Line data    Source code
       1             : // Copyright 2016 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/zone/accounting-allocator.h"
       6             : 
       7             : #include <cstdlib>
       8             : 
       9             : #if V8_LIBC_BIONIC
      10             : #include <malloc.h>  // NOLINT
      11             : #endif
      12             : 
      13             : #include "src/allocation.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18     2678730 : AccountingAllocator::AccountingAllocator() : unused_segments_mutex_() {
      19             :   static const size_t kDefaultBucketMaxSize = 5;
      20             : 
      21             :   memory_pressure_level_.SetValue(MemoryPressureLevel::kNone);
      22             :   std::fill(unused_segments_heads_, unused_segments_heads_ + kNumberBuckets,
      23     2678730 :             nullptr);
      24     2678730 :   std::fill(unused_segments_sizes_, unused_segments_sizes_ + kNumberBuckets, 0);
      25             :   std::fill(unused_segments_max_sizes_,
      26             :             unused_segments_max_sizes_ + kNumberBuckets, kDefaultBucketMaxSize);
      27     2678730 : }
      28             : 
      29     2662932 : AccountingAllocator::~AccountingAllocator() { ClearPool(); }
      30             : 
      31          83 : void AccountingAllocator::MemoryPressureNotification(
      32             :     MemoryPressureLevel level) {
      33             :   memory_pressure_level_.SetValue(level);
      34             : 
      35          83 :   if (level != MemoryPressureLevel::kNone) {
      36          78 :     ClearPool();
      37             :   }
      38          83 : }
      39             : 
      40       60751 : void AccountingAllocator::ConfigureSegmentPool(const size_t max_pool_size) {
      41             :   // The sum of the bytes of one segment of each size.
      42             :   static const size_t full_size = (size_t(1) << (kMaxSegmentSizePower + 1)) -
      43             :                                   (size_t(1) << kMinSegmentSizePower);
      44       60751 :   size_t fits_fully = max_pool_size / full_size;
      45             : 
      46       60751 :   base::MutexGuard lock_guard(&unused_segments_mutex_);
      47             : 
      48             :   // We assume few zones (less than 'fits_fully' many) to be active at the same
      49             :   // time. When zones grow regularly, they will keep requesting segments of
      50             :   // increasing size each time. Therefore we try to get as many segments with an
      51             :   // equal number of segments of each size as possible.
      52             :   // The remaining space is used to make more room for an 'incomplete set' of
      53             :   // segments beginning with the smaller ones.
      54             :   // This code will work best if the max_pool_size is a multiple of the
      55             :   // full_size. If max_pool_size is no sum of segment sizes the actual pool
      56             :   // size might be smaller then max_pool_size. Note that no actual memory gets
      57             :   // wasted though.
      58             :   // TODO(heimbuef): Determine better strategy generating a segment sizes
      59             :   // distribution that is closer to real/benchmark usecases and uses the given
      60             :   // max_pool_size more efficiently.
      61       60751 :   size_t total_size = fits_fully * full_size;
      62             : 
      63      425257 :   for (size_t power = 0; power < kNumberBuckets; ++power) {
      64      364506 :     if (total_size + (size_t(1) << (power + kMinSegmentSizePower)) <=
      65             :         max_pool_size) {
      66       29552 :       unused_segments_max_sizes_[power] = fits_fully + 1;
      67       29552 :       total_size += size_t(1) << power;
      68             :     } else {
      69      334954 :       unused_segments_max_sizes_[power] = fits_fully;
      70             :     }
      71             :   }
      72       60751 : }
      73             : 
      74    52052928 : Segment* AccountingAllocator::GetSegment(size_t bytes) {
      75    52052928 :   Segment* result = GetSegmentFromPool(bytes);
      76    52060082 :   if (result == nullptr) {
      77    26190242 :     result = AllocateSegment(bytes);
      78    26190230 :     if (result != nullptr) {
      79             :       result->Initialize(bytes);
      80             :     }
      81             :   }
      82             : 
      83    52060070 :   return result;
      84             : }
      85             : 
      86    26190229 : Segment* AccountingAllocator::AllocateSegment(size_t bytes) {
      87    26190229 :   void* memory = AllocWithRetry(bytes);
      88    26190203 :   if (memory != nullptr) {
      89             :     base::AtomicWord current =
      90    26190223 :         base::Relaxed_AtomicIncrement(&current_memory_usage_, bytes);
      91    26190223 :     base::AtomicWord max = base::Relaxed_Load(&max_memory_usage_);
      92    56834728 :     while (current > max) {
      93             :       max = base::Relaxed_CompareAndSwap(&max_memory_usage_, max, current);
      94             :     }
      95             :   }
      96    26190203 :   return reinterpret_cast<Segment*>(memory);
      97             : }
      98             : 
      99    52040825 : void AccountingAllocator::ReturnSegment(Segment* segment) {
     100    52040825 :   segment->ZapContents();
     101             : 
     102    52040630 :   if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) {
     103        2236 :     FreeSegment(segment);
     104    52038394 :   } else if (!AddSegmentToPool(segment)) {
     105    24617684 :     FreeSegment(segment);
     106             :   }
     107    52045415 : }
     108             : 
     109    26175223 : void AccountingAllocator::FreeSegment(Segment* memory) {
     110             :   base::Relaxed_AtomicIncrement(&current_memory_usage_,
     111    26175223 :                                 -static_cast<base::AtomicWord>(memory->size()));
     112    26175223 :   memory->ZapHeader();
     113    26175232 :   free(memory);
     114    26175232 : }
     115             : 
     116         507 : size_t AccountingAllocator::GetCurrentMemoryUsage() const {
     117        1014 :   return base::Relaxed_Load(&current_memory_usage_);
     118             : }
     119             : 
     120         507 : size_t AccountingAllocator::GetMaxMemoryUsage() const {
     121        1014 :   return base::Relaxed_Load(&max_memory_usage_);
     122             : }
     123             : 
     124           0 : size_t AccountingAllocator::GetCurrentPoolSize() const {
     125           0 :   return base::Relaxed_Load(&current_pool_size_);
     126             : }
     127             : 
     128    52052952 : Segment* AccountingAllocator::GetSegmentFromPool(size_t requested_size) {
     129    52052952 :   if (requested_size > (1 << kMaxSegmentSizePower)) {
     130             :     return nullptr;
     131             :   }
     132             : 
     133             :   size_t power = kMinSegmentSizePower;
     134    15356217 :   while (requested_size > (static_cast<size_t>(1) << power)) power++;
     135             : 
     136             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     137    51910752 :   power -= kMinSegmentSizePower;
     138             : 
     139    51740018 :   Segment* segment;
     140             :   {
     141    51910752 :     base::MutexGuard lock_guard(&unused_segments_mutex_);
     142             : 
     143    51917798 :     segment = unused_segments_heads_[power];
     144             : 
     145    51917798 :     if (segment != nullptr) {
     146    25870009 :       unused_segments_heads_[power] = segment->next();
     147             :       segment->set_next(nullptr);
     148             : 
     149    25870009 :       unused_segments_sizes_[power]--;
     150             :       base::Relaxed_AtomicIncrement(
     151    25870009 :           &current_pool_size_, -static_cast<base::AtomicWord>(segment->size()));
     152             :     }
     153             :   }
     154             : 
     155             :   if (segment) {
     156             :     DCHECK_GE(segment->size(), requested_size);
     157             :   }
     158    51917701 :   return segment;
     159             : }
     160             : 
     161    52038106 : bool AccountingAllocator::AddSegmentToPool(Segment* segment) {
     162             :   size_t size = segment->size();
     163             : 
     164    52038106 :   if (size >= (1 << (kMaxSegmentSizePower + 1))) return false;
     165             : 
     166    51946719 :   if (size < (1 << kMinSegmentSizePower)) return false;
     167             : 
     168             :   size_t power = kMaxSegmentSizePower;
     169             : 
     170   249746170 :   while (size < (static_cast<size_t>(1) << power)) power--;
     171             : 
     172             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     173    51946996 :   power -= kMinSegmentSizePower;
     174             : 
     175             :   {
     176    51946996 :     base::MutexGuard lock_guard(&unused_segments_mutex_);
     177             : 
     178    51951743 :     if (unused_segments_sizes_[power] >= unused_segments_max_sizes_[power]) {
     179             :       return false;
     180             :     }
     181             : 
     182    27425651 :     segment->set_next(unused_segments_heads_[power]);
     183    27425651 :     unused_segments_heads_[power] = segment;
     184    27425651 :     base::Relaxed_AtomicIncrement(&current_pool_size_, size);
     185    27425651 :     unused_segments_sizes_[power]++;
     186             :   }
     187             : 
     188    27425586 :   return true;
     189             : }
     190             : 
     191     2663010 : void AccountingAllocator::ClearPool() {
     192     2663010 :   base::MutexGuard lock_guard(&unused_segments_mutex_);
     193             : 
     194    18641077 :   for (size_t power = 0; power <= kMaxSegmentSizePower - kMinSegmentSizePower;
     195             :        power++) {
     196    17533368 :     Segment* current = unused_segments_heads_[power];
     197    33511434 :     while (current) {
     198             :       Segment* next = current->next();
     199     1555302 :       FreeSegment(current);
     200             :       current = next;
     201             :     }
     202    15978066 :     unused_segments_heads_[power] = nullptr;
     203             :   }
     204     2663011 : }
     205             : 
     206             : }  // namespace internal
     207      178779 : }  // namespace v8

Generated by: LCOV version 1.10