[heap] Separate ObjectStats out into its own class.

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}
This commit is contained in:
mstarzinger 2015-09-02 09:43:21 -07:00 committed by Commit bot
parent a369ab1838
commit c7de3e7f27
8 changed files with 317 additions and 214 deletions

View File

@ -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",

View 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);

View 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

View 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);
@ -1383,6 +1332,25 @@ class Heap {
bool InSpace(Address addr, AllocationSpace space);
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_;

View 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();
}
}

138
src/heap/object-stats.cc Normal file
View File

@ -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

86
src/heap/object-stats.h Normal file
View File

@ -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_

View File

@ -721,6 +721,8 @@
'../../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',