Implement committed physical memory stats for Linux.

The patch introduces CommittedPhysicalMemory function to
the Heap class that reports committed *physical* memory acquired
for the heap from the OS.
It is important because some OSes may defer actual committment on e.g.
first access to the region.
So reporting just plain committed size led to various weird artifacts
like showing V8 allocated memory higher than the whole process
private size.

BUG=v8:2191

Review URL: https://codereview.chromium.org/11066118
Patch from Alexei Filippov <alph@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12793 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 3c864d3e
......@@ -2773,6 +2773,7 @@ class V8EXPORT HeapStatistics {
HeapStatistics();
size_t total_heap_size() { return total_heap_size_; }
size_t total_heap_size_executable() { return total_heap_size_executable_; }
size_t total_physical_size() { return total_physical_size_; }
size_t used_heap_size() { return used_heap_size_; }
size_t heap_size_limit() { return heap_size_limit_; }
......@@ -2781,11 +2782,15 @@ class V8EXPORT HeapStatistics {
void set_total_heap_size_executable(size_t size) {
total_heap_size_executable_ = size;
}
void set_total_physical_size(size_t size) {
total_physical_size_ = size;
}
void set_used_heap_size(size_t size) { used_heap_size_ = size; }
void set_heap_size_limit(size_t size) { heap_size_limit_ = size; }
size_t total_heap_size_;
size_t total_heap_size_executable_;
size_t total_physical_size_;
size_t used_heap_size_;
size_t heap_size_limit_;
......
......@@ -4314,6 +4314,7 @@ bool v8::V8::Dispose() {
HeapStatistics::HeapStatistics(): total_heap_size_(0),
total_heap_size_executable_(0),
total_physical_size_(0),
used_heap_size_(0),
heap_size_limit_(0) { }
......@@ -4323,6 +4324,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
// Isolate is unitialized thus heap is not configured yet.
heap_statistics->set_total_heap_size(0);
heap_statistics->set_total_heap_size_executable(0);
heap_statistics->set_total_physical_size(0);
heap_statistics->set_used_heap_size(0);
heap_statistics->set_heap_size_limit(0);
return;
......@@ -4332,6 +4334,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
heap_statistics->set_total_heap_size(heap->CommittedMemory());
heap_statistics->set_total_heap_size_executable(
heap->CommittedMemoryExecutable());
heap_statistics->set_total_physical_size(heap->CommittedPhysicalMemory());
heap_statistics->set_used_heap_size(heap->SizeOfObjects());
heap_statistics->set_heap_size_limit(heap->MaxReserved());
}
......
......@@ -212,6 +212,20 @@ intptr_t Heap::CommittedMemory() {
lo_space_->Size();
}
size_t Heap::CommittedPhysicalMemory() {
if (!HasBeenSetUp()) return 0;
return new_space_.CommittedPhysicalMemory() +
old_pointer_space_->CommittedPhysicalMemory() +
old_data_space_->CommittedPhysicalMemory() +
code_space_->CommittedPhysicalMemory() +
map_space_->CommittedPhysicalMemory() +
cell_space_->CommittedPhysicalMemory() +
lo_space_->CommittedPhysicalMemory();
}
intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetUp()) return 0;
......
......@@ -487,6 +487,9 @@ class Heap {
// Returns the amount of executable memory currently committed for the heap.
intptr_t CommittedMemoryExecutable();
// Returns the amount of phyical memory currently committed for the heap.
size_t CommittedPhysicalMemory();
// Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead.
......
......@@ -359,6 +359,12 @@ bool VirtualMemory::Guard(void* address) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() : thread_(kNoThread) {}
......
......@@ -456,6 +456,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced {
public:
pthread_t thread_; // Thread handle for pthread.
......
......@@ -722,6 +722,11 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
return true;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() : thread_(kNoThread) {}
......
......@@ -471,6 +471,11 @@ bool VirtualMemory::ReleaseRegion(void* address, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
return false;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() : thread_(kNoThread) {}
......
......@@ -340,6 +340,12 @@ bool VirtualMemory::Guard(void* address) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() {
......
......@@ -504,6 +504,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() : thread_(kNoThread) {}
......
......@@ -448,6 +448,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced {
public:
PlatformData() : thread_(kNoThread) { }
......
......@@ -1551,6 +1551,12 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
}
bool VirtualMemory::HasLazyCommits() {
// TODO(alph): implement for the platform.
return false;
}
// ----------------------------------------------------------------------------
// Win32 thread support.
......
......@@ -432,6 +432,11 @@ class VirtualMemory {
// and the same size it was reserved with.
static bool ReleaseRegion(void* base, size_t size);
// Returns true if OS performs lazy commits, i.e. the memory allocation call
// defers actual physical memory allocation till the first memory access.
// Otherwise returns false.
static bool HasLazyCommits();
private:
void* address_; // Start address of the virtual memory.
size_t size_; // Size of the virtual memory.
......
......@@ -214,6 +214,19 @@ MemoryChunk* MemoryChunk::FromAnyPointerAddress(Address addr) {
}
void MemoryChunk::UpdateHighWaterMark(Address mark) {
if (mark == NULL) return;
// Need to subtract one from the mark because when a chunk is full the
// top points to the next address after the chunk, which effectively belongs
// to another chunk. See the comment to Page::FromAllocationTop.
MemoryChunk* chunk = MemoryChunk::FromAddress(mark - 1);
int new_mark = static_cast<int>(mark - chunk->address());
if (new_mark > chunk->high_water_mark_) {
chunk->high_water_mark_ = new_mark;
}
}
PointerChunkIterator::PointerChunkIterator(Heap* heap)
: state_(kOldPointerState),
old_pointer_iterator_(heap->old_pointer_space()),
......
......@@ -448,6 +448,7 @@ MemoryChunk* MemoryChunk::Initialize(Heap* heap,
chunk->slots_buffer_ = NULL;
chunk->skip_list_ = NULL;
chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity;
chunk->high_water_mark_ = area_start - base;
chunk->ResetLiveBytes();
Bitmap::Clear(chunk);
chunk->initialize_scan_on_scavenge(false);
......@@ -824,6 +825,18 @@ void PagedSpace::TearDown() {
}
size_t PagedSpace::CommittedPhysicalMemory() {
if (!VirtualMemory::HasLazyCommits()) return CommittedMemory();
MemoryChunk::UpdateHighWaterMark(allocation_info_.top);
size_t size = 0;
PageIterator it(this);
while (it.has_next()) {
size += it.next()->CommittedPhysicalMemory();
}
return size;
}
MaybeObject* PagedSpace::FindObject(Address addr) {
// Note: this function can only be called on precisely swept spaces.
ASSERT(!heap()->mark_compact_collector()->in_use());
......@@ -1175,6 +1188,7 @@ void NewSpace::Shrink() {
void NewSpace::UpdateAllocationInfo() {
MemoryChunk::UpdateHighWaterMark(allocation_info_.top);
allocation_info_.top = to_space_.page_low();
allocation_info_.limit = to_space_.page_high();
......@@ -1387,6 +1401,17 @@ bool SemiSpace::Uncommit() {
}
size_t SemiSpace::CommittedPhysicalMemory() {
if (!is_committed()) return 0;
size_t size = 0;
NewSpacePageIterator it(this);
while (it.has_next()) {
size += it.next()->CommittedPhysicalMemory();
}
return size;
}
bool SemiSpace::GrowTo(int new_capacity) {
if (!is_committed()) {
if (!Commit()) return false;
......@@ -1821,6 +1846,17 @@ void NewSpace::RecordPromotion(HeapObject* obj) {
promoted_histogram_[type].increment_bytes(obj->Size());
}
size_t NewSpace::CommittedPhysicalMemory() {
if (!VirtualMemory::HasLazyCommits()) return CommittedMemory();
MemoryChunk::UpdateHighWaterMark(allocation_info_.top);
size_t size = to_space_.CommittedPhysicalMemory();
if (from_space_.is_committed()) {
size += from_space_.CommittedPhysicalMemory();
}
return size;
}
// -----------------------------------------------------------------------------
// Free lists for old object spaces implementation
......@@ -2698,6 +2734,18 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size,
}
size_t LargeObjectSpace::CommittedPhysicalMemory() {
if (!VirtualMemory::HasLazyCommits()) return CommittedMemory();
size_t size = 0;
LargePage* current = first_page_;
while (current != NULL) {
size += current->CommittedPhysicalMemory();
current = current->next_page();
}
return size;
}
// GC support
MaybeObject* LargeObjectSpace::FindObject(Address a) {
LargePage* page = FindPage(a);
......
......@@ -504,7 +504,8 @@ class MemoryChunk {
static const size_t kWriteBarrierCounterOffset =
kSlotsBufferOffset + kPointerSize + kPointerSize;
static const size_t kHeaderSize = kWriteBarrierCounterOffset + kPointerSize;
static const size_t kHeaderSize =
kWriteBarrierCounterOffset + kPointerSize + kPointerSize;
static const int kBodyOffset =
CODE_POINTER_ALIGN(kHeaderSize + Bitmap::kSize);
......@@ -616,6 +617,13 @@ class MemoryChunk {
return static_cast<int>(area_end() - area_start());
}
// Approximate amount of physical memory committed for this chunk.
size_t CommittedPhysicalMemory() {
return high_water_mark_;
}
static inline void UpdateHighWaterMark(Address mark);
protected:
MemoryChunk* next_chunk_;
MemoryChunk* prev_chunk_;
......@@ -641,6 +649,9 @@ class MemoryChunk {
SlotsBuffer* slots_buffer_;
SkipList* skip_list_;
intptr_t write_barrier_counter_;
// Assuming the initial allocation on a page is sequential,
// count highest number of bytes ever allocated on the page.
int high_water_mark_;
static MemoryChunk* Initialize(Heap* heap,
Address base,
......@@ -1490,6 +1501,9 @@ class PagedSpace : public Space {
// spaces this equals the capacity.
intptr_t CommittedMemory() { return Capacity(); }
// Approximate amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
// Sets the capacity, the available space and the wasted space to zero.
// The stats are rebuilt during sweeping by adding each page to the
// capacity and the size when it is encountered. As free spaces are
......@@ -1550,6 +1564,7 @@ class PagedSpace : public Space {
void SetTop(Address top, Address limit) {
ASSERT(top == limit ||
Page::FromAddress(top) == Page::FromAddress(limit - 1));
MemoryChunk::UpdateHighWaterMark(allocation_info_.top);
allocation_info_.top = top;
allocation_info_.limit = limit;
}
......@@ -1961,6 +1976,9 @@ class SemiSpace : public Space {
static void Swap(SemiSpace* from, SemiSpace* to);
// Approximate amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
private:
// Flips the semispace between being from-space and to-space.
// Copies the flags into the masked positions on all pages in the space.
......@@ -2158,6 +2176,9 @@ class NewSpace : public Space {
return Capacity();
}
// Approximate amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
// Return the available bytes without growing.
intptr_t Available() {
return Capacity() - Size();
......@@ -2524,6 +2545,9 @@ class LargeObjectSpace : public Space {
return Size();
}
// Approximate amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
int PageCount() {
return page_count_;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment