Implement committed physical memory stats for Linux.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 27 Sep 2012 13:27:50 +0000 (13:27 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 27 Sep 2012 13:27:50 +0000 (13:27 +0000)
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

15 files changed:
include/v8.h
src/api.cc
src/heap.cc
src/heap.h
src/platform-cygwin.cc
src/platform-freebsd.cc
src/platform-linux.cc
src/platform-macos.cc
src/platform-nullos.cc
src/platform-openbsd.cc
src/platform-solaris.cc
src/platform-win32.cc
src/platform.h
src/spaces.cc
src/spaces.h

index 92d928b..72558d0 100644 (file)
@@ -2766,6 +2766,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_; }
 
@@ -2774,11 +2775,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_;
 
index dcadf52..74e0a0b 100644 (file)
@@ -4306,6 +4306,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) { }
 
@@ -4315,6 +4316,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;
@@ -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_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());
 }
index 1336027..97524a4 100644 (file)
@@ -211,6 +211,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;
 
index 46ec6cf..c759792 100644 (file)
@@ -486,6 +486,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.
index 089ea38..6c59ecf 100644 (file)
@@ -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 {
  public:
   PlatformData() : thread_(kNoThread) {}
index 511759c..7d41f37 100644 (file)
@@ -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 {
  public:
   pthread_t thread_;  // Thread handle for pthread.
index 606d102..f934da1 100644 (file)
@@ -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 {
  public:
   PlatformData() : thread_(kNoThread) {}
index a216f6e..9b14d2f 100644 (file)
@@ -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 {
  public:
   PlatformData() : thread_(kNoThread) {}
index 679ef8e..0b2929d 100644 (file)
@@ -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 {
  public:
   PlatformData() {
index 408d4dc..558361d 100644 (file)
@@ -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 {
  public:
   PlatformData() : thread_(kNoThread) {}
index 4248ea2..2ab3fee 100644 (file)
@@ -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 {
  public:
   PlatformData() : thread_(kNoThread) {  }
index 49463be..f10b46e 100644 (file)
@@ -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.
 
index f50e713..5e3bdc7 100644 (file)
@@ -429,6 +429,14 @@ class VirtualMemory {
   // and the same size it was reserved with.
   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:
   void* address_;  // Start address of the virtual memory.
   size_t size_;  // Size of the virtual memory.
index 62d8263..d286002 100644 (file)
@@ -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,
                                             Executability executable,
                                             Space* owner) {
@@ -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) {
   // Note: this function can only be called on precisely swept spaces.
   ASSERT(!heap()->mark_compact_collector()->in_use());
@@ -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) {
   if (!is_committed()) {
     if (!Commit()) return false;
@@ -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
 MaybeObject* LargeObjectSpace::FindObject(Address a) {
   LargePage* page = FindPage(a);
index 97bcaa5..4ccd788 100644 (file)
@@ -653,6 +653,8 @@ class MemoryChunk {
     return static_cast<int>(area_end() - area_start());
   }
 
+  size_t CommittedPhysicalMemory();
+
  protected:
   MemoryChunk* next_chunk_;
   MemoryChunk* prev_chunk_;
@@ -1528,6 +1530,9 @@ class PagedSpace : public Space {
   // spaces this equals the 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.
   // The stats are rebuilt during sweeping by adding each page to the
   // capacity and the size when it is encountered.  As free spaces are
@@ -1994,6 +1999,8 @@ class SemiSpace : public Space {
 
   static void Swap(SemiSpace* from, SemiSpace* to);
 
+  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.
@@ -2191,6 +2198,12 @@ class NewSpace : public Space {
     return Capacity();
   }
 
+  size_t CommittedPhysicalMemory() {
+    return to_space_.CommittedPhysicalMemory()
+        + (from_space_.is_committed() ? from_space_.CommittedPhysicalMemory()
+                                      : 0);
+  }
+
   // Return the available bytes without growing.
   intptr_t Available() {
     return Capacity() - Size();
@@ -2558,6 +2571,8 @@ class LargeObjectSpace : public Space {
     return Size();
   }
 
+  size_t CommittedPhysicalMemory();
+
   int PageCount() {
     return page_count_;
   }