"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",
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);
#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"
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),
// 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);
}
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()));
memory_reducer_ = nullptr;
}
+ delete object_stats_;
+ object_stats_ = nullptr;
+
WaitUntilUnmappingOfFreeChunksCompleted();
TearDownArrayBuffers();
}
-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_;
}
+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) \
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
class HeapStats;
class Isolate;
class MemoryReducer;
+class ObjectStats;
class WeakObjectRetainer;
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 {
// 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; }
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);
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. ============================================================
// ===========================================================================
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();
// 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_;
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_;
#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"
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());
}
}
}
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);
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());
}
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);
}
};
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);
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);
}
if (FLAG_track_gc_object_stats) {
if (FLAG_trace_gc_object_stats) {
- heap()->TraceObjectStats();
+ heap()->object_stats_->TraceObjectStats();
}
- heap()->CheckpointObjectStats();
+ heap()->object_stats_->CheckpointObjectStats();
}
}
--- /dev/null
+// 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
--- /dev/null
+// 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_
'../../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',