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,
return true;
INSTANCE_TYPE_LIST(COMPARE_AND_RETURN_NAME)
#undef COMPARE_AND_RETURN_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 ObjectStats::FIRST_FIXED_ARRAY_SUB_TYPE + name: \
*object_type = "FIXED_ARRAY_TYPE"; \
*object_sub_type = #name; \
#define COMPARE_AND_RETURN_NAME(name) \
case ObjectStats::FIRST_VIRTUAL_TYPE + ObjectStats::name: \
*object_type = #name; \
*object_sub_type = ""; \
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
}
return false;
......
......@@ -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_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
......@@ -99,23 +98,14 @@ void ObjectStats::PrintJSON(const char* key) {
#define INSTANCE_TYPE_WRAPPER(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) \
PrintInstanceTypeJSON(key, gc_count, #name, FIRST_VIRTUAL_TYPE + name);
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)
#undef INSTANCE_TYPE_WRAPPER
#undef CODE_KIND_WRAPPER
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
#undef VIRTUAL_INSTANCE_TYPE_WRAPPER
}
......@@ -150,25 +140,15 @@ void ObjectStats::Dump(std::stringstream& stream) {
stream << "\"type_data\":{";
#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) \
DumpInstanceTypeData(stream, #name, FIRST_VIRTUAL_TYPE + name);
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)
stream << "\"END\":{}}}";
#undef INSTANCE_TYPE_WRAPPER
#undef CODE_KIND_WRAPPER
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
#undef VIRTUAL_INSTANCE_TYPE_WRAPPER
}
......@@ -202,94 +182,59 @@ void ObjectStats::RecordObjectStats(InstanceType type, size_t size) {
}
void ObjectStats::RecordVirtualObjectStats(VirtualInstanceType type,
size_t size) {
size_t size, size_t over_allocated) {
DCHECK_LE(type, LAST_VIRTUAL_TYPE);
object_counts_[FIRST_VIRTUAL_TYPE + type]++;
object_sizes_[FIRST_VIRTUAL_TYPE + type] += size;
size_histogram_[FIRST_VIRTUAL_TYPE + type][HistogramIndexFromSize(size)]++;
}
void ObjectStats::RecordCodeSubTypeStats(int code_sub_type, size_t 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;
over_allocated_[FIRST_VIRTUAL_TYPE + type] += over_allocated;
over_allocated_histogram_[FIRST_VIRTUAL_TYPE + type]
[HistogramIndexFromSize(size)]++;
}
Isolate* ObjectStats::isolate() { return heap()->isolate(); }
class ObjectStatsCollectorImpl {
public:
enum Phase {
kPhase1,
kPhase2,
};
static const int kNumberOfPhases = kPhase2 + 1;
ObjectStatsCollectorImpl(Heap* heap, ObjectStats* stats);
void CollectGlobalStatistics();
// Collects statistics of objects for virtual instance types.
void CollectVirtualStatistics(HeapObject* obj);
// Collects statistics of objects for regular instance types.
void CollectStatistics(HeapObject* obj);
void CollectStatistics(HeapObject* obj, Phase phase);
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 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,
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 RecordVirtualFeedbackVectorDetails(FeedbackVector* site);
void RecordVirtualBytecodeArrayDetails(BytecodeArray* bytecode);
void RecordVirtualCodeDetails(Code* code);
void RecordVirtualFeedbackVectorDetails(FeedbackVector* vector);
void RecordVirtualMapDetails(Map* map);
Heap* heap_;
ObjectStats* stats_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
std::unordered_set<HeapObject*> virtual_objects_;
friend class ObjectStatsCollectorImpl::CompilationCacheTableVisitor;
};
ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
......@@ -299,18 +244,27 @@ ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()) {}
// For entries which shared the same instance type (historically FixedArrays)
// we do a pre-pass and create virtual instance types.
void ObjectStatsCollectorImpl::CollectVirtualStatistics(HeapObject* obj) {
if (obj->IsAllocationSite()) {
RecordVirtualAllocationSiteDetails(AllocationSite::cast(obj));
} else if (obj->IsFeedbackVector()) {
RecordVirtualFeedbackVectorDetails(FeedbackVector::cast(obj));
bool ObjectStatsCollectorImpl::ShouldRecordObject(HeapObject* obj) {
if (obj->IsFixedArray()) {
FixedArray* fixed_array = FixedArray::cast(obj);
return CanRecordFixedArray(fixed_array) && !IsCowArray(fixed_array);
}
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(
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 (virtual_objects_.find(obj) != virtual_objects_.end()) {
std::stringstream description;
......@@ -321,7 +275,7 @@ void ObjectStatsCollectorImpl::RecordVirtualObjectStats(
}
#endif
virtual_objects_.insert(obj);
stats_->RecordVirtualObjectStats(type, size);
stats_->RecordVirtualObjectStats(type, size, over_allocated);
}
void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails(
......@@ -329,34 +283,35 @@ void ObjectStatsCollectorImpl::RecordVirtualAllocationSiteDetails(
if (!site->PointsToLiteral()) return;
JSObject* boilerplate = site->boilerplate();
if (boilerplate->IsJSArray()) {
RecordVirtualObjectStats(boilerplate,
ObjectStats::JS_ARRAY_BOILERPLATE_TYPE,
boilerplate->Size());
RecordVirtualObjectStats(
site, boilerplate, ObjectStats::JS_ARRAY_BOILERPLATE_TYPE,
boilerplate->Size(), ObjectStats::kNoOverAllocation);
// Array boilerplates cannot have properties.
} else {
RecordVirtualObjectStats(boilerplate,
ObjectStats::JS_OBJECT_BOILERPLATE_TYPE,
boilerplate->Size());
RecordVirtualObjectStats(
site, boilerplate, ObjectStats::JS_OBJECT_BOILERPLATE_TYPE,
boilerplate->Size(), ObjectStats::kNoOverAllocation);
if (boilerplate->HasFastProperties()) {
// We'll misclassify the empty_proeprty_array here. Given that there is a
// single instance, this is neglible.
// We'll mis-classify the empty_property_array here. Given that there is a
// single instance, this is negligible.
PropertyArray* properties = boilerplate->property_array();
RecordVirtualObjectStats(properties,
ObjectStats::BOILERPLATE_PROPERTY_ARRAY_TYPE,
properties->Size());
RecordVirtualObjectStats(
site, properties, ObjectStats::BOILERPLATE_PROPERTY_ARRAY_TYPE,
properties->Size(), ObjectStats::kNoOverAllocation);
} else {
NameDictionary* properties = boilerplate->property_dictionary();
RecordVirtualObjectStats(properties,
ObjectStats::BOILERPLATE_NAME_DICTIONARY_TYPE,
properties->Size());
RecordVirtualObjectStats(
site, properties, ObjectStats::BOILERPLATE_NAME_DICTIONARY_TYPE,
properties->Size(), ObjectStats::kNoOverAllocation);
}
}
FixedArrayBase* elements = boilerplate->elements();
// 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.
if (!elements->IsCowArray()) {
RecordVirtualObjectStats(elements, ObjectStats::BOILERPLATE_ELEMENTS_TYPE,
elements->Size());
RecordVirtualObjectStats(site, elements,
ObjectStats::BOILERPLATE_ELEMENTS_TYPE,
elements->Size(), ObjectStats::kNoOverAllocation);
}
}
......@@ -368,97 +323,74 @@ void ObjectStatsCollectorImpl::RecordVirtualFeedbackVectorDetails(
if (!raw_object->IsHeapObject()) continue;
HeapObject* object = HeapObject::cast(raw_object);
if (object->IsCell() || object->IsFixedArray()) {
RecordVirtualObjectStats(object, ObjectStats::FEEDBACK_VECTOR_ENTRY_TYPE,
object->Size());
RecordVirtualObjectStats(vector, object,
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();
// Record for the InstanceType.
int object_size = obj->Size();
RecordObjectStats(obj, map->instance_type(), object_size);
// Record specific sub types where possible.
if (obj->IsMap()) RecordMapDetails(Map::cast(obj));
if (obj->IsObjectTemplateInfo() || obj->IsFunctionTemplateInfo()) {
RecordTemplateInfoDetails(TemplateInfo::cast(obj));
}
if (obj->IsBytecodeArray()) {
RecordBytecodeArrayDetails(BytecodeArray::cast(obj));
}
if (obj->IsCode()) RecordCodeDetails(Code::cast(obj));
if (obj->IsSharedFunctionInfo()) {
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));
switch (phase) {
case kPhase1:
if (obj->IsFeedbackVector()) {
RecordVirtualFeedbackVectorDetails(FeedbackVector::cast(obj));
} else if (obj->IsMap()) {
RecordVirtualMapDetails(Map::cast(obj));
} else if (obj->IsBytecodeArray()) {
RecordVirtualBytecodeArrayDetails(BytecodeArray::cast(obj));
} else if (obj->IsCode()) {
RecordVirtualCodeDetails(Code::cast(obj));
}
break;
case kPhase2:
RecordObjectStats(obj, map->instance_type(), obj->Size());
break;
}
if (obj->IsScript()) RecordScriptDetails(Script::cast(obj));
}
class ObjectStatsCollectorImpl::CompilationCacheTableVisitor
: public RootVisitor {
public:
explicit CompilationCacheTableVisitor(ObjectStatsCollectorImpl* parent)
: parent_(parent) {}
void VisitRootPointers(Root root, Object** start, Object** end) override {
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);
}
void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
// Iterate boilerplates first to disambiguate them from regular JS objects.
Object* list = heap_->allocation_sites_list();
while (list->IsAllocationSite()) {
AllocationSite* site = AllocationSite::cast(list);
RecordVirtualAllocationSiteDetails(site);
list = site->weak_next();
}
private:
ObjectStatsCollectorImpl* parent_;
};
void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
// Global FixedArrays.
RecordFixedArrayHelper(nullptr, heap_->weak_new_space_object_to_code_list(),
WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->serialized_objects(),
SERIALIZED_OBJECTS_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->number_string_cache(),
NUMBER_STRING_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->single_character_string_cache(),
SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->string_split_cache(),
STRING_SPLIT_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->regexp_multiple_cache(),
REGEXP_MULTIPLE_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, heap_->retained_maps(),
RETAINED_MAPS_SUB_TYPE, 0);
RecordSimpleVirtualObjectStats(
nullptr, heap_->weak_new_space_object_to_code_list(),
ObjectStats::WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->serialized_objects(),
ObjectStats::SERIALIZED_OBJECTS_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->number_string_cache(),
ObjectStats::NUMBER_STRING_CACHE_TYPE);
RecordSimpleVirtualObjectStats(
nullptr, heap_->single_character_string_cache(),
ObjectStats::SINGLE_CHARACTER_STRING_CACHE_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->string_split_cache(),
ObjectStats::STRING_SPLIT_CACHE_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->regexp_multiple_cache(),
ObjectStats::REGEXP_MULTIPLE_CACHE_TYPE);
RecordSimpleVirtualObjectStats(nullptr, heap_->retained_maps(),
ObjectStats::RETAINED_MAPS_TYPE);
// Global weak FixedArrays.
RecordFixedArrayHelper(
RecordSimpleVirtualObjectStats(
nullptr, WeakFixedArray::cast(heap_->noscript_shared_function_infos()),
NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
RecordFixedArrayHelper(nullptr, WeakFixedArray::cast(heap_->script_list()),
SCRIPT_LIST_SUB_TYPE, 0);
ObjectStats::NOSCRIPT_SHARED_FUNCTION_INFOS_TYPE);
RecordSimpleVirtualObjectStats(nullptr,
WeakFixedArray::cast(heap_->script_list()),
ObjectStats::SCRIPT_LIST_TYPE);
// Global hash tables.
RecordHashTableHelper(nullptr, heap_->string_table(), STRING_TABLE_SUB_TYPE);
RecordHashTableHelper(nullptr, heap_->weak_object_to_code_table(),
OBJECT_TO_CODE_SUB_TYPE);
RecordHashTableHelper(nullptr, heap_->code_stubs(),
CODE_STUBS_TABLE_SUB_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);
// TODO(mlippautz):
// - heap_->string_table(): STRING_TABLE_TYPE
// - heap_->weak_object_to_code_table(): OBJECT_TO_CODE_TYPE
// - heap_->code_stubs(): CODE_STUBS_TABLE_TYPE
// - heap_->empty_property_dictionary(): EMPTY_PROPERTIES_DICTIONARY_TYPE
}
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 &&
array != heap->empty_fixed_array() &&
array != heap->empty_sloppy_arguments_elements() &&
array != heap->empty_slow_element_dictionary() &&
array != heap->empty_property_dictionary();
array != heap_->empty_fixed_array() &&
array != heap_->empty_sloppy_arguments_elements() &&
array != heap_->empty_slow_element_dictionary() &&
array != heap_->empty_property_dictionary();
}
static bool IsCowArray(Heap* heap, FixedArrayBase* array) {
return array->map() == heap->fixed_cow_array_map();
bool ObjectStatsCollectorImpl::IsCowArray(FixedArrayBase* array) {
return array->map() == heap_->fixed_cow_array_map();
}
bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1,
......@@ -487,256 +419,93 @@ bool ObjectStatsCollectorImpl::SameLiveness(HeapObject* obj1,
marking_state_->Color(obj1) == marking_state_->Color(obj2);
}
bool ObjectStatsCollectorImpl::RecordFixedArrayHelper(HeapObject* parent,
FixedArray* array,
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::RecordVirtualMapDetails(Map* map) {
// TODO(mlippautz): map->dependent_code(): DEPENDENT_CODE_TYPE.
void ObjectStatsCollectorImpl::RecordScriptDetails(Script* obj) {
FixedArray* infos = FixedArray::cast(obj->shared_function_infos());
RecordFixedArrayHelper(obj, infos, SHARED_FUNCTION_INFOS_SUB_TYPE, 0);
}
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);
DescriptorArray* array = map->instance_descriptors();
if (map->owns_descriptors() && array != heap_->empty_descriptor_array()) {
// DescriptorArray has its own instance type.
EnumCache* enum_cache = array->GetEnumCache();
RecordFixedArrayHelper(array, enum_cache->keys(), ENUM_CACHE_SUB_TYPE, 0);
RecordFixedArrayHelper(array, enum_cache->indices(),
ENUM_INDICES_CACHE_SUB_TYPE, 0);
}
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);
RecordSimpleVirtualObjectStats(array, enum_cache->keys(),
ObjectStats::ENUM_CACHE_TYPE);
RecordSimpleVirtualObjectStats(array, enum_cache->indices(),
ObjectStats::ENUM_INDICES_CACHE_TYPE);
}
if (map_obj->is_prototype_map()) {
if (map_obj->prototype_info()->IsPrototypeInfo()) {
PrototypeInfo* info = PrototypeInfo::cast(map_obj->prototype_info());
if (map->is_prototype_map()) {
if (map->prototype_info()->IsPrototypeInfo()) {
PrototypeInfo* info = PrototypeInfo::cast(map->prototype_info());
Object* users = info->prototype_users();
if (users->IsWeakFixedArray()) {
RecordFixedArrayHelper(map_obj, WeakFixedArray::cast(users),
PROTOTYPE_USERS_SUB_TYPE, 0);
RecordSimpleVirtualObjectStats(map, WeakFixedArray::cast(users),
ObjectStats::PROTOTYPE_USERS_TYPE);
}
}
}
}
void ObjectStatsCollectorImpl::RecordTemplateInfoDetails(TemplateInfo* obj) {
if (obj->property_accessors()->IsFixedArray()) {
RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_accessors()),
TEMPLATE_INFO_SUB_TYPE, 0);
}
if (obj->property_list()->IsFixedArray()) {
RecordFixedArrayHelper(obj, FixedArray::cast(obj->property_list()),
TEMPLATE_INFO_SUB_TYPE, 0);
}
void ObjectStatsCollectorImpl::RecordVirtualBytecodeArrayDetails(
BytecodeArray* bytecode) {
RecordVirtualObjectStats(bytecode, bytecode->constant_pool(),
ObjectStats::BYTECODE_ARRAY_CONSTANT_POOL_TYPE,
bytecode->constant_pool()->Size(),
ObjectStats::kNoOverAllocation);
RecordVirtualObjectStats(bytecode, bytecode->handler_table(),
ObjectStats::BYTECODE_ARRAY_HANDLER_TABLE_TYPE,
bytecode->constant_pool()->Size(),
ObjectStats::kNoOverAllocation);
}
void ObjectStatsCollectorImpl::RecordBytecodeArrayDetails(BytecodeArray* obj) {
RecordFixedArrayHelper(obj, obj->constant_pool(),
BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE, 0);
RecordFixedArrayHelper(obj, obj->handler_table(),
BYTECODE_ARRAY_HANDLER_TABLE_SUB_TYPE, 0);
}
namespace {
void ObjectStatsCollectorImpl::RecordCodeDetails(Code* code) {
stats_->RecordCodeSubTypeStats(code->kind(), code->Size());
RecordFixedArrayHelper(code, code->deoptimization_data(),
DEOPTIMIZATION_DATA_SUB_TYPE, 0);
if (code->kind() == Code::Kind::OPTIMIZED_FUNCTION) {
DeoptimizationData* input_data =
DeoptimizationData::cast(code->deoptimization_data());
if (input_data->length() > 0) {
RecordFixedArrayHelper(code->deoptimization_data(),
input_data->LiteralArray(),
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);
}
}
ObjectStats::VirtualInstanceType CodeKindToVirtualInstanceType(
Code::Kind kind) {
switch (kind) {
#define CODE_KIND_CASE(type) \
case Code::type: \
return ObjectStats::type;
CODE_KIND_LIST(CODE_KIND_CASE)
#undef CODE_KIND_CASE
default:
UNREACHABLE();
}
UNREACHABLE();
}
void ObjectStatsCollectorImpl::RecordSharedFunctionInfoDetails(
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);
}
}
} // namespace
void ObjectStatsCollectorImpl::RecordFixedArrayDetails(FixedArray* array) {
if (array->IsContext()) {
RecordFixedArrayHelper(nullptr, array, CONTEXT_SUB_TYPE, 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);
}
void ObjectStatsCollectorImpl::RecordVirtualCodeDetails(Code* code) {
RecordVirtualObjectStats(nullptr, code,
CodeKindToVirtualInstanceType(code->kind()),
code->Size(), 0);
}
class ObjectStatsVisitor {
public:
enum CollectionMode {
kRegular,
kVirtual,
};
ObjectStatsVisitor(Heap* heap, ObjectStatsCollectorImpl* live_collector,
ObjectStatsCollectorImpl* dead_collector,
CollectionMode mode)
ObjectStatsCollectorImpl::Phase phase)
: live_collector_(live_collector),
dead_collector_(dead_collector),
marking_state_(
heap->mark_compact_collector()->non_atomic_marking_state()),
mode_(mode) {}
phase_(phase) {}
bool Visit(HeapObject* obj, int size) {
if (marking_state_->IsBlack(obj)) {
Collect(live_collector_, obj);
live_collector_->CollectStatistics(obj, phase_);
} else {
DCHECK(!marking_state_->IsGrey(obj));
Collect(dead_collector_, obj);
dead_collector_->CollectStatistics(obj, phase_);
}
return true;
}
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* dead_collector_;
MarkCompactCollector::NonAtomicMarkingState* marking_state_;
CollectionMode mode_;
ObjectStatsCollectorImpl::Phase phase_;
};
namespace {
......@@ -758,19 +527,10 @@ void IterateHeap(Heap* heap, ObjectStatsVisitor* visitor) {
void ObjectStatsCollector::Collect() {
ObjectStatsCollectorImpl live_collector(heap_, live_);
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();
// 3. Collect rest.
{
for (int i = 0; i < ObjectStatsCollectorImpl::kNumberOfPhases; i++) {
ObjectStatsVisitor visitor(heap_, &live_collector, &dead_collector,
ObjectStatsVisitor::kRegular);
static_cast<ObjectStatsCollectorImpl::Phase>(i));
IterateHeap(heap_, &visitor);
}
}
......
......@@ -19,19 +19,37 @@
// tracing.
//
// Update LAST_VIRTUAL_TYPE below when changing this macro.
#define VIRTUAL_INSTANCE_TYPE_LIST(V) \
V(BOILERPLATE_ELEMENTS_TYPE) \
V(BOILERPLATE_NAME_DICTIONARY_TYPE) \
V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \
V(FEEDBACK_VECTOR_ENTRY_TYPE) \
V(JS_ARRAY_BOILERPLATE_TYPE) \
V(JS_OBJECT_BOILERPLATE_TYPE)
#define VIRTUAL_INSTANCE_TYPE_LIST(V) \
CODE_KIND_LIST(V) \
V(BOILERPLATE_ELEMENTS_TYPE) \
V(BOILERPLATE_NAME_DICTIONARY_TYPE) \
V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \
V(BYTECODE_ARRAY_CONSTANT_POOL_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 internal {
class ObjectStats {
public:
static const size_t kNoOverAllocation = 0;
explicit ObjectStats(Heap* heap) : heap_(heap) { ClearObjectStats(); }
// See description on VIRTUAL_INSTANCE_TYPE_LIST.
......@@ -39,18 +57,14 @@ class ObjectStats {
#define DEFINE_VIRTUAL_INSTANCE_TYPE(type) type,
VIRTUAL_INSTANCE_TYPE_LIST(DEFINE_VIRTUAL_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
// 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_VIRTUAL_TYPE =
FIRST_FIXED_ARRAY_SUB_TYPE + LAST_FIXED_ARRAY_SUB_TYPE + 1,
FIRST_VIRTUAL_TYPE = LAST_TYPE + 1,
OBJECT_STATS_COUNT = FIRST_VIRTUAL_TYPE + LAST_VIRTUAL_TYPE + 1,
};
......@@ -61,10 +75,8 @@ class ObjectStats {
void CheckpointObjectStats();
void RecordObjectStats(InstanceType type, size_t size);
void RecordVirtualObjectStats(VirtualInstanceType type, size_t size);
void RecordCodeSubTypeStats(int code_sub_type, size_t size);
bool RecordFixedArraySubTypeStats(FixedArrayBase* array, int array_sub_type,
size_t size, size_t over_allocated);
void RecordVirtualObjectStats(VirtualInstanceType type, size_t size,
size_t over_allocated);
size_t object_count_last_gc(size_t index) {
return object_counts_last_time_[index];
......@@ -106,8 +118,6 @@ class ObjectStats {
// Detailed histograms by InstanceType.
size_t size_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
size_t over_allocated_histogram_[OBJECT_STATS_COUNT][kNumberOfBuckets];
std::set<FixedArrayBase*> visited_fixed_array_sub_types_;
};
class ObjectStatsCollector {
......
......@@ -6,12 +6,6 @@
const CATEGORIES = new Map([
[
'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_STRING_TYPE',
'DESCRIPTOR_ARRAY_TYPE',
......@@ -89,20 +83,8 @@ const CATEGORIES = new Map([
'BYTE_ARRAY_TYPE',
'CELL_TYPE',
'CONTEXT_EXTENSION_TYPE',
'*FIXED_ARRAY_DEPENDENT_CODE_SUB_TYPE',
'*FIXED_ARRAY_ENUM_CACHE_SUB_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',
'ENUM_CACHE_TYPE',
'ENUM_INDICES_CACHE_TYPE',
'FOREIGN_TYPE',
'FUNCTION_TEMPLATE_INFO_TYPE',
'INTERCEPTOR_INFO_TYPE',
......@@ -117,6 +99,7 @@ const CATEGORIES = new Map([
'PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE',
'PROPERTY_CELL_TYPE',
'PROTOTYPE_INFO_TYPE',
'PROTOTYPE_USERS_TYPE',
'STACK_FRAME_INFO_TYPE',
'TRANSITION_ARRAY_TYPE',
'WEAK_CELL_TYPE'
......@@ -124,21 +107,13 @@ const CATEGORIES = new Map([
],
[
'code', new Set([
'*CODE_BUILTIN',
'*CODE_BYTECODE_HANDLER',
'*CODE_OPTIMIZED_FUNCTION',
'*CODE_REGEXP',
'*CODE_STUB',
'*FIXED_ARRAY_BYTECODE_ARRAY_CONSTANT_POOL_SUB_TYPE',
'*FIXED_ARRAY_BYTECODE_ARRAY_HANDLER_TABLE_SUB_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',
'BUILTIN',
'BYTECODE_HANDLER',
'OPTIMIZED_FUNCTION',
'REGEXP',
'STUB',
'BYTECODE_ARRAY_CONSTANT_POOL_TYPE',
'BYTECODE_ARRAY_HANDLER_TABLE_TYPE',
'BYTECODE_ARRAY_TYPE',
'CODE_DATA_CONTAINER_TYPE',
'FEEDBACK_VECTOR_ENTRY_TYPE',
......@@ -159,10 +134,3 @@ const CATEGORY_NAMES = new Map([
['code', 'Code'],
['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 {
for (let instance_type of this.data[this.selection.isolate]
.non_empty_instance_types) {
if (IGNORED_INSTANCE_TYPES.has(instance_type)) continue;
const category = this.categoryForType(instance_type);
categories[category].push(instance_type);
}
......
......@@ -144,62 +144,6 @@ class TraceFileReader extends HTMLElement {
}
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