blob: a024b956e0edc0dcf4ede6f1752b0d0da1ae9524 [file] [log] [blame]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_ALLOCATION_STATS_H_
#define V8_HEAP_ALLOCATION_STATS_H_
#include <atomic>
#include <unordered_map>
#include "src/base/macros.h"
#include "src/heap/basic-memory-chunk.h"
namespace v8 {
namespace internal {
// An abstraction of the accounting statistics of a page-structured space.
//
// The stats are only set by functions that ensure they stay balanced. These
// functions increase or decrease one of the non-capacity stats in conjunction
// with capacity, or else they always balance increases and decreases to the
// non-capacity stats.
class AllocationStats {
public:
AllocationStats() { Clear(); }
AllocationStats& operator=(const AllocationStats& stats) V8_NOEXCEPT {
capacity_ = stats.capacity_.load();
max_capacity_ = stats.max_capacity_;
size_.store(stats.size_);
#ifdef DEBUG
allocated_on_page_ = stats.allocated_on_page_;
#endif
return *this;
}
// Zero out all the allocation statistics (i.e., no capacity).
void Clear() {
capacity_ = 0;
max_capacity_ = 0;
ClearSize();
}
void ClearSize() {
size_ = 0;
#ifdef DEBUG
allocated_on_page_.clear();
#endif
}
// Accessors for the allocation statistics.
size_t Capacity() const { return capacity_; }
size_t MaxCapacity() const { return max_capacity_; }
size_t Size() const { return size_; }
#ifdef DEBUG
size_t AllocatedOnPage(const BasicMemoryChunk* page) const {
return allocated_on_page_.at(page);
}
#endif
void IncreaseAllocatedBytes(size_t bytes, const BasicMemoryChunk* page) {
#ifdef DEBUG
size_t size = size_;
DCHECK_GE(size + bytes, size);
#endif
size_.fetch_add(bytes);
#ifdef DEBUG
allocated_on_page_[page] += bytes;
#endif
}
void DecreaseAllocatedBytes(size_t bytes, const BasicMemoryChunk* page) {
DCHECK_GE(size_, bytes);
size_.fetch_sub(bytes);
#ifdef DEBUG
DCHECK_GE(allocated_on_page_[page], bytes);
allocated_on_page_[page] -= bytes;
#endif
}
void DecreaseCapacity(size_t bytes) {
DCHECK_GE(capacity_, bytes);
DCHECK_GE(capacity_ - bytes, size_);
capacity_ -= bytes;
}
void IncreaseCapacity(size_t bytes) {
DCHECK_GE(capacity_ + bytes, capacity_);
capacity_ += bytes;
if (capacity_ > max_capacity_) {
max_capacity_ = capacity_;
}
}
private:
// |capacity_|: The number of object-area bytes (i.e., not including page
// bookkeeping structures) currently in the space.
// During evacuation capacity of the main spaces is accessed from multiple
// threads to check the old generation hard limit.
std::atomic<size_t> capacity_;
// |max_capacity_|: The maximum capacity ever observed.
size_t max_capacity_;
// |size_|: The number of allocated bytes.
std::atomic<size_t> size_;
#ifdef DEBUG
std::unordered_map<const BasicMemoryChunk*, size_t, BasicMemoryChunk::Hasher>
allocated_on_page_;
#endif
};
} // namespace internal
} // namespace v8
#endif // V8_HEAP_ALLOCATION_STATS_H_