[heap] Various improvements to GC stats.
This CL contains a bunch of different improvements to the existing object stats, namely: - Introduce DEPRECATED_DESCRIPTOR_ARRAY_TYPE virtual instance type to also estimate the memory overhead of DescriptorArrays for deprecated Maps. - Do proper over-allocation computating for inobject fields in JSObjects. - Introduce OBJECT_PROPERTY_ARRAY_TYPE virtual instance type and properly compute over-allocation for PropertyArrays - Compute over-allocation for JSObject/JSArray elements properly. - Correctly report JSFunction and JSCollection like the other JSObjects, specifically report over-allocation properly for the instances itself and for the elements/properties backing stores. - Implement correct over-allocation computation for hash tables in ObjectStatsCollectorImpl::RecordHashTableVirtualObjectStats(). Bug: v8:7266 Change-Id: I9cadd703266dc90911a8e7420c3b00dcee82b06d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1557139 Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Auto-Submit: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#60683}
This commit is contained in:
parent
453e86df6a
commit
f8e3b1d612
@ -18,6 +18,7 @@
|
||||
#include "src/memcopy.h"
|
||||
#include "src/objects/compilation-cache-inl.h"
|
||||
#include "src/objects/heap-object.h"
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/js-collection-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/slots.h"
|
||||
@ -310,11 +311,14 @@ int ObjectStats::HistogramIndexFromSize(size_t size) {
|
||||
kLastValueBucketIndex);
|
||||
}
|
||||
|
||||
void ObjectStats::RecordObjectStats(InstanceType type, size_t size) {
|
||||
void ObjectStats::RecordObjectStats(InstanceType type, size_t size,
|
||||
size_t over_allocated) {
|
||||
DCHECK_LE(type, LAST_TYPE);
|
||||
object_counts_[type]++;
|
||||
object_sizes_[type] += size;
|
||||
size_histogram_[type][HistogramIndexFromSize(size)]++;
|
||||
over_allocated_[type] += over_allocated;
|
||||
over_allocated_histogram_[type][HistogramIndexFromSize(size)]++;
|
||||
}
|
||||
|
||||
void ObjectStats::RecordVirtualObjectStats(VirtualInstanceType type,
|
||||
@ -366,7 +370,7 @@ class ObjectStatsCollectorImpl {
|
||||
ObjectStats::VirtualInstanceType type);
|
||||
// For HashTable it is possible to compute over allocated memory.
|
||||
void RecordHashTableVirtualObjectStats(HeapObject parent,
|
||||
FixedArray hash_table,
|
||||
HashTableBase hash_table,
|
||||
ObjectStats::VirtualInstanceType type);
|
||||
|
||||
bool SameLiveness(HeapObject obj1, HeapObject obj2);
|
||||
@ -378,7 +382,9 @@ class ObjectStatsCollectorImpl {
|
||||
// objects dispatch to the low level ObjectStats::RecordObjectStats manually.
|
||||
bool ShouldRecordObject(HeapObject object, CowMode check_cow_array);
|
||||
|
||||
void RecordObjectStats(HeapObject obj, InstanceType type, size_t size);
|
||||
void RecordObjectStats(
|
||||
HeapObject obj, InstanceType type, size_t size,
|
||||
size_t over_allocated = ObjectStats::kNoOverAllocation);
|
||||
|
||||
// Specific recursion into constant pool or embedded code objects. Records
|
||||
// FixedArrays and Tuple2.
|
||||
@ -395,13 +401,11 @@ class ObjectStatsCollectorImpl {
|
||||
void RecordVirtualFixedArrayDetails(FixedArray array);
|
||||
void RecordVirtualFunctionTemplateInfoDetails(FunctionTemplateInfo fti);
|
||||
void RecordVirtualJSGlobalObjectDetails(JSGlobalObject object);
|
||||
void RecordVirtualJSCollectionDetails(JSObject object);
|
||||
void RecordVirtualJSObjectDetails(JSObject object);
|
||||
void RecordVirtualMapDetails(Map map);
|
||||
void RecordVirtualScriptDetails(Script script);
|
||||
void RecordVirtualExternalStringDetails(ExternalString script);
|
||||
void RecordVirtualSharedFunctionInfoDetails(SharedFunctionInfo info);
|
||||
void RecordVirtualJSFunctionDetails(JSFunction function);
|
||||
|
||||
void RecordVirtualArrayBoilerplateDescription(
|
||||
ArrayBoilerplateDescription description);
|
||||
@ -435,12 +439,19 @@ bool ObjectStatsCollectorImpl::ShouldRecordObject(HeapObject obj,
|
||||
}
|
||||
|
||||
void ObjectStatsCollectorImpl::RecordHashTableVirtualObjectStats(
|
||||
HeapObject parent, FixedArray hash_table,
|
||||
HeapObject parent, HashTableBase hash_table,
|
||||
ObjectStats::VirtualInstanceType type) {
|
||||
CHECK(hash_table->IsHashTable());
|
||||
// TODO(mlippautz): Implement over allocation for hash tables.
|
||||
size_t entry_size =
|
||||
((hash_table->length() - HashTableBase::kPrefixStartIndex) /
|
||||
hash_table->Capacity()) *
|
||||
kTaggedSize;
|
||||
size_t over_allocated =
|
||||
(hash_table->length() -
|
||||
(HashTableBase::kPrefixStartIndex + hash_table->NumberOfElements() +
|
||||
hash_table->NumberOfDeletedElements())) *
|
||||
entry_size;
|
||||
RecordVirtualObjectStats(parent, hash_table, type, hash_table->Size(),
|
||||
ObjectStats::kNoOverAllocation);
|
||||
over_allocated);
|
||||
}
|
||||
|
||||
bool ObjectStatsCollectorImpl::RecordSimpleVirtualObjectStats(
|
||||
@ -529,36 +540,58 @@ void ObjectStatsCollectorImpl::RecordVirtualJSGlobalObjectDetails(
|
||||
ObjectStats::GLOBAL_ELEMENTS_TYPE);
|
||||
}
|
||||
|
||||
void ObjectStatsCollectorImpl::RecordVirtualJSCollectionDetails(
|
||||
JSObject object) {
|
||||
if (object->IsJSMap()) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
object, FixedArray::cast(JSMap::cast(object)->table()),
|
||||
ObjectStats::JS_COLLECTION_TABLE_TYPE);
|
||||
}
|
||||
if (object->IsJSSet()) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
object, FixedArray::cast(JSSet::cast(object)->table()),
|
||||
ObjectStats::JS_COLLECTION_TABLE_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectStatsCollectorImpl::RecordVirtualJSObjectDetails(JSObject object) {
|
||||
// JSGlobalObject is recorded separately.
|
||||
if (object->IsJSGlobalObject()) return;
|
||||
|
||||
// Uncompiled JSFunction has a separate type.
|
||||
if (object->IsJSFunction() && !JSFunction::cast(object)->is_compiled()) {
|
||||
RecordSimpleVirtualObjectStats(HeapObject(), object,
|
||||
ObjectStats::JS_UNCOMPILED_FUNCTION_TYPE);
|
||||
}
|
||||
|
||||
// Properties.
|
||||
if (object->HasFastProperties()) {
|
||||
PropertyArray properties = object->property_array();
|
||||
CHECK_EQ(PROPERTY_ARRAY_TYPE, properties->map()->instance_type());
|
||||
size_t over_allocated = ObjectStats::kNoOverAllocation;
|
||||
if (properties != ReadOnlyRoots(heap_).empty_property_array()) {
|
||||
over_allocated += object->map()->UnusedPropertyFields() * kTaggedSize;
|
||||
}
|
||||
RecordVirtualObjectStats(object, properties,
|
||||
ObjectStats::OBJECT_PROPERTY_ARRAY_TYPE,
|
||||
properties->Size(), over_allocated);
|
||||
} else {
|
||||
NameDictionary properties = object->property_dictionary();
|
||||
RecordHashTableVirtualObjectStats(
|
||||
object, properties, ObjectStats::OBJECT_PROPERTY_DICTIONARY_TYPE);
|
||||
}
|
||||
|
||||
// Elements.
|
||||
FixedArrayBase elements = object->elements();
|
||||
RecordSimpleVirtualObjectStats(object, elements, ObjectStats::ELEMENTS_TYPE);
|
||||
if (object->HasDictionaryElements()) {
|
||||
RecordHashTableVirtualObjectStats(
|
||||
object, NumberDictionary::cast(elements),
|
||||
object->IsJSArray() ? ObjectStats::ARRAY_DICTIONARY_ELEMENTS_TYPE
|
||||
: ObjectStats::OBJECT_DICTIONARY_ELEMENTS_TYPE);
|
||||
} else if (object->IsJSArray()) {
|
||||
size_t element_size =
|
||||
(elements->Size() - FixedArrayBase::kHeaderSize) / elements->length();
|
||||
uint32_t length = JSArray::cast(object)->length()->Number();
|
||||
size_t over_allocated = (elements->length() - length) * element_size;
|
||||
RecordVirtualObjectStats(object, elements, ObjectStats::ARRAY_ELEMENTS_TYPE,
|
||||
elements->Size(), over_allocated);
|
||||
} else {
|
||||
RecordSimpleVirtualObjectStats(object, elements,
|
||||
ObjectStats::OBJECT_ELEMENTS_TYPE);
|
||||
}
|
||||
|
||||
// JSCollections.
|
||||
if (object->IsJSCollection()) {
|
||||
// TODO(bmeurer): Properly compute over-allocation here.
|
||||
RecordSimpleVirtualObjectStats(
|
||||
object, FixedArray::cast(JSCollection::cast(object)->table()),
|
||||
ObjectStats::JS_COLLECTION_TABLE_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
static ObjectStats::VirtualInstanceType GetFeedbackSlotType(
|
||||
@ -676,16 +709,12 @@ void ObjectStatsCollectorImpl::CollectStatistics(
|
||||
} else if (obj->IsFunctionTemplateInfo()) {
|
||||
RecordVirtualFunctionTemplateInfoDetails(
|
||||
FunctionTemplateInfo::cast(obj));
|
||||
} else if (obj->IsJSFunction()) {
|
||||
RecordVirtualJSFunctionDetails(JSFunction::cast(obj));
|
||||
} else if (obj->IsJSGlobalObject()) {
|
||||
RecordVirtualJSGlobalObjectDetails(JSGlobalObject::cast(obj));
|
||||
} else if (obj->IsJSObject()) {
|
||||
// This phase needs to come after RecordVirtualAllocationSiteDetails
|
||||
// to properly split among boilerplates.
|
||||
RecordVirtualJSObjectDetails(JSObject::cast(obj));
|
||||
} else if (obj->IsJSCollection()) {
|
||||
RecordVirtualJSCollectionDetails(JSObject::cast(obj));
|
||||
} else if (obj->IsSharedFunctionInfo()) {
|
||||
RecordVirtualSharedFunctionInfoDetails(SharedFunctionInfo::cast(obj));
|
||||
} else if (obj->IsContext()) {
|
||||
@ -706,7 +735,11 @@ void ObjectStatsCollectorImpl::CollectStatistics(
|
||||
// sources. We still want to run RecordObjectStats after though.
|
||||
RecordVirtualExternalStringDetails(ExternalString::cast(obj));
|
||||
}
|
||||
RecordObjectStats(obj, map->instance_type(), obj->Size());
|
||||
size_t over_allocated = ObjectStats::kNoOverAllocation;
|
||||
if (obj->IsJSObject()) {
|
||||
over_allocated = map->instance_size() - map->UsedInstanceSize();
|
||||
}
|
||||
RecordObjectStats(obj, map->instance_type(), obj->Size(), over_allocated);
|
||||
if (collect_field_stats == CollectFieldStats::kYes) {
|
||||
field_stats_collector_.RecordStats(obj);
|
||||
}
|
||||
@ -749,10 +782,10 @@ void ObjectStatsCollectorImpl::CollectGlobalStatistics() {
|
||||
}
|
||||
|
||||
void ObjectStatsCollectorImpl::RecordObjectStats(HeapObject obj,
|
||||
InstanceType type,
|
||||
size_t size) {
|
||||
InstanceType type, size_t size,
|
||||
size_t over_allocated) {
|
||||
if (virtual_objects_.find(obj) == virtual_objects_.end()) {
|
||||
stats_->RecordObjectStats(type, size);
|
||||
stats_->RecordObjectStats(type, size, over_allocated);
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,10 +842,14 @@ void ObjectStatsCollectorImpl::RecordVirtualMapDetails(Map map) {
|
||||
array != ReadOnlyRoots(heap_).empty_descriptor_array()) {
|
||||
// Generally DescriptorArrays have their own instance type already
|
||||
// (DESCRIPTOR_ARRAY_TYPE), but we'd like to be able to tell which
|
||||
// of those are for (abandoned) prototypes.
|
||||
// of those are for (abandoned) prototypes, and which of those are
|
||||
// owned by deprecated maps.
|
||||
if (map->is_prototype_map()) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
map, array, ObjectStats::PROTOTYPE_DESCRIPTOR_ARRAY_TYPE);
|
||||
} else if (map->is_deprecated()) {
|
||||
RecordSimpleVirtualObjectStats(
|
||||
map, array, ObjectStats::DEPRECATED_DESCRIPTOR_ARRAY_TYPE);
|
||||
}
|
||||
|
||||
EnumCache enum_cache = array->enum_cache();
|
||||
@ -887,14 +924,6 @@ void ObjectStatsCollectorImpl::RecordVirtualSharedFunctionInfoDetails(
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectStatsCollectorImpl::RecordVirtualJSFunctionDetails(
|
||||
JSFunction function) {
|
||||
// Uncompiled JSFunctions get their own category.
|
||||
if (!function->is_compiled()) {
|
||||
RecordSimpleVirtualObjectStats(HeapObject(), function,
|
||||
ObjectStats::UNCOMPILED_JS_FUNCTION_TYPE);
|
||||
}
|
||||
}
|
||||
void ObjectStatsCollectorImpl::RecordVirtualArrayBoilerplateDescription(
|
||||
ArrayBoilerplateDescription description) {
|
||||
RecordVirtualObjectsForConstantPoolOrEmbeddedObjects(
|
||||
|
@ -17,6 +17,8 @@
|
||||
#define VIRTUAL_INSTANCE_TYPE_LIST(V) \
|
||||
CODE_KIND_LIST(V) \
|
||||
V(ARRAY_BOILERPLATE_DESCRIPTION_ELEMENTS_TYPE) \
|
||||
V(ARRAY_DICTIONARY_ELEMENTS_TYPE) \
|
||||
V(ARRAY_ELEMENTS_TYPE) \
|
||||
V(BOILERPLATE_ELEMENTS_TYPE) \
|
||||
V(BOILERPLATE_PROPERTY_ARRAY_TYPE) \
|
||||
V(BOILERPLATE_PROPERTY_DICTIONARY_TYPE) \
|
||||
@ -25,7 +27,7 @@
|
||||
V(COW_ARRAY_TYPE) \
|
||||
V(DEOPTIMIZATION_DATA_TYPE) \
|
||||
V(DEPENDENT_CODE_TYPE) \
|
||||
V(ELEMENTS_TYPE) \
|
||||
V(DEPRECATED_DESCRIPTOR_ARRAY_TYPE) \
|
||||
V(EMBEDDED_OBJECT_TYPE) \
|
||||
V(ENUM_CACHE_TYPE) \
|
||||
V(ENUM_INDICES_CACHE_TYPE) \
|
||||
@ -45,6 +47,7 @@
|
||||
V(JS_ARRAY_BOILERPLATE_TYPE) \
|
||||
V(JS_COLLECTION_TABLE_TYPE) \
|
||||
V(JS_OBJECT_BOILERPLATE_TYPE) \
|
||||
V(JS_UNCOMPILED_FUNCTION_TYPE) \
|
||||
V(MAP_ABANDONED_PROTOTYPE_TYPE) \
|
||||
V(MAP_DEPRECATED_TYPE) \
|
||||
V(MAP_DICTIONARY_TYPE) \
|
||||
@ -53,6 +56,9 @@
|
||||
V(MAP_STABLE_TYPE) \
|
||||
V(NOSCRIPT_SHARED_FUNCTION_INFOS_TYPE) \
|
||||
V(NUMBER_STRING_CACHE_TYPE) \
|
||||
V(OBJECT_DICTIONARY_ELEMENTS_TYPE) \
|
||||
V(OBJECT_ELEMENTS_TYPE) \
|
||||
V(OBJECT_PROPERTY_ARRAY_TYPE) \
|
||||
V(OBJECT_PROPERTY_DICTIONARY_TYPE) \
|
||||
V(OBJECT_TO_CODE_TYPE) \
|
||||
V(OPTIMIZED_CODE_LITERALS_TYPE) \
|
||||
@ -74,7 +80,6 @@
|
||||
V(STRING_EXTERNAL_RESOURCE_ONE_BYTE_TYPE) \
|
||||
V(STRING_EXTERNAL_RESOURCE_TWO_BYTE_TYPE) \
|
||||
V(SOURCE_POSITION_TABLE_TYPE) \
|
||||
V(UNCOMPILED_JS_FUNCTION_TYPE) \
|
||||
V(UNCOMPILED_SHARED_FUNCTION_INFO_TYPE) \
|
||||
V(WEAK_NEW_SPACE_OBJECT_TO_CODE_TYPE)
|
||||
|
||||
@ -112,7 +117,8 @@ class ObjectStats {
|
||||
void Dump(std::stringstream& stream);
|
||||
|
||||
void CheckpointObjectStats();
|
||||
void RecordObjectStats(InstanceType type, size_t size);
|
||||
void RecordObjectStats(InstanceType type, size_t size,
|
||||
size_t over_allocated = kNoOverAllocation);
|
||||
void RecordVirtualObjectStats(VirtualInstanceType type, size_t size,
|
||||
size_t over_allocated);
|
||||
|
||||
|
@ -51,6 +51,7 @@ ACCESSORS(JSCollectionIterator, index, Object, kIndexOffset)
|
||||
|
||||
ACCESSORS(JSWeakCollection, table, Object, kTableOffset)
|
||||
|
||||
CAST_ACCESSOR(JSCollection)
|
||||
CAST_ACCESSOR(JSSet)
|
||||
CAST_ACCESSOR(JSSetIterator)
|
||||
CAST_ACCESSOR(JSMap)
|
||||
|
@ -19,6 +19,8 @@ class OrderedHashMap;
|
||||
|
||||
class JSCollection : public JSObject {
|
||||
public:
|
||||
DECL_CAST(JSCollection)
|
||||
|
||||
// [table]: the backing hash table
|
||||
DECL_ACCESSORS(table, Object)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user