1 // Copyright 2020 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 #ifndef V8_HEAP_ALLOCATION_STATS_H_ 6 #define V8_HEAP_ALLOCATION_STATS_H_ 7 8 #include <atomic> 9 #include <unordered_map> 10 11 #include "src/base/macros.h" 12 #include "src/heap/basic-memory-chunk.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // An abstraction of the accounting statistics of a page-structured space. 18 // 19 // The stats are only set by functions that ensure they stay balanced. These 20 // functions increase or decrease one of the non-capacity stats in conjunction 21 // with capacity, or else they always balance increases and decreases to the 22 // non-capacity stats. 23 class AllocationStats { 24 public: AllocationStats()25 AllocationStats() { Clear(); } 26 27 AllocationStats& operator=(const AllocationStats& stats) V8_NOEXCEPT { 28 capacity_ = stats.capacity_.load(); 29 max_capacity_ = stats.max_capacity_; 30 size_.store(stats.size_); 31 #ifdef DEBUG 32 allocated_on_page_ = stats.allocated_on_page_; 33 #endif 34 return *this; 35 } 36 37 // Zero out all the allocation statistics (i.e., no capacity). Clear()38 void Clear() { 39 capacity_ = 0; 40 max_capacity_ = 0; 41 ClearSize(); 42 } 43 ClearSize()44 void ClearSize() { 45 size_ = 0; 46 #ifdef DEBUG 47 allocated_on_page_.clear(); 48 #endif 49 } 50 51 // Accessors for the allocation statistics. Capacity()52 size_t Capacity() const { return capacity_; } MaxCapacity()53 size_t MaxCapacity() const { return max_capacity_; } Size()54 size_t Size() const { return size_; } 55 #ifdef DEBUG AllocatedOnPage(const BasicMemoryChunk * page)56 size_t AllocatedOnPage(const BasicMemoryChunk* page) const { 57 return allocated_on_page_.at(page); 58 } 59 #endif 60 IncreaseAllocatedBytes(size_t bytes,const BasicMemoryChunk * page)61 void IncreaseAllocatedBytes(size_t bytes, const BasicMemoryChunk* page) { 62 #ifdef DEBUG 63 size_t size = size_; 64 DCHECK_GE(size + bytes, size); 65 #endif 66 size_.fetch_add(bytes); 67 #ifdef DEBUG 68 allocated_on_page_[page] += bytes; 69 #endif 70 } 71 DecreaseAllocatedBytes(size_t bytes,const BasicMemoryChunk * page)72 void DecreaseAllocatedBytes(size_t bytes, const BasicMemoryChunk* page) { 73 DCHECK_GE(size_, bytes); 74 size_.fetch_sub(bytes); 75 #ifdef DEBUG 76 DCHECK_GE(allocated_on_page_[page], bytes); 77 allocated_on_page_[page] -= bytes; 78 #endif 79 } 80 DecreaseCapacity(size_t bytes)81 void DecreaseCapacity(size_t bytes) { 82 DCHECK_GE(capacity_, bytes); 83 DCHECK_GE(capacity_ - bytes, size_); 84 capacity_ -= bytes; 85 } 86 IncreaseCapacity(size_t bytes)87 void IncreaseCapacity(size_t bytes) { 88 DCHECK_GE(capacity_ + bytes, capacity_); 89 capacity_ += bytes; 90 if (capacity_ > max_capacity_) { 91 max_capacity_ = capacity_; 92 } 93 } 94 95 private: 96 // |capacity_|: The number of object-area bytes (i.e., not including page 97 // bookkeeping structures) currently in the space. 98 // During evacuation capacity of the main spaces is accessed from multiple 99 // threads to check the old generation hard limit. 100 std::atomic<size_t> capacity_; 101 102 // |max_capacity_|: The maximum capacity ever observed. 103 size_t max_capacity_; 104 105 // |size_|: The number of allocated bytes. 106 std::atomic<size_t> size_; 107 108 #ifdef DEBUG 109 std::unordered_map<const BasicMemoryChunk*, size_t, BasicMemoryChunk::Hasher> 110 allocated_on_page_; 111 #endif 112 }; 113 114 } // namespace internal 115 } // namespace v8 116 117 #endif // V8_HEAP_ALLOCATION_STATS_H_ 118