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: 2019-01-20 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     3271360 : 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     3271361 :             nullptr);
      24     3271361 :   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     3271361 : }
      28             : 
      29     3226838 : AccountingAllocator::~AccountingAllocator() { ClearPool(); }
      30             : 
      31          90 : void AccountingAllocator::MemoryPressureNotification(
      32             :     MemoryPressureLevel level) {
      33             :   memory_pressure_level_.SetValue(level);
      34             : 
      35          90 :   if (level != MemoryPressureLevel::kNone) {
      36          85 :     ClearPool();
      37             :   }
      38          90 : }
      39             : 
      40       62590 : 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       62590 :   size_t fits_fully = max_pool_size / full_size;
      45             : 
      46       62590 :   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       62590 :   size_t total_size = fits_fully * full_size;
      62             : 
      63      438130 :   for (size_t power = 0; power < kNumberBuckets; ++power) {
      64      375540 :     if (total_size + (size_t(1) << (power + kMinSegmentSizePower)) <=
      65             :         max_pool_size) {
      66       28779 :       unused_segments_max_sizes_[power] = fits_fully + 1;
      67       28779 :       total_size += size_t(1) << power;
      68             :     } else {
      69      346761 :       unused_segments_max_sizes_[power] = fits_fully;
      70             :     }
      71             :   }
      72       62590 : }
      73             : 
      74    62639144 : Segment* AccountingAllocator::GetSegment(size_t bytes) {
      75    62639144 :   Segment* result = GetSegmentFromPool(bytes);
      76    62649556 :   if (result == nullptr) {
      77    29297024 :     result = AllocateSegment(bytes);
      78    29297092 :     if (result != nullptr) {
      79             :       result->Initialize(bytes);
      80             :     }
      81             :   }
      82             : 
      83    62649624 :   return result;
      84             : }
      85             : 
      86    29297013 : Segment* AccountingAllocator::AllocateSegment(size_t bytes) {
      87    29297013 :   void* memory = AllocWithRetry(bytes);
      88    29297087 :   if (memory != nullptr) {
      89             :     base::AtomicWord current =
      90    29297091 :         base::Relaxed_AtomicIncrement(&current_memory_usage_, bytes);
      91    29297091 :     base::AtomicWord max = base::Relaxed_Load(&max_memory_usage_);
      92    63824356 :     while (current > max) {
      93             :       max = base::Relaxed_CompareAndSwap(&max_memory_usage_, max, current);
      94             :     }
      95             :   }
      96    29297087 :   return reinterpret_cast<Segment*>(memory);
      97             : }
      98             : 
      99    62627618 : void AccountingAllocator::ReturnSegment(Segment* segment) {
     100    62627618 :   segment->ZapContents();
     101             : 
     102    62626684 :   if (memory_pressure_level_.Value() != MemoryPressureLevel::kNone) {
     103        2276 :     FreeSegment(segment);
     104    62624408 :   } else if (!AddSegmentToPool(segment)) {
     105    27375862 :     FreeSegment(segment);
     106             :   }
     107    62634641 : }
     108             : 
     109    29224918 : void AccountingAllocator::FreeSegment(Segment* memory) {
     110             :   base::Relaxed_AtomicIncrement(&current_memory_usage_,
     111    29224918 :                                 -static_cast<base::AtomicWord>(memory->size()));
     112    29224918 :   memory->ZapHeader();
     113    29224934 :   free(memory);
     114    29224934 : }
     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    62639136 : Segment* AccountingAllocator::GetSegmentFromPool(size_t requested_size) {
     129    62639136 :   if (requested_size > (1 << kMaxSegmentSizePower)) {
     130             :     return nullptr;
     131             :   }
     132             : 
     133             :   size_t power = kMinSegmentSizePower;
     134    15299245 :   while (requested_size > (static_cast<size_t>(1) << power)) power++;
     135             : 
     136             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     137    62511928 :   power -= kMinSegmentSizePower;
     138             : 
     139    66705862 :   Segment* segment;
     140             :   {
     141    62511928 :     base::MutexGuard lock_guard(&unused_segments_mutex_);
     142             : 
     143    62522293 :     segment = unused_segments_heads_[power];
     144             : 
     145    62522293 :     if (segment != nullptr) {
     146    33352931 :       unused_segments_heads_[power] = segment->next();
     147             :       segment->set_next(nullptr);
     148             : 
     149    33352931 :       unused_segments_sizes_[power]--;
     150             :       base::Relaxed_AtomicIncrement(
     151    33352931 :           &current_pool_size_, -static_cast<base::AtomicWord>(segment->size()));
     152             :     }
     153             :   }
     154             : 
     155             :   if (segment) {
     156             :     DCHECK_GE(segment->size(), requested_size);
     157             :   }
     158    62522018 :   return segment;
     159             : }
     160             : 
     161    62623881 : bool AccountingAllocator::AddSegmentToPool(Segment* segment) {
     162             :   size_t size = segment->size();
     163             : 
     164    62623881 :   if (size >= (1 << (kMaxSegmentSizePower + 1))) return false;
     165             : 
     166    62544926 :   if (size < (1 << kMinSegmentSizePower)) return false;
     167             : 
     168             :   size_t power = kMaxSegmentSizePower;
     169             : 
     170   302812430 :   while (size < (static_cast<size_t>(1) << power)) power--;
     171             : 
     172             :   DCHECK_GE(power, kMinSegmentSizePower + 0);
     173    62545314 :   power -= kMinSegmentSizePower;
     174             : 
     175             :   {
     176    62545314 :     base::MutexGuard lock_guard(&unused_segments_mutex_);
     177             : 
     178    62553440 :     if (unused_segments_sizes_[power] >= unused_segments_max_sizes_[power]) {
     179             :       return false;
     180             :     }
     181             : 
     182    35256790 :     segment->set_next(unused_segments_heads_[power]);
     183    35256790 :     unused_segments_heads_[power] = segment;
     184    35256790 :     base::Relaxed_AtomicIncrement(&current_pool_size_, size);
     185    35256790 :     unused_segments_sizes_[power]++;
     186             :   }
     187             : 
     188             :   return true;
     189             : }
     190             : 
     191     3226923 : void AccountingAllocator::ClearPool() {
     192     3226923 :   base::MutexGuard lock_guard(&unused_segments_mutex_);
     193             : 
     194    22588468 :   for (size_t power = 0; power <= kMaxSegmentSizePower - kMinSegmentSizePower;
     195             :        power++) {
     196    21208312 :     Segment* current = unused_segments_heads_[power];
     197    40569856 :     while (current) {
     198             :       Segment* next = current->next();
     199     1846768 :       FreeSegment(current);
     200             :       current = next;
     201             :     }
     202    19361544 :     unused_segments_heads_[power] = nullptr;
     203             :   }
     204     3226924 : }
     205             : 
     206             : }  // namespace internal
     207      183867 : }  // namespace v8

Generated by: LCOV version 1.10