LCOV - code coverage report
Current view: top level - src/zone - accounting-allocator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 80 82 97.6 %
Date: 2017-04-26 Functions: 14 15 93.3 %

          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             : namespace v8 {
      14             : namespace internal {
      15             : 
      16      631991 : AccountingAllocator::AccountingAllocator() : unused_segments_mutex_() {
      17             :   static const size_t kDefaultBucketMaxSize = 5;
      18             : 
      19             :   memory_pressure_level_.SetValue(MemoryPressureLevel::kNone);
      20             :   std::fill(unused_segments_heads_, unused_segments_heads_ + kNumberBuckets,
      21      631991 :             nullptr);
      22      631991 :   std::fill(unused_segments_sizes_, unused_segments_sizes_ + kNumberBuckets, 0);
      23             :   std::fill(unused_segments_max_sizes_,
      24             :             unused_segments_max_sizes_ + kNumberBuckets, kDefaultBucketMaxSize);
      25      631991 : }
      26             : 
      27      614976 : AccountingAllocator::~AccountingAllocator() { ClearPool(); }
      28             : 
      29          26 : void AccountingAllocator::MemoryPressureNotification(
      30             :     MemoryPressureLevel level) {
      31             :   memory_pressure_level_.SetValue(level);
      32             : 
      33          26 :   if (level != MemoryPressureLevel::kNone) {
      34          20 :     ClearPool();
      35             :   }
      36          26 : }
      37             : 
      38       60607 : void AccountingAllocator::ConfigureSegmentPool(const size_t max_pool_size) {
      39             :   // The sum of the bytes of one segment of each size.
      40             :   static const size_t full_size = (size_t(1) << (kMaxSegmentSizePower + 1)) -
      41             :                                   (size_t(1) << kMinSegmentSizePower);
      42       60607 :   size_t fits_fully = max_pool_size / full_size;
      43             : 
      44       60607 :   base::LockGuard<base::Mutex> lock_guard(&unused_segments_mutex_);
      45             : 
      46             :   // We assume few zones (less than 'fits_fully' many) to be active at the same
      47             :   // time. When zones grow regularly, they will keep requesting segments of
      48             :   // increasing size each time. Therefore we try to get as many segments with an
      49             :   // equal number of segments of each size as possible.
      50             :   // The remaining space is used to make more room for an 'incomplete set' of
      51             :   // segments beginning with the smaller ones.
      52             :   // This code will work best if the max_pool_size is a multiple of the
      53             :   // full_size. If max_pool_size is no sum of segment sizes the actual pool
      54             :   // size might be smaller then max_pool_size. Note that no actual memory gets
      55             :   // wasted though.
      56             :   // TODO(heimbuef): Determine better strategy generating a segment sizes
      57             :   // distribution that is closer to real/benchmark usecases and uses the given
      58             :   // max_pool_size more efficiently.
      59       60607 :   size_t total_size = fits_fully * full_size;
      60             : 
      61      424249 :   for (size_t power = 0; power < kNumberBuckets; ++power) {
      62      363642 :     if (total_size + (size_t(1) << (power + kMinSegmentSizePower)) <=
      63             :         max_pool_size) {
      64       28627 :       unused_segments_max_sizes_[power] = fits_fully + 1;
      65       28627 :       total_size += size_t(1) << power;
      66             :     } else {
      67      335015 :       unused_segments_max_sizes_[power] = fits_fully;
      68             :     }
      69             :   }
      70       60607 : }
      71             : 
      72    44982049 : Segment* AccountingAllocator::GetSegment(size_t bytes) {
      73    44982049 :   Segment* result = GetSegmentFromPool(bytes);
      74    44984321 :   if (result == nullptr) {
      75    20351754 :     result = AllocateSegment(bytes);
      76    20351484 :     if (result != nullptr) {
      77             :       result->Initialize(bytes);
      78             :     }
      79             :   }
      80             : 
      81    44984051 :   return result;
      82             : }
      83             : 
      84    20351754 : Segment* AccountingAllocator::AllocateSegment(size_t bytes) {
      85    20351754 :   void* memory = malloc(bytes);
      86    20351754 :   if (memory) {
      87             :     base::AtomicWord current =
      88    20351725 :         base::NoBarrier_AtomicIncrement(&current_memory_usage_, bytes);
      89    20351725 :     base::AtomicWord max = base::NoBarrier_Load(&max_memory_usage_);
      90    42984457 :     while (current > max) {
      91             :       max = base::NoBarrier_CompareAndSwap(&max_memory_usage_, max, current);
      92             :     }
      93             :   }
      94    20351754 :   return reinterpret_cast<Segment*>(memory);
      95             : }
      96             : 
      97    44964481 : void AccountingAllocator::ReturnSegment(Segment* segment) {
      98    44964481 :   segment->ZapContents();
      99             : 
     100    44964456 :   if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) {
     101         137 :     FreeSegment(segment);
     102    44964319 :   } else if (!AddSegmentToPool(segment)) {
     103    19754917 :     FreeSegment(segment);
     104             :   }
     105    44967182 : }
     106             : 
     107    20334010 : void AccountingAllocator::FreeSegment(Segment* memory) {
     108             :   base::NoBarrier_AtomicIncrement(
     109    20334010 :       &current_memory_usage_, -static_cast<base::AtomicWord>(memory->size()));
     110    20334010 :   memory->ZapHeader();
     111    20334054 :   free(memory);
     112    20334054 : }
     113             : 
     114           7 : size_t AccountingAllocator::GetCurrentMemoryUsage() const {
     115          14 :   return base::NoBarrier_Load(&current_memory_usage_);
     116             : }
     117             : 
     118           7 : size_t AccountingAllocator::GetMaxMemoryUsage() const {
     119          14 :   return base::NoBarrier_Load(&max_memory_usage_);
     120             : }
     121             : 
     122           0 : size_t AccountingAllocator::GetCurrentPoolSize() const {
     123           0 :   return base::NoBarrier_Load(&current_pool_size_);
     124             : }
     125             : 
     126    44982065 : Segment* AccountingAllocator::GetSegmentFromPool(size_t requested_size) {
     127    44982065 :   if (requested_size > (1 << kMaxSegmentSizePower)) {
     128             :     return nullptr;
     129             :   }
     130             : 
     131             :   size_t power = kMinSegmentSizePower;
     132    13994128 :   while (requested_size > (static_cast<size_t>(1) << power)) power++;
     133             : 
     134             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     135    44851366 :   power -= kMinSegmentSizePower;
     136             : 
     137    49265308 :   Segment* segment;
     138             :   {
     139    44851366 :     base::LockGuard<base::Mutex> lock_guard(&unused_segments_mutex_);
     140             : 
     141    44853663 :     segment = unused_segments_heads_[power];
     142             : 
     143    44853663 :     if (segment != nullptr) {
     144    24632654 :       unused_segments_heads_[power] = segment->next();
     145             :       segment->set_next(nullptr);
     146             : 
     147    24632654 :       unused_segments_sizes_[power]--;
     148             :       base::NoBarrier_AtomicIncrement(
     149    24632654 :           &current_pool_size_, -static_cast<base::AtomicWord>(segment->size()));
     150             :     }
     151             :   }
     152             : 
     153             :   if (segment) {
     154             :     DCHECK_GE(segment->size(), requested_size);
     155             :   }
     156    44853552 :   return segment;
     157             : }
     158             : 
     159    44964160 : bool AccountingAllocator::AddSegmentToPool(Segment* segment) {
     160             :   size_t size = segment->size();
     161             : 
     162    44964160 :   if (size >= (1 << (kMaxSegmentSizePower + 1))) return false;
     163             : 
     164    44911817 :   if (size < (1 << kMinSegmentSizePower)) return false;
     165             : 
     166             :   size_t power = kMaxSegmentSizePower;
     167             : 
     168   215886345 :   while (size < (static_cast<size_t>(1) << power)) power--;
     169             : 
     170             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     171    44911983 :   power -= kMinSegmentSizePower;
     172             : 
     173             :   {
     174    44911983 :     base::LockGuard<base::Mutex> lock_guard(&unused_segments_mutex_);
     175             : 
     176    44914820 :     if (unused_segments_sizes_[power] >= unused_segments_max_sizes_[power]) {
     177             :       return false;
     178             :     }
     179             : 
     180    25212232 :     segment->set_next(unused_segments_heads_[power]);
     181    25212232 :     unused_segments_heads_[power] = segment;
     182    25212232 :     base::NoBarrier_AtomicIncrement(&current_pool_size_, size);
     183    25212232 :     unused_segments_sizes_[power]++;
     184             :   }
     185             : 
     186    25212232 :   return true;
     187             : }
     188             : 
     189      614996 : void AccountingAllocator::ClearPool() {
     190      614996 :   base::LockGuard<base::Mutex> lock_guard(&unused_segments_mutex_);
     191             : 
     192     4304978 :   for (size_t power = 0; power <= kMaxSegmentSizePower - kMinSegmentSizePower;
     193             :        power++) {
     194     4268935 :     Segment* current = unused_segments_heads_[power];
     195     7958917 :     while (current) {
     196             :       Segment* next = current->next();
     197      578954 :       FreeSegment(current);
     198             :       current = next;
     199             :     }
     200     3689982 :     unused_segments_heads_[power] = nullptr;
     201             :   }
     202      614997 : }
     203             : 
     204             : }  // namespace internal
     205             : }  // namespace v8

Generated by: LCOV version 1.10