[heap] Separate ObjectStats out into its own class.
authormstarzinger <mstarzinger@chromium.org>
Wed, 2 Sep 2015 16:43:21 +0000 (09:43 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 2 Sep 2015 16:43:40 +0000 (16:43 +0000)
Note that this is only pulling out the bookkeeping side of things, the
marking visitor that actually records the statistics should also move
into the ObjectStats class. That will be done as a follow-up.

R=mlippautz@chromium.org

Review URL: https://codereview.chromium.org/1326793002

Cr-Commit-Position: refs/heads/master@{#30547}

BUILD.gn
src/api.cc
src/heap/heap.cc
src/heap/heap.h
src/heap/mark-compact.cc
src/heap/object-stats.cc [new file with mode: 0644]
src/heap/object-stats.h [new file with mode: 0644]
tools/gyp/v8.gyp

index 434bb65..9cf0cb1 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -970,6 +970,8 @@ source_set("v8_base") {
     "src/heap/mark-compact.h",
     "src/heap/memory-reducer.cc",
     "src/heap/memory-reducer.h",
+    "src/heap/object-stats.cc",
+    "src/heap/object-stats.h",
     "src/heap/objects-visiting-inl.h",
     "src/heap/objects-visiting.cc",
     "src/heap/objects-visiting.h",
index b703b0b..2cb41a0 100644 (file)
@@ -7252,22 +7252,25 @@ bool Isolate::GetHeapSpaceStatistics(HeapSpaceStatistics* space_statistics,
 
 
 size_t Isolate::NumberOfTrackedHeapObjectTypes() {
-  return i::Heap::OBJECT_STATS_COUNT;
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+  i::Heap* heap = isolate->heap();
+  return heap->NumberOfTrackedHeapObjectTypes();
 }
 
 
 bool Isolate::GetHeapObjectStatisticsAtLastGC(
     HeapObjectStatistics* object_statistics, size_t type_index) {
   if (!object_statistics) return false;
-  if (type_index >= i::Heap::OBJECT_STATS_COUNT) return false;
   if (!i::FLAG_track_gc_object_stats) return false;
 
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   i::Heap* heap = isolate->heap();
+  if (type_index >= heap->NumberOfTrackedHeapObjectTypes()) return false;
+
   const char* object_type;
   const char* object_sub_type;
-  size_t object_count = heap->object_count_last_gc(type_index);
-  size_t object_size = heap->object_size_last_gc(type_index);
+  size_t object_count = heap->ObjectCountAtLastGC(type_index);
+  size_t object_size = heap->ObjectSizeAtLastGC(type_index);
   if (!heap->GetObjectTypeName(type_index, &object_type, &object_sub_type)) {
     // There should be no objects counted when the type is unknown.
     DCHECK_EQ(object_count, 0U);
index faaa852..9c6a2a1 100644 (file)
@@ -23,6 +23,7 @@
 #include "src/heap/mark-compact-inl.h"
 #include "src/heap/mark-compact.h"
 #include "src/heap/memory-reducer.h"
+#include "src/heap/object-stats.h"
 #include "src/heap/objects-visiting-inl.h"
 #include "src/heap/objects-visiting.h"
 #include "src/heap/store-buffer.h"
@@ -122,6 +123,7 @@ Heap::Heap()
       store_buffer_(this),
       incremental_marking_(this),
       memory_reducer_(nullptr),
+      object_stats_(nullptr),
       full_codegen_bytes_generated_(0),
       crankshaft_codegen_bytes_generated_(0),
       new_space_allocation_counter_(0),
@@ -161,8 +163,6 @@ Heap::Heap()
   // Put a dummy entry in the remembered pages so we can find the list the
   // minidump even if there are no real unmapped pages.
   RememberUnmappedPage(NULL, false);
-
-  ClearObjectStats(true);
 }
 
 
@@ -5643,6 +5643,9 @@ bool Heap::SetUp() {
 
   memory_reducer_ = new MemoryReducer(this);
 
+  object_stats_ = new ObjectStats(this);
+  object_stats_->ClearObjectStats(true);
+
   LOG(isolate_, IntPtrTEvent("heap-capacity", Capacity()));
   LOG(isolate_, IntPtrTEvent("heap-available", Available()));
 
@@ -5753,6 +5756,9 @@ void Heap::TearDown() {
     memory_reducer_ = nullptr;
   }
 
+  delete object_stats_;
+  object_stats_ = nullptr;
+
   WaitUntilUnmappingOfFreeChunksCompleted();
 
   TearDownArrayBuffers();
@@ -6573,124 +6579,6 @@ void Heap::RememberUnmappedPage(Address page, bool compacted) {
 }
 
 
-void Heap::ClearObjectStats(bool clear_last_time_stats) {
-  memset(object_counts_, 0, sizeof(object_counts_));
-  memset(object_sizes_, 0, sizeof(object_sizes_));
-  if (clear_last_time_stats) {
-    memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
-    memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
-  }
-}
-
-
-static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER;
-
-
-void Heap::TraceObjectStat(const char* name, int count, int size, double time) {
-  PrintIsolate(isolate_,
-               "heap:%p, time:%f, gc:%d, type:%s, count:%d, size:%d\n",
-               static_cast<void*>(this), time, ms_count_, name, count, size);
-}
-
-
-void Heap::TraceObjectStats() {
-  base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer());
-  int index;
-  int count;
-  int size;
-  int total_size = 0;
-  double time = isolate_->time_millis_since_init();
-#define TRACE_OBJECT_COUNT(name)                     \
-  count = static_cast<int>(object_counts_[name]);    \
-  size = static_cast<int>(object_sizes_[name]) / KB; \
-  total_size += size;                                \
-  TraceObjectStat(#name, count, size, time);
-  INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT)
-#undef TRACE_OBJECT_COUNT
-#define TRACE_OBJECT_COUNT(name)                      \
-  index = FIRST_CODE_KIND_SUB_TYPE + Code::name;      \
-  count = static_cast<int>(object_counts_[index]);    \
-  size = static_cast<int>(object_sizes_[index]) / KB; \
-  TraceObjectStat("*CODE_" #name, count, size, time);
-  CODE_KIND_LIST(TRACE_OBJECT_COUNT)
-#undef TRACE_OBJECT_COUNT
-#define TRACE_OBJECT_COUNT(name)                      \
-  index = FIRST_FIXED_ARRAY_SUB_TYPE + name;          \
-  count = static_cast<int>(object_counts_[index]);    \
-  size = static_cast<int>(object_sizes_[index]) / KB; \
-  TraceObjectStat("*FIXED_ARRAY_" #name, count, size, time);
-  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT)
-#undef TRACE_OBJECT_COUNT
-#define TRACE_OBJECT_COUNT(name)                                              \
-  index =                                                                     \
-      FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \
-  count = static_cast<int>(object_counts_[index]);                            \
-  size = static_cast<int>(object_sizes_[index]) / KB;                         \
-  TraceObjectStat("*CODE_AGE_" #name, count, size, time);
-  CODE_AGE_LIST_COMPLETE(TRACE_OBJECT_COUNT)
-#undef TRACE_OBJECT_COUNT
-}
-
-
-void Heap::CheckpointObjectStats() {
-  base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer());
-  Counters* counters = isolate()->counters();
-#define ADJUST_LAST_TIME_OBJECT_COUNT(name)              \
-  counters->count_of_##name()->Increment(                \
-      static_cast<int>(object_counts_[name]));           \
-  counters->count_of_##name()->Decrement(                \
-      static_cast<int>(object_counts_last_time_[name])); \
-  counters->size_of_##name()->Increment(                 \
-      static_cast<int>(object_sizes_[name]));            \
-  counters->size_of_##name()->Decrement(                 \
-      static_cast<int>(object_sizes_last_time_[name]));
-  INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
-#undef ADJUST_LAST_TIME_OBJECT_COUNT
-  int index;
-#define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \
-  index = FIRST_CODE_KIND_SUB_TYPE + Code::name;          \
-  counters->count_of_CODE_TYPE_##name()->Increment(       \
-      static_cast<int>(object_counts_[index]));           \
-  counters->count_of_CODE_TYPE_##name()->Decrement(       \
-      static_cast<int>(object_counts_last_time_[index])); \
-  counters->size_of_CODE_TYPE_##name()->Increment(        \
-      static_cast<int>(object_sizes_[index]));            \
-  counters->size_of_CODE_TYPE_##name()->Decrement(        \
-      static_cast<int>(object_sizes_last_time_[index]));
-  CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
-#undef ADJUST_LAST_TIME_OBJECT_COUNT
-#define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \
-  index = FIRST_FIXED_ARRAY_SUB_TYPE + name;              \
-  counters->count_of_FIXED_ARRAY_##name()->Increment(     \
-      static_cast<int>(object_counts_[index]));           \
-  counters->count_of_FIXED_ARRAY_##name()->Decrement(     \
-      static_cast<int>(object_counts_last_time_[index])); \
-  counters->size_of_FIXED_ARRAY_##name()->Increment(      \
-      static_cast<int>(object_sizes_[index]));            \
-  counters->size_of_FIXED_ARRAY_##name()->Decrement(      \
-      static_cast<int>(object_sizes_last_time_[index]));
-  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
-#undef ADJUST_LAST_TIME_OBJECT_COUNT
-#define ADJUST_LAST_TIME_OBJECT_COUNT(name)                                   \
-  index =                                                                     \
-      FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \
-  counters->count_of_CODE_AGE_##name()->Increment(                            \
-      static_cast<int>(object_counts_[index]));                               \
-  counters->count_of_CODE_AGE_##name()->Decrement(                            \
-      static_cast<int>(object_counts_last_time_[index]));                     \
-  counters->size_of_CODE_AGE_##name()->Increment(                             \
-      static_cast<int>(object_sizes_[index]));                                \
-  counters->size_of_CODE_AGE_##name()->Decrement(                             \
-      static_cast<int>(object_sizes_last_time_[index]));
-  CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT)
-#undef ADJUST_LAST_TIME_OBJECT_COUNT
-
-  MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
-  MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
-  ClearObjectStats();
-}
-
-
 void Heap::RegisterStrongRoots(Object** start, Object** end) {
   StrongRootsList* list = new StrongRootsList();
   list->next = strong_roots_list_;
@@ -6720,9 +6608,26 @@ void Heap::UnregisterStrongRoots(Object** start) {
 }
 
 
+size_t Heap::NumberOfTrackedHeapObjectTypes() {
+  return ObjectStats::OBJECT_STATS_COUNT;
+}
+
+
+size_t Heap::ObjectCountAtLastGC(size_t index) {
+  if (index >= ObjectStats::OBJECT_STATS_COUNT) return 0;
+  return object_stats_->object_count_last_gc(index);
+}
+
+
+size_t Heap::ObjectSizeAtLastGC(size_t index) {
+  if (index >= ObjectStats::OBJECT_STATS_COUNT) return 0;
+  return object_stats_->object_size_last_gc(index);
+}
+
+
 bool Heap::GetObjectTypeName(size_t index, const char** object_type,
                              const char** object_sub_type) {
-  if (index >= OBJECT_STATS_COUNT) return false;
+  if (index >= ObjectStats::OBJECT_STATS_COUNT) return false;
 
   switch (static_cast<int>(index)) {
 #define COMPARE_AND_RETURN_NAME(name) \
@@ -6732,29 +6637,31 @@ bool Heap::GetObjectTypeName(size_t index, const char** object_type,
     return true;
     INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
 #undef COMPARE_AND_RETURN_NAME
-#define COMPARE_AND_RETURN_NAME(name)         \
-  case FIRST_CODE_KIND_SUB_TYPE + Code::name: \
-    *object_type = "CODE_TYPE";               \
-    *object_sub_type = "CODE_KIND/" #name;    \
+#define COMPARE_AND_RETURN_NAME(name)                      \
+  case ObjectStats::FIRST_CODE_KIND_SUB_TYPE + Code::name: \
+    *object_type = "CODE_TYPE";                            \
+    *object_sub_type = "CODE_KIND/" #name;                 \
     return true;
     CODE_KIND_LIST(COMPARE_AND_RETURN_NAME)
 #undef COMPARE_AND_RETURN_NAME
-#define COMPARE_AND_RETURN_NAME(name)     \
-  case FIRST_FIXED_ARRAY_SUB_TYPE + name: \
-    *object_type = "FIXED_ARRAY_TYPE";    \
-    *object_sub_type = #name;             \
+#define COMPARE_AND_RETURN_NAME(name)                  \
+  case ObjectStats::FIRST_FIXED_ARRAY_SUB_TYPE + name: \
+    *object_type = "FIXED_ARRAY_TYPE";                 \
+    *object_sub_type = #name;                          \
     return true;
     FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
 #undef COMPARE_AND_RETURN_NAME
-#define COMPARE_AND_RETURN_NAME(name)                                          \
-  case FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge: \
-    *object_type = "CODE_TYPE";                                                \
-    *object_sub_type = "CODE_AGE/" #name;                                      \
+#define COMPARE_AND_RETURN_NAME(name)                                  \
+  case ObjectStats::FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - \
+      Code::kFirstCodeAge:                                             \
+    *object_type = "CODE_TYPE";                                        \
+    *object_sub_type = "CODE_AGE/" #name;                              \
     return true;
     CODE_AGE_LIST_COMPLETE(COMPARE_AND_RETURN_NAME)
 #undef COMPARE_AND_RETURN_NAME
   }
   return false;
 }
+
 }  // namespace internal
 }  // namespace v8
index 32be769..933c4dc 100644 (file)
@@ -424,6 +424,7 @@ class HeapObjectsFilter;
 class HeapStats;
 class Isolate;
 class MemoryReducer;
+class ObjectStats;
 class WeakObjectRetainer;
 
 
@@ -586,18 +587,6 @@ class Heap {
 
   enum HeapState { NOT_IN_GC, SCAVENGE, MARK_COMPACT };
 
-  // ObjectStats are kept in two arrays, counts and sizes. Related stats are
-  // stored in a contiguous linear buffer. Stats groups are stored one after
-  // another.
-  enum {
-    FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1,
-    FIRST_FIXED_ARRAY_SUB_TYPE =
-        FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS,
-    FIRST_CODE_AGE_SUB_TYPE =
-        FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1,
-    OBJECT_STATS_COUNT = FIRST_CODE_AGE_SUB_TYPE + Code::kCodeAgeCount + 1
-  };
-
   // Taking this lock prevents the GC from entering a phase that relocates
   // object references.
   class RelocationLock {
@@ -909,14 +898,6 @@ class Heap {
   // Print short heap statistics.
   void PrintShortHeapStatistics();
 
-  size_t object_count_last_gc(size_t index) {
-    return index < OBJECT_STATS_COUNT ? object_counts_last_time_[index] : 0;
-  }
-
-  size_t object_size_last_gc(size_t index) {
-    return index < OBJECT_STATS_COUNT ? object_sizes_last_time_[index] : 0;
-  }
-
   inline HeapState gc_state() { return gc_state_; }
 
   inline bool IsInGCPostProcessing() { return gc_post_processing_depth_ > 0; }
@@ -1009,38 +990,6 @@ class Heap {
     return new_space_.IsAtMaximumCapacity() && maximum_size_scavenges_ == 0;
   }
 
-  void RecordObjectStats(InstanceType type, size_t size) {
-    DCHECK(type <= LAST_TYPE);
-    object_counts_[type]++;
-    object_sizes_[type] += size;
-  }
-
-  void RecordCodeSubTypeStats(int code_sub_type, int code_age, size_t size) {
-    int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type;
-    int code_age_index =
-        FIRST_CODE_AGE_SUB_TYPE + code_age - Code::kFirstCodeAge;
-    DCHECK(code_sub_type_index >= FIRST_CODE_KIND_SUB_TYPE &&
-           code_sub_type_index < FIRST_CODE_AGE_SUB_TYPE);
-    DCHECK(code_age_index >= FIRST_CODE_AGE_SUB_TYPE &&
-           code_age_index < OBJECT_STATS_COUNT);
-    object_counts_[code_sub_type_index]++;
-    object_sizes_[code_sub_type_index] += size;
-    object_counts_[code_age_index]++;
-    object_sizes_[code_age_index] += size;
-  }
-
-  void RecordFixedArraySubTypeStats(int array_sub_type, size_t size) {
-    DCHECK(array_sub_type <= LAST_FIXED_ARRAY_SUB_TYPE);
-    object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]++;
-    object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += size;
-  }
-
-  void TraceObjectStats();
-  void TraceObjectStat(const char* name, int count, int size, double time);
-  void CheckpointObjectStats();
-  bool GetObjectTypeName(size_t index, const char** object_type,
-                         const char** object_sub_type);
-
   void AddWeakObjectToCodeDependency(Handle<HeapObject> obj,
                                      Handle<DependentCode> dep);
 
@@ -1384,6 +1333,25 @@ class Heap {
   bool InSpace(HeapObject* value, AllocationSpace space);
 
   // ===========================================================================
+  // Object statistics tracking. ===============================================
+  // ===========================================================================
+
+  // Returns the number of buckets used by object statistics tracking during a
+  // major GC. Note that the following methods fail gracefully when the bounds
+  // are exceeded though.
+  size_t NumberOfTrackedHeapObjectTypes();
+
+  // Returns object statistics about count and size at the last major GC.
+  // Objects are being grouped into buckets that roughly resemble existing
+  // instance types.
+  size_t ObjectCountAtLastGC(size_t index);
+  size_t ObjectSizeAtLastGC(size_t index);
+
+  // Retrieves names of buckets used by object statistics tracking.
+  bool GetObjectTypeName(size_t index, const char** object_type,
+                         const char** object_sub_type);
+
+  // ===========================================================================
   // GC statistics. ============================================================
   // ===========================================================================
 
@@ -1840,8 +1808,6 @@ class Heap {
   void CheckAndNotifyBackgroundIdleNotification(double idle_time_in_ms,
                                                 double now_ms);
 
-  void ClearObjectStats(bool clear_last_time_stats = false);
-
   inline void UpdateAllocationsHash(HeapObject* object);
   inline void UpdateAllocationsHash(uint32_t value);
   void PrintAlloctionsHash();
@@ -2274,12 +2240,6 @@ class Heap {
   // of the allocation site.
   unsigned int maximum_size_scavenges_;
 
-  // Object counts and used memory by InstanceType
-  size_t object_counts_[OBJECT_STATS_COUNT];
-  size_t object_counts_last_time_[OBJECT_STATS_COUNT];
-  size_t object_sizes_[OBJECT_STATS_COUNT];
-  size_t object_sizes_last_time_[OBJECT_STATS_COUNT];
-
   // Maximum GC pause.
   double max_gc_pause_;
 
@@ -2314,6 +2274,8 @@ class Heap {
 
   MemoryReducer* memory_reducer_;
 
+  ObjectStats* object_stats_;
+
   // These two counters are monotomically increasing and never reset.
   size_t full_codegen_bytes_generated_;
   size_t crankshaft_codegen_bytes_generated_;
index 6aa4087..b66dd55 100644 (file)
@@ -17,6 +17,7 @@
 #include "src/heap/gc-tracer.h"
 #include "src/heap/incremental-marking.h"
 #include "src/heap/mark-compact-inl.h"
+#include "src/heap/object-stats.h"
 #include "src/heap/objects-visiting.h"
 #include "src/heap/objects-visiting-inl.h"
 #include "src/heap/spaces-inl.h"
@@ -1416,9 +1417,11 @@ void MarkCompactMarkingVisitor::ObjectStatsCountFixedArray(
       fixed_array->map() != heap->fixed_double_array_map() &&
       fixed_array != heap->empty_fixed_array()) {
     if (fixed_array->IsDictionary()) {
-      heap->RecordFixedArraySubTypeStats(dictionary_type, fixed_array->Size());
+      heap->object_stats_->RecordFixedArraySubTypeStats(dictionary_type,
+                                                        fixed_array->Size());
     } else {
-      heap->RecordFixedArraySubTypeStats(fast_type, fixed_array->Size());
+      heap->object_stats_->RecordFixedArraySubTypeStats(fast_type,
+                                                        fixed_array->Size());
     }
   }
 }
@@ -1428,7 +1431,7 @@ void MarkCompactMarkingVisitor::ObjectStatsVisitBase(
     MarkCompactMarkingVisitor::VisitorId id, Map* map, HeapObject* obj) {
   Heap* heap = map->GetHeap();
   int object_size = obj->Size();
-  heap->RecordObjectStats(map->instance_type(), object_size);
+  heap->object_stats_->RecordObjectStats(map->instance_type(), object_size);
   non_count_table_.GetVisitorById(id)(map, obj);
   if (obj->IsJSObject()) {
     JSObject* object = JSObject::cast(obj);
@@ -1460,21 +1463,21 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
     if (map_obj->owns_descriptors() &&
         array != heap->empty_descriptor_array()) {
       int fixed_array_size = array->Size();
-      heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
-                                         fixed_array_size);
+      heap->object_stats_->RecordFixedArraySubTypeStats(
+          DESCRIPTOR_ARRAY_SUB_TYPE, fixed_array_size);
     }
     if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) {
       int fixed_array_size =
           TransitionArray::cast(map_obj->raw_transitions())->Size();
-      heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
-                                         fixed_array_size);
+      heap->object_stats_->RecordFixedArraySubTypeStats(
+          TRANSITION_ARRAY_SUB_TYPE, fixed_array_size);
     }
     if (map_obj->has_code_cache()) {
       CodeCache* cache = CodeCache::cast(map_obj->code_cache());
-      heap->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE,
-                                         cache->default_cache()->Size());
+      heap->object_stats_->RecordFixedArraySubTypeStats(
+          MAP_CODE_CACHE_SUB_TYPE, cache->default_cache()->Size());
       if (!cache->normal_type_cache()->IsUndefined()) {
-        heap->RecordFixedArraySubTypeStats(
+        heap->object_stats_->RecordFixedArraySubTypeStats(
             MAP_CODE_CACHE_SUB_TYPE,
             FixedArray::cast(cache->normal_type_cache())->Size());
       }
@@ -1493,8 +1496,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
     int object_size = obj->Size();
     DCHECK(map->instance_type() == CODE_TYPE);
     Code* code_obj = Code::cast(obj);
-    heap->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(),
-                                 object_size);
+    heap->object_stats_->RecordCodeSubTypeStats(
+        code_obj->kind(), code_obj->GetAge(), object_size);
     ObjectStatsVisitBase(kVisitCode, map, obj);
   }
 };
@@ -1508,7 +1511,7 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
     Heap* heap = map->GetHeap();
     SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
     if (sfi->scope_info() != heap->empty_fixed_array()) {
-      heap->RecordFixedArraySubTypeStats(
+      heap->object_stats_->RecordFixedArraySubTypeStats(
           SCOPE_INFO_SUB_TYPE, FixedArray::cast(sfi->scope_info())->Size());
     }
     ObjectStatsVisitBase(kVisitSharedFunctionInfo, map, obj);
@@ -1524,8 +1527,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
     Heap* heap = map->GetHeap();
     FixedArray* fixed_array = FixedArray::cast(obj);
     if (fixed_array == heap->string_table()) {
-      heap->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE,
-                                         fixed_array->Size());
+      heap->object_stats_->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE,
+                                                        fixed_array->Size());
     }
     ObjectStatsVisitBase(kVisitFixedArray, map, obj);
   }
@@ -2343,9 +2346,9 @@ void MarkCompactCollector::AfterMarking() {
 
   if (FLAG_track_gc_object_stats) {
     if (FLAG_trace_gc_object_stats) {
-      heap()->TraceObjectStats();
+      heap()->object_stats_->TraceObjectStats();
     }
-    heap()->CheckpointObjectStats();
+    heap()->object_stats_->CheckpointObjectStats();
   }
 }
 
diff --git a/src/heap/object-stats.cc b/src/heap/object-stats.cc
new file mode 100644 (file)
index 0000000..4cdd807
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2015 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.
+
+#include "src/heap/object-stats.h"
+
+#include "src/counters.h"
+#include "src/heap/heap-inl.h"
+#include "src/isolate.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER;
+
+
+void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
+  memset(object_counts_, 0, sizeof(object_counts_));
+  memset(object_sizes_, 0, sizeof(object_sizes_));
+  if (clear_last_time_stats) {
+    memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
+    memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
+  }
+}
+
+
+void ObjectStats::TraceObjectStat(const char* name, int count, int size,
+                                  double time) {
+  int ms_count = heap()->ms_count();
+  PrintIsolate(isolate(),
+               "heap:%p, time:%f, gc:%d, type:%s, count:%d, size:%d\n",
+               static_cast<void*>(heap()), time, ms_count, name, count, size);
+}
+
+
+void ObjectStats::TraceObjectStats() {
+  base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer());
+  int index;
+  int count;
+  int size;
+  int total_size = 0;
+  double time = isolate()->time_millis_since_init();
+#define TRACE_OBJECT_COUNT(name)                     \
+  count = static_cast<int>(object_counts_[name]);    \
+  size = static_cast<int>(object_sizes_[name]) / KB; \
+  total_size += size;                                \
+  TraceObjectStat(#name, count, size, time);
+  INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT)
+#undef TRACE_OBJECT_COUNT
+#define TRACE_OBJECT_COUNT(name)                      \
+  index = FIRST_CODE_KIND_SUB_TYPE + Code::name;      \
+  count = static_cast<int>(object_counts_[index]);    \
+  size = static_cast<int>(object_sizes_[index]) / KB; \
+  TraceObjectStat("*CODE_" #name, count, size, time);
+  CODE_KIND_LIST(TRACE_OBJECT_COUNT)
+#undef TRACE_OBJECT_COUNT
+#define TRACE_OBJECT_COUNT(name)                      \
+  index = FIRST_FIXED_ARRAY_SUB_TYPE + name;          \
+  count = static_cast<int>(object_counts_[index]);    \
+  size = static_cast<int>(object_sizes_[index]) / KB; \
+  TraceObjectStat("*FIXED_ARRAY_" #name, count, size, time);
+  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(TRACE_OBJECT_COUNT)
+#undef TRACE_OBJECT_COUNT
+#define TRACE_OBJECT_COUNT(name)                                              \
+  index =                                                                     \
+      FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \
+  count = static_cast<int>(object_counts_[index]);                            \
+  size = static_cast<int>(object_sizes_[index]) / KB;                         \
+  TraceObjectStat("*CODE_AGE_" #name, count, size, time);
+  CODE_AGE_LIST_COMPLETE(TRACE_OBJECT_COUNT)
+#undef TRACE_OBJECT_COUNT
+}
+
+
+void ObjectStats::CheckpointObjectStats() {
+  base::LockGuard<base::Mutex> lock_guard(object_stats_mutex.Pointer());
+  Counters* counters = isolate()->counters();
+#define ADJUST_LAST_TIME_OBJECT_COUNT(name)              \
+  counters->count_of_##name()->Increment(                \
+      static_cast<int>(object_counts_[name]));           \
+  counters->count_of_##name()->Decrement(                \
+      static_cast<int>(object_counts_last_time_[name])); \
+  counters->size_of_##name()->Increment(                 \
+      static_cast<int>(object_sizes_[name]));            \
+  counters->size_of_##name()->Decrement(                 \
+      static_cast<int>(object_sizes_last_time_[name]));
+  INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
+#undef ADJUST_LAST_TIME_OBJECT_COUNT
+  int index;
+#define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \
+  index = FIRST_CODE_KIND_SUB_TYPE + Code::name;          \
+  counters->count_of_CODE_TYPE_##name()->Increment(       \
+      static_cast<int>(object_counts_[index]));           \
+  counters->count_of_CODE_TYPE_##name()->Decrement(       \
+      static_cast<int>(object_counts_last_time_[index])); \
+  counters->size_of_CODE_TYPE_##name()->Increment(        \
+      static_cast<int>(object_sizes_[index]));            \
+  counters->size_of_CODE_TYPE_##name()->Decrement(        \
+      static_cast<int>(object_sizes_last_time_[index]));
+  CODE_KIND_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
+#undef ADJUST_LAST_TIME_OBJECT_COUNT
+#define ADJUST_LAST_TIME_OBJECT_COUNT(name)               \
+  index = FIRST_FIXED_ARRAY_SUB_TYPE + name;              \
+  counters->count_of_FIXED_ARRAY_##name()->Increment(     \
+      static_cast<int>(object_counts_[index]));           \
+  counters->count_of_FIXED_ARRAY_##name()->Decrement(     \
+      static_cast<int>(object_counts_last_time_[index])); \
+  counters->size_of_FIXED_ARRAY_##name()->Increment(      \
+      static_cast<int>(object_sizes_[index]));            \
+  counters->size_of_FIXED_ARRAY_##name()->Decrement(      \
+      static_cast<int>(object_sizes_last_time_[index]));
+  FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
+#undef ADJUST_LAST_TIME_OBJECT_COUNT
+#define ADJUST_LAST_TIME_OBJECT_COUNT(name)                                   \
+  index =                                                                     \
+      FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge; \
+  counters->count_of_CODE_AGE_##name()->Increment(                            \
+      static_cast<int>(object_counts_[index]));                               \
+  counters->count_of_CODE_AGE_##name()->Decrement(                            \
+      static_cast<int>(object_counts_last_time_[index]));                     \
+  counters->size_of_CODE_AGE_##name()->Increment(                             \
+      static_cast<int>(object_sizes_[index]));                                \
+  counters->size_of_CODE_AGE_##name()->Decrement(                             \
+      static_cast<int>(object_sizes_last_time_[index]));
+  CODE_AGE_LIST_COMPLETE(ADJUST_LAST_TIME_OBJECT_COUNT)
+#undef ADJUST_LAST_TIME_OBJECT_COUNT
+
+  MemCopy(object_counts_last_time_, object_counts_, sizeof(object_counts_));
+  MemCopy(object_sizes_last_time_, object_sizes_, sizeof(object_sizes_));
+  ClearObjectStats();
+}
+
+
+Isolate* ObjectStats::isolate() { return heap()->isolate(); }
+
+}  // namespace internal
+}  // namespace v8
diff --git a/src/heap/object-stats.h b/src/heap/object-stats.h
new file mode 100644 (file)
index 0000000..ae85516
--- /dev/null
@@ -0,0 +1,86 @@
+// Copyright 2015 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_OBJECT_STATS_H_
+#define V8_HEAP_OBJECT_STATS_H_
+
+#include "src/heap/heap.h"
+#include "src/objects.h"
+
+namespace v8 {
+namespace internal {
+
+class ObjectStats {
+ public:
+  explicit ObjectStats(Heap* heap) : heap_(heap) {}
+
+  // ObjectStats are kept in two arrays, counts and sizes. Related stats are
+  // stored in a contiguous linear buffer. Stats groups are stored one after
+  // another.
+  enum {
+    FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1,
+    FIRST_FIXED_ARRAY_SUB_TYPE =
+        FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS,
+    FIRST_CODE_AGE_SUB_TYPE =
+        FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1,
+    OBJECT_STATS_COUNT = FIRST_CODE_AGE_SUB_TYPE + Code::kCodeAgeCount + 1
+  };
+
+  void ClearObjectStats(bool clear_last_time_stats = false);
+
+  void TraceObjectStats();
+  void TraceObjectStat(const char* name, int count, int size, double time);
+  void CheckpointObjectStats();
+
+  void RecordObjectStats(InstanceType type, size_t size) {
+    DCHECK(type <= LAST_TYPE);
+    object_counts_[type]++;
+    object_sizes_[type] += size;
+  }
+
+  void RecordCodeSubTypeStats(int code_sub_type, int code_age, size_t size) {
+    int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type;
+    int code_age_index =
+        FIRST_CODE_AGE_SUB_TYPE + code_age - Code::kFirstCodeAge;
+    DCHECK(code_sub_type_index >= FIRST_CODE_KIND_SUB_TYPE &&
+           code_sub_type_index < FIRST_CODE_AGE_SUB_TYPE);
+    DCHECK(code_age_index >= FIRST_CODE_AGE_SUB_TYPE &&
+           code_age_index < OBJECT_STATS_COUNT);
+    object_counts_[code_sub_type_index]++;
+    object_sizes_[code_sub_type_index] += size;
+    object_counts_[code_age_index]++;
+    object_sizes_[code_age_index] += size;
+  }
+
+  void RecordFixedArraySubTypeStats(int array_sub_type, size_t size) {
+    DCHECK(array_sub_type <= LAST_FIXED_ARRAY_SUB_TYPE);
+    object_counts_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]++;
+    object_sizes_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] += size;
+  }
+
+  size_t object_count_last_gc(size_t index) {
+    return object_counts_last_time_[index];
+  }
+
+  size_t object_size_last_gc(size_t index) {
+    return object_sizes_last_time_[index];
+  }
+
+  Isolate* isolate();
+  Heap* heap() { return heap_; }
+
+ private:
+  Heap* heap_;
+
+  // Object counts and used memory by InstanceType
+  size_t object_counts_[OBJECT_STATS_COUNT];
+  size_t object_counts_last_time_[OBJECT_STATS_COUNT];
+  size_t object_sizes_[OBJECT_STATS_COUNT];
+  size_t object_sizes_last_time_[OBJECT_STATS_COUNT];
+};
+
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_HEAP_OBJECT_STATS_H_
index 154b709..d7f83cb 100644 (file)
         '../../src/heap/mark-compact-inl.h',
         '../../src/heap/mark-compact.cc',
         '../../src/heap/mark-compact.h',
+        '../../src/heap/object-stats.cc',
+        '../../src/heap/object-stats.h',
         '../../src/heap/objects-visiting-inl.h',
         '../../src/heap/objects-visiting.cc',
         '../../src/heap/objects-visiting.h',