Implement committed physical memory stats for Linux.

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

BUG=v8:2191

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12625 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent fbcc4a40
...@@ -2766,6 +2766,7 @@ class V8EXPORT HeapStatistics { ...@@ -2766,6 +2766,7 @@ class V8EXPORT HeapStatistics {
HeapStatistics(); HeapStatistics();
size_t total_heap_size() { return total_heap_size_; } size_t total_heap_size() { return total_heap_size_; }
size_t total_heap_size_executable() { return total_heap_size_executable_; } 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 used_heap_size() { return used_heap_size_; }
size_t heap_size_limit() { return heap_size_limit_; } size_t heap_size_limit() { return heap_size_limit_; }
...@@ -2774,11 +2775,15 @@ class V8EXPORT HeapStatistics { ...@@ -2774,11 +2775,15 @@ class V8EXPORT HeapStatistics {
void set_total_heap_size_executable(size_t size) { void set_total_heap_size_executable(size_t size) {
total_heap_size_executable_ = 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_used_heap_size(size_t size) { used_heap_size_ = size; }
void set_heap_size_limit(size_t size) { heap_size_limit_ = size; } void set_heap_size_limit(size_t size) { heap_size_limit_ = size; }
size_t total_heap_size_; size_t total_heap_size_;
size_t total_heap_size_executable_; size_t total_heap_size_executable_;
size_t total_physical_size_;
size_t used_heap_size_; size_t used_heap_size_;
size_t heap_size_limit_; size_t heap_size_limit_;
......
...@@ -4306,6 +4306,7 @@ bool v8::V8::Dispose() { ...@@ -4306,6 +4306,7 @@ bool v8::V8::Dispose() {
HeapStatistics::HeapStatistics(): total_heap_size_(0), HeapStatistics::HeapStatistics(): total_heap_size_(0),
total_heap_size_executable_(0), total_heap_size_executable_(0),
total_physical_size_(0),
used_heap_size_(0), used_heap_size_(0),
heap_size_limit_(0) { } heap_size_limit_(0) { }
...@@ -4315,6 +4316,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { ...@@ -4315,6 +4316,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
// Isolate is unitialized thus heap is not configured yet. // Isolate is unitialized thus heap is not configured yet.
heap_statistics->set_total_heap_size(0); heap_statistics->set_total_heap_size(0);
heap_statistics->set_total_heap_size_executable(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_used_heap_size(0);
heap_statistics->set_heap_size_limit(0); heap_statistics->set_heap_size_limit(0);
return; return;
...@@ -4324,6 +4326,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { ...@@ -4324,6 +4326,7 @@ void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
heap_statistics->set_total_heap_size(heap->CommittedMemory()); heap_statistics->set_total_heap_size(heap->CommittedMemory());
heap_statistics->set_total_heap_size_executable( heap_statistics->set_total_heap_size_executable(
heap->CommittedMemoryExecutable()); heap->CommittedMemoryExecutable());
heap_statistics->set_total_physical_size(heap->CommittedPhysicalMemory());
heap_statistics->set_used_heap_size(heap->SizeOfObjects()); heap_statistics->set_used_heap_size(heap->SizeOfObjects());
heap_statistics->set_heap_size_limit(heap->MaxReserved()); heap_statistics->set_heap_size_limit(heap->MaxReserved());
} }
......
...@@ -211,6 +211,20 @@ intptr_t Heap::CommittedMemory() { ...@@ -211,6 +211,20 @@ intptr_t Heap::CommittedMemory() {
lo_space_->Size(); 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() { intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetUp()) return 0; if (!HasBeenSetUp()) return 0;
......
...@@ -486,6 +486,9 @@ class Heap { ...@@ -486,6 +486,9 @@ class Heap {
// Returns the amount of executable memory currently committed for the heap. // Returns the amount of executable memory currently committed for the heap.
intptr_t CommittedMemoryExecutable(); 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. // Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires // Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead. // all available bytes. Check MaxHeapObjectSize() instead.
......
...@@ -359,6 +359,13 @@ bool VirtualMemory::Guard(void* address) { ...@@ -359,6 +359,13 @@ bool VirtualMemory::Guard(void* address) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() : thread_(kNoThread) {} PlatformData() : thread_(kNoThread) {}
......
...@@ -456,6 +456,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { ...@@ -456,6 +456,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
pthread_t thread_; // Thread handle for pthread. pthread_t thread_; // Thread handle for pthread.
......
...@@ -701,6 +701,24 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { ...@@ -701,6 +701,24 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
const size_t page_size = sysconf(_SC_PAGESIZE);
base = reinterpret_cast<void*>(
reinterpret_cast<intptr_t>(base) & ~(page_size - 1));
const size_t pages = (size + page_size - 1) / page_size;
ScopedVector<unsigned char> buffer(pages);
int result = mincore(base, size, buffer.start());
if (result) return false;
int resident_pages = 0;
for (unsigned i = 0; i < pages; ++i) {
resident_pages += buffer[i] & 1;
}
*physical = resident_pages * page_size;
return true;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() : thread_(kNoThread) {} PlatformData() : thread_(kNoThread) {}
......
...@@ -471,6 +471,13 @@ bool VirtualMemory::ReleaseRegion(void* address, size_t size) { ...@@ -471,6 +471,13 @@ bool VirtualMemory::ReleaseRegion(void* address, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() : thread_(kNoThread) {} PlatformData() : thread_(kNoThread) {}
......
...@@ -335,6 +335,13 @@ bool VirtualMemory::Guard(void* address) { ...@@ -335,6 +335,13 @@ bool VirtualMemory::Guard(void* address) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() { PlatformData() {
......
...@@ -504,6 +504,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { ...@@ -504,6 +504,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() : thread_(kNoThread) {} PlatformData() : thread_(kNoThread) {}
......
...@@ -448,6 +448,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { ...@@ -448,6 +448,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
class Thread::PlatformData : public Malloced { class Thread::PlatformData : public Malloced {
public: public:
PlatformData() : thread_(kNoThread) { } PlatformData() : thread_(kNoThread) { }
......
...@@ -1551,6 +1551,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) { ...@@ -1551,6 +1551,13 @@ bool VirtualMemory::ReleaseRegion(void* base, size_t size) {
} }
bool VirtualMemory::CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical) {
// TODO(alph): implement for the platform.
return false;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Win32 thread support. // Win32 thread support.
......
...@@ -429,6 +429,14 @@ class VirtualMemory { ...@@ -429,6 +429,14 @@ class VirtualMemory {
// and the same size it was reserved with. // and the same size it was reserved with.
static bool ReleaseRegion(void* base, size_t size); static bool ReleaseRegion(void* base, size_t size);
// Returns the size of committed memory which is currently resident
// in the physical memory for the region specified with base and size
// arguments.
// On success stores the committed physical memory size at the location
// pointed by the last argument and returns true. Returns false on failure.
static bool CommittedPhysicalSizeInRegion(
void* base, size_t size, size_t* physical);
private: private:
void* address_; // Start address of the virtual memory. void* address_; // Start address of the virtual memory.
size_t size_; // Size of the virtual memory. size_t size_; // Size of the virtual memory.
......
...@@ -488,6 +488,18 @@ void MemoryChunk::Unlink() { ...@@ -488,6 +488,18 @@ void MemoryChunk::Unlink() {
} }
size_t MemoryChunk::CommittedPhysicalMemory() {
size_t physical;
size_t size = area_size();
if (VirtualMemory::CommittedPhysicalSizeInRegion(
area_start_, size, &physical)) {
return physical;
} else {
return size;
}
}
MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size,
Executability executable, Executability executable,
Space* owner) { Space* owner) {
...@@ -820,6 +832,16 @@ void PagedSpace::TearDown() { ...@@ -820,6 +832,16 @@ void PagedSpace::TearDown() {
} }
size_t PagedSpace::CommittedPhysicalMemory() {
size_t size = 0;
PageIterator it(this);
while (it.has_next()) {
size += it.next()->CommittedPhysicalMemory();
}
return size;
}
MaybeObject* PagedSpace::FindObject(Address addr) { MaybeObject* PagedSpace::FindObject(Address addr) {
// Note: this function can only be called on precisely swept spaces. // Note: this function can only be called on precisely swept spaces.
ASSERT(!heap()->mark_compact_collector()->in_use()); ASSERT(!heap()->mark_compact_collector()->in_use());
...@@ -1385,6 +1407,17 @@ bool SemiSpace::Uncommit() { ...@@ -1385,6 +1407,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) { bool SemiSpace::GrowTo(int new_capacity) {
if (!is_committed()) { if (!is_committed()) {
if (!Commit()) return false; if (!Commit()) return false;
...@@ -2689,6 +2722,17 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size, ...@@ -2689,6 +2722,17 @@ MaybeObject* LargeObjectSpace::AllocateRaw(int object_size,
} }
size_t LargeObjectSpace::CommittedPhysicalMemory() {
size_t size = 0;
LargePage* current = first_page_;
while (current != NULL) {
size += current->CommittedPhysicalMemory();
current = current->next_page();
}
return size;
}
// GC support // GC support
MaybeObject* LargeObjectSpace::FindObject(Address a) { MaybeObject* LargeObjectSpace::FindObject(Address a) {
LargePage* page = FindPage(a); LargePage* page = FindPage(a);
......
...@@ -653,6 +653,8 @@ class MemoryChunk { ...@@ -653,6 +653,8 @@ class MemoryChunk {
return static_cast<int>(area_end() - area_start()); return static_cast<int>(area_end() - area_start());
} }
size_t CommittedPhysicalMemory();
protected: protected:
MemoryChunk* next_chunk_; MemoryChunk* next_chunk_;
MemoryChunk* prev_chunk_; MemoryChunk* prev_chunk_;
...@@ -1528,6 +1530,9 @@ class PagedSpace : public Space { ...@@ -1528,6 +1530,9 @@ class PagedSpace : public Space {
// spaces this equals the capacity. // spaces this equals the capacity.
intptr_t CommittedMemory() { return Capacity(); } intptr_t CommittedMemory() { return Capacity(); }
// Total amount of physical memory committed for this space.
size_t CommittedPhysicalMemory();
// Sets the capacity, the available space and the wasted space to zero. // Sets the capacity, the available space and the wasted space to zero.
// The stats are rebuilt during sweeping by adding each page to the // The stats are rebuilt during sweeping by adding each page to the
// capacity and the size when it is encountered. As free spaces are // capacity and the size when it is encountered. As free spaces are
...@@ -1994,6 +1999,8 @@ class SemiSpace : public Space { ...@@ -1994,6 +1999,8 @@ class SemiSpace : public Space {
static void Swap(SemiSpace* from, SemiSpace* to); static void Swap(SemiSpace* from, SemiSpace* to);
size_t CommittedPhysicalMemory();
private: private:
// Flips the semispace between being from-space and to-space. // Flips the semispace between being from-space and to-space.
// Copies the flags into the masked positions on all pages in the space. // Copies the flags into the masked positions on all pages in the space.
...@@ -2191,6 +2198,12 @@ class NewSpace : public Space { ...@@ -2191,6 +2198,12 @@ class NewSpace : public Space {
return Capacity(); return Capacity();
} }
size_t CommittedPhysicalMemory() {
return to_space_.CommittedPhysicalMemory()
+ (from_space_.is_committed() ? from_space_.CommittedPhysicalMemory()
: 0);
}
// Return the available bytes without growing. // Return the available bytes without growing.
intptr_t Available() { intptr_t Available() {
return Capacity() - Size(); return Capacity() - Size();
...@@ -2558,6 +2571,8 @@ class LargeObjectSpace : public Space { ...@@ -2558,6 +2571,8 @@ class LargeObjectSpace : public Space {
return Size(); return Size();
} }
size_t CommittedPhysicalMemory();
int PageCount() { int PageCount() {
return page_count_; 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