Commit c7de3e7f authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[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}
parent a369ab18
......@@ -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",
......
......@@ -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);
......
This diff is collapsed.
......@@ -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_;
......
......@@ -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();
}
}
......
// 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
// 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_
......@@ -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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment