Commit 91618802 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[object-stats] Redo recording of non-existing instance types

- Base recording just on the concept of virtual instance types.
- Re-add dropped types incrementally.

Bug: v8:7266
Change-Id: Ic8209ce8c6067e24536a0c62404e1160f86377db
Reviewed-on: https://chromium-review.googlesource.com/873646Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50714}
parent cdc6f7e1
...@@ -6479,19 +6479,13 @@ bool Heap::GetObjectTypeName(size_t index, const char** object_type, ...@@ -6479,19 +6479,13 @@ bool Heap::GetObjectTypeName(size_t index, const char** object_type,
return true; return true;
INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
#undef COMPARE_AND_RETURN_NAME #undef COMPARE_AND_RETURN_NAME
#define COMPARE_AND_RETURN_NAME(name) \
case ObjectStats::FIRST_CODE_KIND_SUB_TYPE + Code::name: \ #define COMPARE_AND_RETURN_NAME(name) \
*object_type = "CODE_TYPE"; \ case ObjectStats::FIRST_VIRTUAL_TYPE + ObjectStats::name: \
*object_sub_type = "CODE_KIND/" #name; \ *object_type = #name; \
return true; *object_sub_type = ""; \
CODE_KIND_LIST(COMPARE_AND_RETURN_NAME)
#undef COMPARE_AND_RETURN_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; return true;
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME) VIRTUAL_INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
#undef COMPARE_AND_RETURN_NAME #undef COMPARE_AND_RETURN_NAME
} }
return false; return false;
......
...@@ -31,7 +31,6 @@ void ObjectStats::ClearObjectStats(bool clear_last_time_stats) { ...@@ -31,7 +31,6 @@ void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
} }
visited_fixed_array_sub_types_.clear();
} }
// Tell the compiler to never inline this: occasionally, the optimizer will // Tell the compiler to never inline this: occasionally, the optimizer will
...@@ -99,23 +98,14 @@ void ObjectStats::PrintJSON(const char* key) { ...@@ -99,23 +98,14 @@ void ObjectStats::PrintJSON(const char* key) {
#define INSTANCE_TYPE_WRAPPER(name) \ #define INSTANCE_TYPE_WRAPPER(name) \
PrintInstanceTypeJSON(key, gc_count, #name, name); PrintInstanceTypeJSON(key, gc_count, #name, name);
#define CODE_KIND_WRAPPER(name) \
PrintInstanceTypeJSON(key, gc_count, "*CODE_" #name, \
FIRST_CODE_KIND_SUB_TYPE + Code::name);
#define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \
PrintInstanceTypeJSON(key, gc_count, "*FIXED_ARRAY_" #name, \
FIRST_FIXED_ARRAY_SUB_TYPE + name);
#define VIRTUAL_INSTANCE_TYPE_WRAPPER(name) \ #define VIRTUAL_INSTANCE_TYPE_WRAPPER(name) \
PrintInstanceTypeJSON(key, gc_count, #name, FIRST_VIRTUAL_TYPE + name); PrintInstanceTypeJSON(key, gc_count, #name, FIRST_VIRTUAL_TYPE + name);
INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER) INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER)
CODE_KIND_LIST(CODE_KIND_WRAPPER)
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER)
VIRTUAL_INSTANCE_TYPE_LIST(VIRTUAL_INSTANCE_TYPE_WRAPPER) VIRTUAL_INSTANCE_TYPE_LIST(VIRTUAL_INSTANCE_TYPE_WRAPPER)
#undef INSTANCE_TYPE_WRAPPER #undef INSTANCE_TYPE_WRAPPER
#undef CODE_KIND_WRAPPER
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
#undef VIRTUAL_INSTANCE_TYPE_WRAPPER #undef VIRTUAL_INSTANCE_TYPE_WRAPPER
} }
...@@ -150,25 +140,15 @@ void ObjectStats::Dump(std::stringstream& stream) { ...@@ -150,25 +140,15 @@ void ObjectStats::Dump(std::stringstream& stream) {
stream << "\"type_data\":{"; stream << "\"type_data\":{";
#define INSTANCE_TYPE_WRAPPER(name) DumpInstanceTypeData(stream, #name, name); #define INSTANCE_TYPE_WRAPPER(name) DumpInstanceTypeData(stream, #name, name);
#define CODE_KIND_WRAPPER(name) \
DumpInstanceTypeData(stream, "*CODE_" #name, \
FIRST_CODE_KIND_SUB_TYPE + Code::name);
#define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \
DumpInstanceTypeData(stream, "*FIXED_ARRAY_" #name, \
FIRST_FIXED_ARRAY_SUB_TYPE + name);
#define VIRTUAL_INSTANCE_TYPE_WRAPPER(name) \ #define VIRTUAL_INSTANCE_TYPE_WRAPPER(name) \
DumpInstanceTypeData(stream, #name, FIRST_VIRTUAL_TYPE + name); DumpInstanceTypeData(stream, #name, FIRST_VIRTUAL_TYPE + name);
INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER); INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER);
CODE_KIND_LIST(CODE_KIND_WRAPPER);
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER);
VIRTUAL_INSTANCE_TYPE_LIST(VIRTUAL_INSTANCE_TYPE_WRAPPER) VIRTUAL_INSTANCE_TYPE_LIST(VIRTUAL_INSTANCE_TYPE_WRAPPER)
stream << "\"END\":{}}}"; stream << "\"END\":{}}}";
#undef INSTANCE_TYPE_WRAPPER #undef INSTANCE_TYPE_WRAPPER
#undef CODE_KIND_WRAPPER
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
#undef VIRTUAL_INSTANCE_TYPE_WRAPPER #undef VIRTUAL_INSTANCE_TYPE_WRAPPER
} }
...@@ -202,94 +182,59 @@ void ObjectStats::RecordObjectStats(InstanceType type, size_t size) { ...@@ -202,94 +182,59 @@ void ObjectStats::RecordObjectStats(InstanceType type, size_t size) {
} }
void ObjectStats::RecordVirtualObjectStats(VirtualInstanceType type, void ObjectStats::RecordVirtualObjectStats(VirtualInstanceType type,
size_t size) { size_t size, size_t over_allocated) {
DCHECK_LE(type, LAST_VIRTUAL_TYPE); DCHECK_LE(type, LAST_VIRTUAL_TYPE);
object_counts_[FIRST_VIRTUAL_TYPE + type]++; object_counts_[FIRST_VIRTUAL_TYPE + type]++;
object_sizes_[FIRST_VIRTUAL_TYPE + type] += size; object_sizes_[FIRST_VIRTUAL_TYPE + type] += size;
size_histogram_[FIRST_VIRTUAL_TYPE + type][HistogramIndexFromSize(size)]++; size_histogram_[FIRST_VIRTUAL_TYPE + type][HistogramIndexFromSize(size)]++;
} over_allocated_[FIRST_VIRTUAL_TYPE + type] += over_allocated;
over_allocated_histogram_[FIRST_VIRTUAL_TYPE + type]
void ObjectStats::RecordCodeSubTypeStats(int code_sub_type, size_t size) { [HistogramIndexFromSize(size)]++;
int code_sub_type_index = FIRST_CODE_KIND_SUB_TYPE + code_sub_type;
DCHECK_GE(code_sub_type_index, FIRST_CODE_KIND_SUB_TYPE);
DCHECK_LT(code_sub_type_index, FIRST_FIXED_ARRAY_SUB_TYPE);
object_counts_[code_sub_type_index]++;
object_sizes_[code_sub_type_index] += size;
size_histogram_[code_sub_type_index][HistogramIndexFromSize(size)]++;
}
bool ObjectStats::RecordFixedArraySubTypeStats(FixedArrayBase* array,
int array_sub_type, size_t size,
size_t over_allocated) {
auto it = visited_fixed_array_sub_types_.insert(array);
if (!it.second) return false;
DCHECK_LE(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_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]
[HistogramIndexFromSize(size)]++;
if (over_allocated > 0) {
InstanceType type =
array->IsHashTable() ? HASH_TABLE_TYPE : FIXED_ARRAY_TYPE;
over_allocated_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type] +=
over_allocated;
over_allocated_histogram_[FIRST_FIXED_ARRAY_SUB_TYPE + array_sub_type]
[HistogramIndexFromSize(over_allocated)]++;
over_allocated_[type] += over_allocated;
over_allocated_histogram_[type][HistogramIndexFromSize(over_allocated)]++;
}
return true;
} }
Isolate* ObjectStats::isolate() { return heap()->isolate(); } Isolate* ObjectStats::isolate() { return heap()->isolate(); }
class ObjectStatsCollectorImpl { class ObjectStatsCollectorImpl {
public: public:
enum Phase {
kPhase1,
kPhase2,
};
static const int kNumberOfPhases = kPhase2 + 1;
ObjectStatsCollectorImpl(Heap* heap, ObjectStats* stats); ObjectStatsCollectorImpl(Heap* heap, ObjectStats* stats);
void CollectGlobalStatistics(); void CollectGlobalStatistics();
void CollectStatistics(HeapObject* obj, Phase phase);
// Collects statistics of objects for virtual instance types.
void CollectVirtualStatistics(HeapObject* obj);
// Collects statistics of objects for regular instance types.
void CollectStatistics(HeapObject* obj);
private: private:
class CompilationCacheTableVisitor; bool SameLiveness(HeapObject* obj1, HeapObject* obj2);
bool CanRecordFixedArray(FixedArrayBase* array);
bool IsCowArray(FixedArrayBase* array);
// Blacklist for objects that should not be recorded using
// VirtualObjectStats and RecordSimpleVirtualObjectStats. For recording those
// objects dispatch to the low level ObjectStats::RecordObjectStats manually.
bool ShouldRecordObject(HeapObject* object);
void RecordObjectStats(HeapObject* obj, InstanceType type, size_t size); void RecordObjectStats(HeapObject* obj, InstanceType type, size_t size);
void RecordBytecodeArrayDetails(BytecodeArray* obj);
void RecordCodeDetails(Code* code);
void RecordFixedArrayDetails(FixedArray* array);
void RecordJSCollectionDetails(JSObject* obj);
void RecordJSObjectDetails(JSObject* object);
void RecordJSWeakCollectionDetails(JSWeakCollection* obj);
void RecordMapDetails(Map* map);
void RecordScriptDetails(Script* obj);
void RecordTemplateInfoDetails(TemplateInfo* obj);
void RecordSharedFunctionInfoDetails(SharedFunctionInfo* sfi);
bool RecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype, size_t overhead);
void RecursivelyRecordFixedArrayHelper(HeapObject* parent, FixedArray* array,
int subtype);
template <class HashTable>
void RecordHashTableHelper(HeapObject* parent, HashTable* array, int subtype);
bool SameLiveness(HeapObject* obj1, HeapObject* obj2);
void RecordVirtualObjectStats(HeapObject* obj, void RecordVirtualObjectStats(HeapObject* parent, HeapObject* obj,
ObjectStats::VirtualInstanceType type, ObjectStats::VirtualInstanceType type,
size_t size); size_t size, size_t over_allocated);
// Gets size from |ob| and assumes no over allocating.
void RecordSimpleVirtualObjectStats(HeapObject* parent, HeapObject* obj,
ObjectStats::VirtualInstanceType type);
void RecordVirtualAllocationSiteDetails(AllocationSite* site); void RecordVirtualAllocationSiteDetails(AllocationSite* site);
void RecordVirtualFeedbackVectorDetails(FeedbackVector* site); void RecordVirtualBytecodeArrayDetails(BytecodeArray* bytecode);
void RecordVirtualCodeDetails(Code* code);
void RecordVirtualFeedbackVectorDetails(FeedbackVector* vector);
void RecordVirtualMapDetails(Map* map);
Heap* heap_; Heap* heap_;
ObjectStats* stats_; ObjectStats* stats_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_; MarkCompactCollector::NonAtomicMarkingState* marking_state_;
std::unordered_set<HeapObject*> virtual_objects_; std::unordered_set<HeapObject*> virtual_objects_;
friend class ObjectStatsCollectorImpl::CompilationCacheTableVisitor;
}; };
ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap, ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
...@@ -299,18 +244,27 @@ ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap, ...@@ -299,18 +244,27 @@ ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
marking_state_( marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()) {} heap->mark_compact_collector()->non_atomic_marking_state()) {}
// For entries which shared the same instance type (historically FixedArrays) bool ObjectStatsCollectorImpl::ShouldRecordObject(HeapObject* obj) {
// we do a pre-pass and create virtual instance types. if (obj->IsFixedArray()) {
void ObjectStatsCollectorImpl::CollectVirtualStatistics(HeapObject* obj) { FixedArray* fixed_array = FixedArray::cast(obj);
if (obj->IsAllocationSite()) { return CanRecordFixedArray(fixed_array) && !IsCowArray(fixed_array);
RecordVirtualAllocationSiteDetails(AllocationSite::cast(obj));
} else if (obj->IsFeedbackVector()) {
RecordVirtualFeedbackVectorDetails(FeedbackVector::cast(obj));
} }
if (obj == heap_->empty_property_array()) return false;
return true;
}
void ObjectStatsCollectorImpl::RecordSimpleVirtualObjectStats(
HeapObject* parent, HeapObject* obj,
ObjectStats::VirtualInstanceType type) {
RecordVirtualObjectStats(parent, obj, type, obj->Size(),
ObjectStats::kNoOverAllocation);
} }
void ObjectStatsCollectorImpl::RecordVirtualObjectStats( void ObjectStatsCollectorImpl::RecordVirtualObjectStats(
HeapObject* obj, ObjectStats::VirtualInstanceType type, size_t size) { HeapObject* parent, HeapObject* obj, ObjectStats::VirtualInstanceType type,
size_t size, size_t over_allocated) {
if (!SameLiveness(parent, obj) || !ShouldRecordObject(obj)) return;
#if DEBUG #if DEBUG
if (virtual_objects_.find(obj) != virtual_objects_.end()) { if (virtual_objects_.find(obj) != virtual_objects_.end()) {
std::stringstream description; std::stringstream description;
...@@ -321,7 +275,7 @@ void ObjectStatsCollectorImpl::RecordVirtualObjectStats( ...@@ -321,7 +275,7 @@ void ObjectStatsCollectorImpl::RecordVirtualObjectStats(
} }
#endif #endif
virtual_objects_.insert(obj); virtual_objects_.insert(obj);
stats_->RecordVirtualObjectStats(type, size); stats_->RecordVirtualObjectStats(type, size, over_allocated);
} }
void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails( void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails(
...@@ -329,34 +283,35 @@ void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails( ...@@ -329,34 +283,35 @@ void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails(
if (!site->PointsToLiteral()) return; if (!site->PointsToLiteral()) return;
JSObject* boilerplate = site->boilerplate(); JSObject* boilerplate = site->boilerplate();
if (boilerplate->IsJSArray()) { if (boilerplate->IsJSArray()) {
RecordVirtualObjectStats(boilerplate, RecordVirtualObjectStats(
ObjectStats::JS_ARRAY_BOILERPLATE_TYPE, site, boilerplate, ObjectStats::JS_ARRAY_BOILERPLATE_TYPE,
boilerplate->Size()); boilerplate->Size(), ObjectStats::kNoOverAllocation);
// Array boilerplates cannot have properties. // Array boilerplates cannot have properties.
} else { } else {
RecordVirtualObjectStats(boilerplate, RecordVirtualObjectStats(
ObjectStats::JS_OBJECT_BOILERPLATE_TYPE, site, boilerplate, ObjectStats::JS_OBJECT_BOILERPLATE_TYPE,
boilerplate->Size()); boilerplate->Size(), ObjectStats::kNoOverAllocation);
if (boilerplate->HasFastProperties()) { if (boilerplate->HasFastProperties()) {
// We'll misclassify the empty_proeprty_array here. Given that there is a // We'll mis-classify the empty_property_array here. Given that there is a
// single instance, this is neglible. // single instance, this is negligible.
PropertyArray* properties = boilerplate->property_array(); PropertyArray* properties = boilerplate->property_array();
RecordVirtualObjectStats(properties, RecordVirtualObjectStats(
ObjectStats::BOILERPLATE_PROPERTY_ARRAY_TYPE, site, properties, ObjectStats::BOILERPLATE_PROPERTY_ARRAY_TYPE,
properties->Size()); properties->Size(), ObjectStats::kNoOverAllocation);
} else { } else {
NameDictionary* properties = boilerplate->property_dictionary(); NameDictionary* properties = boilerplate->property_dictionary();
RecordVirtualObjectStats(properties, RecordVirtualObjectStats(
ObjectStats::BOILERPLATE_NAME_DICTIONARY_TYPE, site, properties, ObjectStats::BOILERPLATE_NAME_DICTIONARY_TYPE,
properties->Size()); properties->Size(), ObjectStats::kNoOverAllocation);
} }
} }
FixedArrayBase* elements = boilerplate->elements(); FixedArrayBase* elements = boilerplate->elements();
// We skip COW elements since they are shared, and we are sure that if the // We skip COW elements since they are shared, and we are sure that if the
// boilerplate exists there must have been at least one instantiation. // boilerplate exists there must have been at least one instantiation.
if (!elements->IsCowArray()) { if (!elements->IsCowArray()) {
RecordVirtualObjectStats(elements, ObjectStats::BOILERPLATE_ELEMENTS_TYPE, RecordVirtualObjectStats(site, elements,
elements->Size()); ObjectStats::BOILERPLATE_ELEMENTS_TYPE,
elements->Size(), ObjectStats::kNoOverAllocation);
} }
} }
...@@ -368,97 +323,74 @@ void ObjectStatsCollectorImpl::RecordVirtualFeedbackVectorDetails( ...@@ -368,97 +323,74 @@ void ObjectStatsCollectorImpl::RecordVirtualFeedbackVectorDetails(
if (!raw_object->IsHeapObject()) continue; if (!raw_object->IsHeapObject()) continue;
HeapObject* object = HeapObject::cast(raw_object); HeapObject* object = HeapObject::cast(raw_object);
if (object->IsCell() || object->IsFixedArray()) { if (object->IsCell() || object->IsFixedArray()) {
RecordVirtualObjectStats(object, ObjectStats::FEEDBACK_VECTOR_ENTRY_TYPE, RecordVirtualObjectStats(vector, object,
object->Size()); ObjectStats::FEEDBACK_VECTOR_ENTRY_TYPE,
object->Size(), ObjectStats::kNoOverAllocation);
} }
} }
} }
void ObjectStatsCollectorImpl::CollectStatistics(HeapObject* obj) { void ObjectStatsCollectorImpl::CollectStatistics(HeapObject* obj, Phase phase) {
Map* map = obj->map(); Map* map = obj->map();
switch (phase) {
// Record for the InstanceType. case kPhase1:
int object_size = obj->Size(); if (obj->IsFeedbackVector()) {
RecordObjectStats(obj, map->instance_type(), object_size); RecordVirtualFeedbackVectorDetails(FeedbackVector::cast(obj));
} else if (obj->IsMap()) {
// Record specific sub types where possible. RecordVirtualMapDetails(Map::cast(obj));
if (obj->IsMap()) RecordMapDetails(Map::cast(obj)); } else if (obj->IsBytecodeArray()) {
if (obj->IsObjectTemplateInfo() || obj->IsFunctionTemplateInfo()) { RecordVirtualBytecodeArrayDetails(BytecodeArray::cast(obj));
RecordTemplateInfoDetails(TemplateInfo::cast(obj)); } else if (obj->IsCode()) {
} RecordVirtualCodeDetails(Code::cast(obj));
if (obj->IsBytecodeArray()) { }
RecordBytecodeArrayDetails(BytecodeArray::cast(obj)); break;
} case kPhase2:
if (obj->IsCode()) RecordCodeDetails(Code::cast(obj)); RecordObjectStats(obj, map->instance_type(), obj->Size());
if (obj->IsSharedFunctionInfo()) { break;
RecordSharedFunctionInfoDetails(SharedFunctionInfo::cast(obj));
}
if (obj->IsFixedArray()) RecordFixedArrayDetails(FixedArray::cast(obj));
if (obj->IsJSObject()) RecordJSObjectDetails(JSObject::cast(obj));
if (obj->IsJSWeakCollection()) {
RecordJSWeakCollectionDetails(JSWeakCollection::cast(obj));
}
if (obj->IsJSCollection()) {
RecordJSCollectionDetails(JSObject::cast(obj));
} }
if (obj->IsScript()) RecordScriptDetails(Script::cast(obj));
} }
class ObjectStatsCollectorImpl::CompilationCacheTableVisitor void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
: public RootVisitor { // Iterate boilerplates first to disambiguate them from regular JS objects.
public: Object* list = heap_->allocation_sites_list();
explicit CompilationCacheTableVisitor(ObjectStatsCollectorImpl* parent) while (list->IsAllocationSite()) {
: parent_(parent) {} AllocationSite* site = AllocationSite::cast(list);
RecordVirtualAllocationSiteDetails(site);
void VisitRootPointers(Root root, Object** start, Object** end) override { list = site->weak_next();
for (Object** current = start; current < end; current++) {
HeapObject* obj = HeapObject::cast(*current);
if (obj->IsUndefined(parent_->heap_->isolate())) continue;
CHECK(obj->IsCompilationCacheTable());
parent_->RecordHashTableHelper(nullptr, CompilationCacheTable::cast(obj),
COMPILATION_CACHE_TABLE_SUB_TYPE);
}
} }
private:
ObjectStatsCollectorImpl* parent_;
};
void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
// Global FixedArrays. // Global FixedArrays.
RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(), RecordSimpleVirtualObjectStats(
WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0); nullptr, heap_->weak_new_space_object_to_code_list(),
RecordFixedArrayHelper(nullptr, heap_->serialized_objects(), ObjectStats::WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE);
SERIALIZED_OBJECTS_SUB_TYPE, 0); RecordSimpleVirtualObjectStats(nullptr, heap_->serialized_objects(),
RecordFixedArrayHelper(nullptr, heap_->number_string_cache(), ObjectStats::SERIALIZED_OBJECTS_TYPE);
NUMBER_STRING_CACHE_SUB_TYPE, 0); RecordSimpleVirtualObjectStats(nullptr, heap_->number_string_cache(),
RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(), ObjectStats::NUMBER_STRING_CACHE_TYPE);
SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE, 0); RecordSimpleVirtualObjectStats(
RecordFixedArrayHelper(nullptr, heap_->string_split_cache(), nullptr, heap_->single_character_string_cache(),
STRING_SPLIT_CACHE_SUB_TYPE, 0); ObjectStats::SINGLE_CHARACTER_STRING_CACHE_TYPE);
RecordFixedArrayHelper(nullptr, heap_->regexp_multiple_cache(), RecordSimpleVirtualObjectStats(nullptr, heap_->string_split_cache(),
REGEXP_MULTIPLE_CACHE_SUB_TYPE, 0); ObjectStats::STRING_SPLIT_CACHE_TYPE);
RecordFixedArrayHelper(nullptr, heap_->retained_maps(), RecordSimpleVirtualObjectStats(nullptr, heap_->regexp_multiple_cache(),
RETAINED_MAPS_SUB_TYPE, 0); ObjectStats::REGEXP_MULTIPLE_CACHE_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->retained_maps(),
ObjectStats::RETAINED_MAPS_TYPE);
// Global weak FixedArrays. // Global weak FixedArrays.
RecordFixedArrayHelper( RecordSimpleVirtualObjectStats(
nullptr, WeakFixedArray::cast(heap_->noscript_shared_function_infos()), nullptr, WeakFixedArray::cast(heap_->noscript_shared_function_infos()),
NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE, 0); ObjectStats::NOSCRIPT_SHARED_FUNCTION_INFOS_TYPE);
RecordFixedArrayHelper(nullptr, WeakFixedArray::cast(heap_->script_list()), RecordSimpleVirtualObjectStats(nullptr,
SCRIPT_LIST_SUB_TYPE, 0); WeakFixedArray::cast(heap_->script_list()),
ObjectStats::SCRIPT_LIST_TYPE);
// Global hash tables. // Global hash tables.
RecordHashTableHelper(nullptr, heap_->string_table(), STRING_TABLE_SUB_TYPE); // TODO(mlippautz):
RecordHashTableHelper(nullptr, heap_->weak_object_to_code_table(), // - heap_->string_table(): STRING_TABLE_TYPE
OBJECT_TO_CODE_SUB_TYPE); // - heap_->weak_object_to_code_table(): OBJECT_TO_CODE_TYPE
RecordHashTableHelper(nullptr, heap_->code_stubs(), // - heap_->code_stubs(): CODE_STUBS_TABLE_TYPE
CODE_STUBS_TABLE_SUB_TYPE); // - heap_->empty_property_dictionary(): EMPTY_PROPERTIES_DICTIONARY_TYPE
RecordHashTableHelper(nullptr, heap_->empty_property_dictionary(),
EMPTY_PROPERTIES_DICTIONARY_SUB_TYPE);
CompilationCache* compilation_cache = heap_->isolate()->compilation_cache();
CompilationCacheTableVisitor v(this);
compilation_cache->Iterate(&v);
} }
void ObjectStatsCollectorImpl::RecordObjectStats(HeapObject* obj, void ObjectStatsCollectorImpl::RecordObjectStats(HeapObject* obj,
...@@ -469,16 +401,16 @@ void ObjectStatsCollectorImpl::RecordObjectStats(HeapObject* obj, ...@@ -469,16 +401,16 @@ void ObjectStatsCollectorImpl::RecordObjectStats(HeapObject* obj,
} }
} }
static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { bool ObjectStatsCollectorImpl::CanRecordFixedArray(FixedArrayBase* array) {
return array->map()->instance_type() == FIXED_ARRAY_TYPE && return array->map()->instance_type() == FIXED_ARRAY_TYPE &&
array != heap->empty_fixed_array() && array != heap_->empty_fixed_array() &&
array != heap->empty_sloppy_arguments_elements() && array != heap_->empty_sloppy_arguments_elements() &&
array != heap->empty_slow_element_dictionary() && array != heap_->empty_slow_element_dictionary() &&
array != heap->empty_property_dictionary(); array != heap_->empty_property_dictionary();
} }
static bool IsCowArray(Heap* heap, FixedArrayBase* array) { bool ObjectStatsCollectorImpl::IsCowArray(FixedArrayBase* array) {
return array->map() == heap->fixed_cow_array_map(); return array->map() == heap_->fixed_cow_array_map();
} }
bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1, bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1,
...@@ -487,256 +419,93 @@ bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1, ...@@ -487,256 +419,93 @@ bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1,
marking_state_->Color(obj1) == marking_state_->Color(obj2); marking_state_->Color(obj1) == marking_state_->Color(obj2);
} }
bool ObjectStatsCollectorImpl::RecordFixedArrayHelper(HeapObject* parent, void ObjectStatsCollectorImpl::RecordVirtualMapDetails(Map* map) {
FixedArray* array, // TODO(mlippautz): map->dependent_code(): DEPENDENT_CODE_TYPE.
int subtype,
size_t overhead) {
if (SameLiveness(parent, array) && CanRecordFixedArray(heap_, array) &&
!IsCowArray(heap_, array)) {
return stats_->RecordFixedArraySubTypeStats(array, subtype, array->Size(),
overhead);
}
return false;
}
void ObjectStatsCollectorImpl::RecursivelyRecordFixedArrayHelper(
HeapObject* parent, FixedArray* array, int subtype) {
if (RecordFixedArrayHelper(parent, array, subtype, 0)) {
for (int i = 0; i < array->length(); i++) {
if (array->get(i)->IsFixedArray()) {
RecursivelyRecordFixedArrayHelper(
parent, FixedArray::cast(array->get(i)), subtype);
}
}
}
}
template <class HashTable>
void ObjectStatsCollectorImpl::RecordHashTableHelper(HeapObject* parent,
HashTable* array,
int subtype) {
int used = array->NumberOfElements() * HashTable::kEntrySize * kPointerSize;
CHECK_GE(array->Size(), used);
size_t overhead = array->Size() - used -
HashTable::kElementsStartIndex * kPointerSize -
FixedArray::kHeaderSize;
RecordFixedArrayHelper(parent, array, subtype, overhead);
}
void ObjectStatsCollectorImpl::RecordJSObjectDetails(JSObject* object) {
size_t overhead = 0;
FixedArrayBase* elements = object->elements();
if (CanRecordFixedArray(heap_, elements) && !IsCowArray(heap_, elements)) {
if (elements->IsDictionary() && SameLiveness(object, elements)) {
NumberDictionary* dict = NumberDictionary::cast(elements);
RecordHashTableHelper(object, dict, DICTIONARY_ELEMENTS_SUB_TYPE);
} else {
if (IsHoleyElementsKind(object->GetElementsKind())) {
int used = object->GetFastElementsUsage() * kPointerSize;
if (object->GetElementsKind() == HOLEY_DOUBLE_ELEMENTS) used *= 2;
CHECK_GE(elements->Size(), used);
overhead = elements->Size() - used - FixedArray::kHeaderSize;
}
stats_->RecordFixedArraySubTypeStats(elements, PACKED_ELEMENTS_SUB_TYPE,
elements->Size(), overhead);
}
}
if (object->IsJSGlobalObject()) {
GlobalDictionary* properties =
JSGlobalObject::cast(object)->global_dictionary();
if (CanRecordFixedArray(heap_, properties) &&
SameLiveness(object, properties)) {
RecordHashTableHelper(object, properties, DICTIONARY_PROPERTIES_SUB_TYPE);
}
} else if (!object->HasFastProperties()) {
NameDictionary* properties = object->property_dictionary();
if (CanRecordFixedArray(heap_, properties) &&
SameLiveness(object, properties)) {
RecordHashTableHelper(object, properties, DICTIONARY_PROPERTIES_SUB_TYPE);
}
}
}
void ObjectStatsCollectorImpl::RecordJSWeakCollectionDetails(
JSWeakCollection* obj) {
if (obj->table()->IsHashTable()) {
ObjectHashTable* table = ObjectHashTable::cast(obj->table());
int used = table->NumberOfElements() * ObjectHashTable::kEntrySize;
size_t overhead = table->Size() - used;
RecordFixedArrayHelper(obj, table, JS_WEAK_COLLECTION_SUB_TYPE, overhead);
}
}
void ObjectStatsCollectorImpl::RecordJSCollectionDetails(JSObject* obj) {
// The JS versions use a different HashTable implementation that cannot use
// the regular helper. Since overall impact is usually small just record
// without overhead.
if (obj->IsJSMap()) {
RecordFixedArrayHelper(nullptr, FixedArray::cast(JSMap::cast(obj)->table()),
JS_COLLECTION_SUB_TYPE, 0);
}
if (obj->IsJSSet()) {
RecordFixedArrayHelper(nullptr, FixedArray::cast(JSSet::cast(obj)->table()),
JS_COLLECTION_SUB_TYPE, 0);
}
}
void ObjectStatsCollectorImpl::RecordScriptDetails(Script* obj) { DescriptorArray* array = map->instance_descriptors();
FixedArray* infos = FixedArray::cast(obj->shared_function_infos()); if (map->owns_descriptors() && array != heap_->empty_descriptor_array()) {
RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0); // DescriptorArray has its own instance type.
}
void ObjectStatsCollectorImpl::RecordMapDetails(Map* map_obj) {
DescriptorArray* array = map_obj->instance_descriptors();
if (map_obj->owns_descriptors() && array != heap_->empty_descriptor_array() &&
SameLiveness(map_obj, array)) {
RecordFixedArrayHelper(map_obj, array, DESCRIPTOR_ARRAY_SUB_TYPE, 0);
EnumCache* enum_cache = array->GetEnumCache(); EnumCache* enum_cache = array->GetEnumCache();
RecordFixedArrayHelper(array, enum_cache->keys(), ENUM_CACHE_SUB_TYPE, 0); RecordSimpleVirtualObjectStats(array, enum_cache->keys(),
RecordFixedArrayHelper(array, enum_cache->indices(), ObjectStats::ENUM_CACHE_TYPE);
ENUM_INDICES_CACHE_SUB_TYPE, 0); RecordSimpleVirtualObjectStats(array, enum_cache->indices(),
} ObjectStats::ENUM_INDICES_CACHE_TYPE);
for (DependentCode* cur_dependent_code = map_obj->dependent_code();
cur_dependent_code != heap_->empty_fixed_array();
cur_dependent_code = DependentCode::cast(
cur_dependent_code->get(DependentCode::kNextLinkIndex))) {
RecordFixedArrayHelper(map_obj, cur_dependent_code, DEPENDENT_CODE_SUB_TYPE,
0);
} }
if (map_obj->is_prototype_map()) { if (map->is_prototype_map()) {
if (map_obj->prototype_info()->IsPrototypeInfo()) { if (map->prototype_info()->IsPrototypeInfo()) {
PrototypeInfo* info = PrototypeInfo::cast(map_obj->prototype_info()); PrototypeInfo* info = PrototypeInfo::cast(map->prototype_info());
Object* users = info->prototype_users(); Object* users = info->prototype_users();
if (users->IsWeakFixedArray()) { if (users->IsWeakFixedArray()) {
RecordFixedArrayHelper(map_obj, WeakFixedArray::cast(users), RecordSimpleVirtualObjectStats(map, WeakFixedArray::cast(users),
PROTOTYPE_USERS_SUB_TYPE, 0); ObjectStats::PROTOTYPE_USERS_TYPE);
} }
} }
} }
} }
void ObjectStatsCollectorImpl::RecordTemplateInfoDetails(TemplateInfo* obj) { void ObjectStatsCollectorImpl::RecordVirtualBytecodeArrayDetails(
if (obj->property_accessors()->IsFixedArray()) { BytecodeArray* bytecode) {
RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_accessors()), RecordVirtualObjectStats(bytecode, bytecode->constant_pool(),
TEMPLATE_INFO_SUB_TYPE, 0); ObjectStats::BYTECODE_ARRAY_CONSTANT_POOL_TYPE,
} bytecode->constant_pool()->Size(),
if (obj->property_list()->IsFixedArray()) { ObjectStats::kNoOverAllocation);
RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_list()), RecordVirtualObjectStats(bytecode, bytecode->handler_table(),
TEMPLATE_INFO_SUB_TYPE, 0); ObjectStats::BYTECODE_ARRAY_HANDLER_TABLE_TYPE,
} bytecode->constant_pool()->Size(),
ObjectStats::kNoOverAllocation);
} }
void ObjectStatsCollectorImpl::RecordBytecodeArrayDetails(BytecodeArray* obj) { namespace {
RecordFixedArrayHelper(obj, obj->constant_pool(),
BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE, 0);
RecordFixedArrayHelper(obj, obj->handler_table(),
BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE, 0);
}
void ObjectStatsCollectorImpl::RecordCodeDetails(Code* code) { ObjectStats::VirtualInstanceType CodeKindToVirtualInstanceType(
stats_->RecordCodeSubTypeStats(code->kind(), code->Size()); Code::Kind kind) {
RecordFixedArrayHelper(code, code->deoptimization_data(), switch (kind) {
DEOPTIMIZATION_DATA_SUB_TYPE, 0); #define CODE_KIND_CASE(type) \
if (code->kind() == Code::Kind::OPTIMIZED_FUNCTION) { case Code::type: \
DeoptimizationData* input_data = return ObjectStats::type;
DeoptimizationData::cast(code->deoptimization_data()); CODE_KIND_LIST(CODE_KIND_CASE)
if (input_data->length() > 0) { #undef CODE_KIND_CASE
RecordFixedArrayHelper(code->deoptimization_data(), default:
input_data->LiteralArray(), UNREACHABLE();
OPTIMIZED_CODE_LITERALS_SUB_TYPE, 0);
}
}
RecordFixedArrayHelper(code, code->handler_table(), HANDLER_TABLE_SUB_TYPE,
0);
int const mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (mode == RelocInfo::EMBEDDED_OBJECT) {
Object* target = it.rinfo()->target_object();
if (target->IsFixedArray()) {
RecursivelyRecordFixedArrayHelper(code, FixedArray::cast(target),
EMBEDDED_OBJECT_SUB_TYPE);
}
}
} }
UNREACHABLE();
} }
void ObjectStatsCollectorImpl::RecordSharedFunctionInfoDetails( } // namespace
SharedFunctionInfo* sfi) {
FixedArray* scope_info = sfi->scope_info();
RecordFixedArrayHelper(sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0);
FeedbackMetadata* feedback_metadata = sfi->feedback_metadata();
if (!feedback_metadata->is_empty()) {
RecordFixedArrayHelper(sfi, feedback_metadata, FEEDBACK_METADATA_SUB_TYPE,
0);
}
}
void ObjectStatsCollectorImpl::RecordFixedArrayDetails(FixedArray* array) { void ObjectStatsCollectorImpl::RecordVirtualCodeDetails(Code* code) {
if (array->IsContext()) { RecordVirtualObjectStats(nullptr, code,
RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 0); CodeKindToVirtualInstanceType(code->kind()),
} code->Size(), 0);
if (IsCowArray(heap_, array) && CanRecordFixedArray(heap_, array)) {
stats_->RecordFixedArraySubTypeStats(array, COPY_ON_WRITE_SUB_TYPE,
array->Size(), 0);
}
if (array->IsNativeContext()) {
Context* native_ctx = Context::cast(array);
RecordHashTableHelper(array,
native_ctx->slow_template_instantiations_cache(),
SLOW_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE);
FixedArray* fast_cache = native_ctx->fast_template_instantiations_cache();
stats_->RecordFixedArraySubTypeStats(
fast_cache, FAST_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE,
fast_cache->Size(), 0);
}
} }
class ObjectStatsVisitor { class ObjectStatsVisitor {
public: public:
enum CollectionMode {
kRegular,
kVirtual,
};
ObjectStatsVisitor(Heap* heap, ObjectStatsCollectorImpl* live_collector, ObjectStatsVisitor(Heap* heap, ObjectStatsCollectorImpl* live_collector,
ObjectStatsCollectorImpl* dead_collector, ObjectStatsCollectorImpl* dead_collector,
CollectionMode mode) ObjectStatsCollectorImpl::Phase phase)
: live_collector_(live_collector), : live_collector_(live_collector),
dead_collector_(dead_collector), dead_collector_(dead_collector),
marking_state_( marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()), heap->mark_compact_collector()->non_atomic_marking_state()),
mode_(mode) {} phase_(phase) {}
bool Visit(HeapObject* obj, int size) { bool Visit(HeapObject* obj, int size) {
if (marking_state_->IsBlack(obj)) { if (marking_state_->IsBlack(obj)) {
Collect(live_collector_, obj); live_collector_->CollectStatistics(obj, phase_);
} else { } else {
DCHECK(!marking_state_->IsGrey(obj)); DCHECK(!marking_state_->IsGrey(obj));
Collect(dead_collector_, obj); dead_collector_->CollectStatistics(obj, phase_);
} }
return true; return true;
} }
private: private:
void Collect(ObjectStatsCollectorImpl* collector, HeapObject* obj) {
switch (mode_) {
case kRegular:
collector->CollectStatistics(obj);
break;
case kVirtual:
collector->CollectVirtualStatistics(obj);
break;
}
}
ObjectStatsCollectorImpl* live_collector_; ObjectStatsCollectorImpl* live_collector_;
ObjectStatsCollectorImpl* dead_collector_; ObjectStatsCollectorImpl* dead_collector_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_; MarkCompactCollector::NonAtomicMarkingState* marking_state_;
CollectionMode mode_; ObjectStatsCollectorImpl::Phase phase_;
}; };
namespace { namespace {
...@@ -758,19 +527,10 @@ void IterateHeap(Heap* heap, ObjectStatsVisitor* visitor) { ...@@ -758,19 +527,10 @@ void IterateHeap(Heap* heap, ObjectStatsVisitor* visitor) {
void ObjectStatsCollector::Collect() { void ObjectStatsCollector::Collect() {
ObjectStatsCollectorImpl live_collector(heap_, live_); ObjectStatsCollectorImpl live_collector(heap_, live_);
ObjectStatsCollectorImpl dead_collector(heap_, dead_); ObjectStatsCollectorImpl dead_collector(heap_, dead_);
// 1. Collect system type otherwise indistinguishable from other types.
{
ObjectStatsVisitor visitor(heap_, &live_collector, &dead_collector,
ObjectStatsVisitor::kVirtual);
IterateHeap(heap_, &visitor);
}
// 2. Collect globals; only applies to live objects.
live_collector.CollectGlobalStatistics(); live_collector.CollectGlobalStatistics();
// 3. Collect rest. for (int i = 0; i < ObjectStatsCollectorImpl::kNumberOfPhases; i++) {
{
ObjectStatsVisitor visitor(heap_, &live_collector, &dead_collector, ObjectStatsVisitor visitor(heap_, &live_collector, &dead_collector,
ObjectStatsVisitor::kRegular); static_cast<ObjectStatsCollectorImpl::Phase>(i));
IterateHeap(heap_, &visitor); IterateHeap(heap_, &visitor);
} }
} }
......
...@@ -19,19 +19,37 @@ ...@@ -19,19 +19,37 @@
// tracing. // tracing.
// //
// Update LAST_VIRTUAL_TYPE below when changing this macro. // Update LAST_VIRTUAL_TYPE below when changing this macro.
#define VIRTUAL_INSTANCE_TYPE_LIST(V) \ #define VIRTUAL_INSTANCE_TYPE_LIST(V) \
V(BOILERPLATE_ELEMENTS_TYPE) \ CODE_KIND_LIST(V) \
V(BOILERPLATE_NAME_DICTIONARY_TYPE) \ V(BOILERPLATE_ELEMENTS_TYPE) \
V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \ V(BOILERPLATE_NAME_DICTIONARY_TYPE) \
V(FEEDBACK_VECTOR_ENTRY_TYPE) \ V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \
V(JS_ARRAY_BOILERPLATE_TYPE) \ V(BYTECODE_ARRAY_CONSTANT_POOL_TYPE) \
V(JS_OBJECT_BOILERPLATE_TYPE) V(BYTECODE_ARRAY_HANDLER_TABLE_TYPE) \
V(DEPENDENT_CODE_TYPE) \
V(ENUM_CACHE_TYPE) \
V(ENUM_INDICES_CACHE_TYPE) \
V(FEEDBACK_VECTOR_ENTRY_TYPE) \
V(JS_ARRAY_BOILERPLATE_TYPE) \
V(JS_OBJECT_BOILERPLATE_TYPE) \
V(NOSCRIPT_SHARED_FUNCTION_INFOS_TYPE) \
V(NUMBER_STRING_CACHE_TYPE) \
V(PROTOTYPE_USERS_TYPE) \
V(REGEXP_MULTIPLE_CACHE_TYPE) \
V(RETAINED_MAPS_TYPE) \
V(SCRIPT_LIST_TYPE) \
V(SERIALIZED_OBJECTS_TYPE) \
V(SINGLE_CHARACTER_STRING_CACHE_TYPE) \
V(STRING_SPLIT_CACHE_TYPE) \
V(WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE)
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class ObjectStats { class ObjectStats {
public: public:
static const size_t kNoOverAllocation = 0;
explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(); } explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(); }
// See description on VIRTUAL_INSTANCE_TYPE_LIST. // See description on VIRTUAL_INSTANCE_TYPE_LIST.
...@@ -39,18 +57,14 @@ class ObjectStats { ...@@ -39,18 +57,14 @@ class ObjectStats {
#define DEFINE_VIRTUAL_INSTANCE_TYPE(type) type, #define DEFINE_VIRTUAL_INSTANCE_TYPE(type) type,
VIRTUAL_INSTANCE_TYPE_LIST(DEFINE_VIRTUAL_INSTANCE_TYPE) VIRTUAL_INSTANCE_TYPE_LIST(DEFINE_VIRTUAL_INSTANCE_TYPE)
#undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE #undef DEFINE_FIXED_ARRAY_SUB_INSTANCE_TYPE
LAST_VIRTUAL_TYPE = JS_OBJECT_BOILERPLATE_TYPE, LAST_VIRTUAL_TYPE = WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE,
}; };
// ObjectStats are kept in two arrays, counts and sizes. Related stats are // ObjectStats are kept in two arrays, counts and sizes. Related stats are
// stored in a contiguous linear buffer. Stats groups are stored one after // stored in a contiguous linear buffer. Stats groups are stored one after
// another. // another.
enum { enum {
FIRST_CODE_KIND_SUB_TYPE = LAST_TYPE + 1, FIRST_VIRTUAL_TYPE = LAST_TYPE + 1,
FIRST_FIXED_ARRAY_SUB_TYPE =
FIRST_CODE_KIND_SUB_TYPE + Code::NUMBER_OF_KINDS,
FIRST_VIRTUAL_TYPE =
FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1,
OBJECT_STATS_COUNT = FIRST_VIRTUAL_TYPE + LAST_VIRTUAL_TYPE + 1, OBJECT_STATS_COUNT = FIRST_VIRTUAL_TYPE + LAST_VIRTUAL_TYPE + 1,
}; };
...@@ -61,10 +75,8 @@ class ObjectStats { ...@@ -61,10 +75,8 @@ class ObjectStats {
void CheckpointObjectStats(); void CheckpointObjectStats();
void RecordObjectStats(InstanceType type, size_t size); void RecordObjectStats(InstanceType type, size_t size);
void RecordVirtualObjectStats(VirtualInstanceType type, size_t size); void RecordVirtualObjectStats(VirtualInstanceType type, size_t size,
void RecordCodeSubTypeStats(int code_sub_type, size_t size); size_t over_allocated);
bool RecordFixedArraySubTypeStats(FixedArrayBase* array, int array_sub_type,
size_t size, size_t over_allocated);
size_t object_count_last_gc(size_t index) { size_t object_count_last_gc(size_t index) {
return object_counts_last_time_[index]; return object_counts_last_time_[index];
...@@ -106,8 +118,6 @@ class ObjectStats { ...@@ -106,8 +118,6 @@ class ObjectStats {
// Detailed histograms by InstanceType. // Detailed histograms by InstanceType.
size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets]; size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
std::set<FixedArrayBase*> visited_fixed_array_sub_types_;
}; };
class ObjectStatsCollector { class ObjectStatsCollector {
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
const CATEGORIES = new Map([ const CATEGORIES = new Map([
[ [
'user', new Set([ 'user', new Set([
'*FIXED_ARRAY_CONTEXT_SUB_TYPE',
'*FIXED_ARRAY_COPY_ON_WRITE_SUB_TYPE',
'*FIXED_ARRAY_DICTIONARY_PROPERTIES_SUB_TYPE',
'*FIXED_ARRAY_JS_COLLECTION_SUB_TYPE',
'*FIXED_ARRAY_JS_WEAK_COLLECTION_SUB_TYPE',
'*FIXED_ARRAY_PACKED_ELEMENTS_SUB_TYPE',
'CONS_ONE_BYTE_STRING_TYPE', 'CONS_ONE_BYTE_STRING_TYPE',
'CONS_STRING_TYPE', 'CONS_STRING_TYPE',
'DESCRIPTOR_ARRAY_TYPE', 'DESCRIPTOR_ARRAY_TYPE',
...@@ -89,20 +83,8 @@ const CATEGORIES = new Map([ ...@@ -89,20 +83,8 @@ const CATEGORIES = new Map([
'BYTE_ARRAY_TYPE', 'BYTE_ARRAY_TYPE',
'CELL_TYPE', 'CELL_TYPE',
'CONTEXT_EXTENSION_TYPE', 'CONTEXT_EXTENSION_TYPE',
'*FIXED_ARRAY_DEPENDENT_CODE_SUB_TYPE', 'ENUM_CACHE_TYPE',
'*FIXED_ARRAY_ENUM_CACHE_SUB_TYPE', 'ENUM_INDICES_CACHE_TYPE',
'*FIXED_ARRAY_ENUM_INDICES_CACHE_SUB_TYPE',
'*FIXED_ARRAY_FAST_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE',
'*FIXED_ARRAY_NUMBER_STRING_CACHE_SUB_TYPE',
'*FIXED_ARRAY_PROTOTYPE_USERS_SUB_TYPE',
'*FIXED_ARRAY_REGEXP_MULTIPLE_CACHE_SUB_TYPE',
'*FIXED_ARRAY_RETAINED_MAPS_SUB_TYPE',
'*FIXED_ARRAY_SCOPE_INFO_SUB_TYPE',
'*FIXED_ARRAY_SCRIPT_LIST_SUB_TYPE',
'*FIXED_ARRAY_SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE',
'*FIXED_ARRAY_STRING_SPLIT_CACHE_SUB_TYPE',
'*FIXED_ARRAY_TEMPLATE_INFO_SUB_TYPE',
'*FIXED_ARRAY_WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE',
'FOREIGN_TYPE', 'FOREIGN_TYPE',
'FUNCTION_TEMPLATE_INFO_TYPE', 'FUNCTION_TEMPLATE_INFO_TYPE',
'INTERCEPTOR_INFO_TYPE', 'INTERCEPTOR_INFO_TYPE',
...@@ -117,6 +99,7 @@ const CATEGORIES = new Map([ ...@@ -117,6 +99,7 @@ const CATEGORIES = new Map([
'PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE', 'PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE',
'PROPERTY_CELL_TYPE', 'PROPERTY_CELL_TYPE',
'PROTOTYPE_INFO_TYPE', 'PROTOTYPE_INFO_TYPE',
'PROTOTYPE_USERS_TYPE',
'STACK_FRAME_INFO_TYPE', 'STACK_FRAME_INFO_TYPE',
'TRANSITION_ARRAY_TYPE', 'TRANSITION_ARRAY_TYPE',
'WEAK_CELL_TYPE' 'WEAK_CELL_TYPE'
...@@ -124,21 +107,13 @@ const CATEGORIES = new Map([ ...@@ -124,21 +107,13 @@ const CATEGORIES = new Map([
], ],
[ [
'code', new Set([ 'code', new Set([
'*CODE_BUILTIN', 'BUILTIN',
'*CODE_BYTECODE_HANDLER', 'BYTECODE_HANDLER',
'*CODE_OPTIMIZED_FUNCTION', 'OPTIMIZED_FUNCTION',
'*CODE_REGEXP', 'REGEXP',
'*CODE_STUB', 'STUB',
'*FIXED_ARRAY_BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE', 'BYTECODE_ARRAY_CONSTANT_POOL_TYPE',
'*FIXED_ARRAY_BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE', 'BYTECODE_ARRAY_HANDLER_TABLE_TYPE',
'*FIXED_ARRAY_CODE_STUBS_TABLE_SUB_TYPE',
'*FIXED_ARRAY_COMPILATION_CACHE_TABLE_SUB_TYPE',
'*FIXED_ARRAY_DEOPTIMIZATION_DATA_SUB_TYPE',
'*FIXED_ARRAY_EMBEDDED_OBJECT_SUB_TYPE',
'*FIXED_ARRAY_HANDLER_TABLE_SUB_TYPE',
'*FIXED_ARRAY_NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE',
'*FIXED_ARRAY_OPTIMIZED_CODE_LITERALS_SUB_TYPE',
'*FIXED_ARRAY_SHARED_FUNCTION_INFOS_SUB_TYPE',
'BYTECODE_ARRAY_TYPE', 'BYTECODE_ARRAY_TYPE',
'CODE_DATA_CONTAINER_TYPE', 'CODE_DATA_CONTAINER_TYPE',
'FEEDBACK_VECTOR_ENTRY_TYPE', 'FEEDBACK_VECTOR_ENTRY_TYPE',
...@@ -159,10 +134,3 @@ const CATEGORY_NAMES = new Map([ ...@@ -159,10 +134,3 @@ const CATEGORY_NAMES = new Map([
['code', 'Code'], ['code', 'Code'],
['unclassified', 'Unclassified'], ['unclassified', 'Unclassified'],
]); ]);
// Instance types that are constructed from their sub types and
// should thus be hidden.
const IGNORED_INSTANCE_TYPES = new Set([
'FIXED_ARRAY_TYPE',
'CODE_TYPE',
]);
...@@ -178,7 +178,6 @@ class DetailsSelection extends HTMLElement { ...@@ -178,7 +178,6 @@ class DetailsSelection extends HTMLElement {
for (let instance_type of this.data[this.selection.isolate] for (let instance_type of this.data[this.selection.isolate]
.non_empty_instance_types) { .non_empty_instance_types) {
if (IGNORED_INSTANCE_TYPES.has(instance_type)) continue;
const category = this.categoryForType(instance_type); const category = this.categoryForType(instance_type);
categories[category].push(instance_type); categories[category].push(instance_type);
} }
......
...@@ -144,62 +144,6 @@ class TraceFileReader extends HTMLElement { ...@@ -144,62 +144,6 @@ class TraceFileReader extends HTMLElement {
} }
return 0; return 0;
}); });
let known_count = 0;
let known_overall = 0;
let known_histogram =
Array(
data_set.instance_type_data.FIXED_ARRAY_TYPE.histogram.length)
.fill(0);
let known_over_allocated = 0;
let known_over_allocated_histogram =
Array(data_set.instance_type_data.FIXED_ARRAY_TYPE
.over_allocated_histogram.length)
.fill(0);
for (const instance_type in data_set.instance_type_data) {
if (!instance_type.startsWith('*FIXED_ARRAY')) continue;
const subtype = data_set.instance_type_data[instance_type];
known_count += subtype.count;
known_overall += subtype.count;
known_over_allocated += subtype.over_allocated;
for (let i = 0; i < subtype.histogram.length; i++) {
known_histogram[i] += subtype.histogram[i];
}
for (let i = 0; i < subtype.over_allocated_histogram.length; i++) {
known_over_allocated_histogram[i] +=
subtype.over_allocated_histogram[i];
}
}
const fixed_array_data = data_set.instance_type_data.FIXED_ARRAY_TYPE;
const unknown_entry = {
count: fixed_array_data.count - known_count,
overall: fixed_array_data.overall - known_overall,
histogram: fixed_array_data.histogram.map(
(value, index) => value - known_histogram[index]),
over_allocated:
fixed_array_data.over_allocated - known_over_allocated,
over_allocated_histogram:
fixed_array_data.over_allocated_histogram.map(
(value, index) =>
value - known_over_allocated_histogram[index])
};
// Check for non-negative values.
checkNonNegativeProperty(unknown_entry, 'count');
checkNonNegativeProperty(unknown_entry, 'overall');
checkNonNegativeProperty(unknown_entry, 'over_allocated');
for (let i = 0; i < unknown_entry.histogram.length; i++) {
checkNonNegativeProperty(unknown_entry.histogram, i);
}
for (let i = 0; i < unknown_entry.over_allocated_histogram.length;
i++) {
checkNonNegativeProperty(unknown_entry.over_allocated_histogram, i);
}
this.addInstanceTypeData(
data, keys, isolate, gc, data_set_key,
'*FIXED_ARRAY_UNKNOWN_SUB_TYPE', unknown_entry);
} }
} }
} }
......
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