[obj-stats] Count more field types (Smi, boxed double, string)
Distinguish between generic Tagged and Smi in-object fields, and special case (boxed) double values and string data rather than lumping those into generic "raw data" Change-Id: I5d635434ab94065c077a40110948424c31ead73d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1718154 Commit-Queue: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Cr-Commit-Position: refs/heads/master@{#62914}
This commit is contained in:
parent
dd7190a979
commit
b50ee58ca7
@ -35,11 +35,16 @@ class FieldStatsCollector : public ObjectVisitor {
|
||||
public:
|
||||
FieldStatsCollector(size_t* tagged_fields_count,
|
||||
size_t* embedder_fields_count,
|
||||
size_t* inobject_smi_fields_count,
|
||||
size_t* unboxed_double_fields_count,
|
||||
size_t* raw_fields_count)
|
||||
size_t* boxed_double_fields_count,
|
||||
size_t* string_data_count, size_t* raw_fields_count)
|
||||
: tagged_fields_count_(tagged_fields_count),
|
||||
embedder_fields_count_(embedder_fields_count),
|
||||
inobject_smi_fields_count_(inobject_smi_fields_count),
|
||||
unboxed_double_fields_count_(unboxed_double_fields_count),
|
||||
boxed_double_fields_count_(boxed_double_fields_count),
|
||||
string_data_count_(string_data_count),
|
||||
raw_fields_count_(raw_fields_count) {}
|
||||
|
||||
void RecordStats(HeapObject host) {
|
||||
@ -62,11 +67,32 @@ class FieldStatsCollector : public ObjectVisitor {
|
||||
*tagged_fields_count_ -= field_stats.embedded_fields_count_;
|
||||
*embedder_fields_count_ += field_stats.embedded_fields_count_;
|
||||
|
||||
// Smi fields are also included into pointer words.
|
||||
DCHECK_LE(
|
||||
field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize,
|
||||
raw_fields_count_in_object);
|
||||
tagged_fields_count_in_object -= field_stats.smi_fields_count_;
|
||||
*tagged_fields_count_ -= field_stats.smi_fields_count_;
|
||||
*inobject_smi_fields_count_ += field_stats.smi_fields_count_;
|
||||
|
||||
// The rest are data words.
|
||||
DCHECK_LE(field_stats.unboxed_double_fields_count_,
|
||||
raw_fields_count_in_object);
|
||||
raw_fields_count_in_object -= field_stats.unboxed_double_fields_count_;
|
||||
DCHECK_LE(
|
||||
field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize,
|
||||
raw_fields_count_in_object);
|
||||
raw_fields_count_in_object -=
|
||||
field_stats.unboxed_double_fields_count_ * kDoubleSize / kTaggedSize;
|
||||
*unboxed_double_fields_count_ += field_stats.unboxed_double_fields_count_;
|
||||
} else if (host.IsHeapNumber() || host.IsMutableHeapNumber()) {
|
||||
DCHECK_LE(kDoubleSize / kTaggedSize, raw_fields_count_in_object);
|
||||
raw_fields_count_in_object -= kDoubleSize / kTaggedSize;
|
||||
*boxed_double_fields_count_ += 1;
|
||||
} else if (host.IsSeqString()) {
|
||||
int string_data = SeqString::cast(host).synchronized_length() *
|
||||
(String::cast(host).IsOneByteRepresentation() ? 1 : 2) /
|
||||
kTaggedSize;
|
||||
DCHECK_LE(string_data, raw_fields_count_in_object);
|
||||
raw_fields_count_in_object -= string_data;
|
||||
*string_data_count_ += string_data;
|
||||
}
|
||||
*raw_fields_count_ += raw_fields_count_in_object;
|
||||
}
|
||||
@ -92,9 +118,12 @@ class FieldStatsCollector : public ObjectVisitor {
|
||||
private:
|
||||
struct JSObjectFieldStats {
|
||||
JSObjectFieldStats()
|
||||
: embedded_fields_count_(0), unboxed_double_fields_count_(0) {}
|
||||
: embedded_fields_count_(0),
|
||||
smi_fields_count_(0),
|
||||
unboxed_double_fields_count_(0) {}
|
||||
|
||||
unsigned embedded_fields_count_ : kDescriptorIndexBitCount;
|
||||
unsigned smi_fields_count_ : kDescriptorIndexBitCount;
|
||||
unsigned unboxed_double_fields_count_ : kDescriptorIndexBitCount;
|
||||
};
|
||||
std::unordered_map<Map, JSObjectFieldStats, Object::Hasher>
|
||||
@ -104,7 +133,10 @@ class FieldStatsCollector : public ObjectVisitor {
|
||||
|
||||
size_t* const tagged_fields_count_;
|
||||
size_t* const embedder_fields_count_;
|
||||
size_t* const inobject_smi_fields_count_;
|
||||
size_t* const unboxed_double_fields_count_;
|
||||
size_t* const boxed_double_fields_count_;
|
||||
size_t* const string_data_count_;
|
||||
size_t* const raw_fields_count_;
|
||||
};
|
||||
|
||||
@ -130,6 +162,9 @@ FieldStatsCollector::GetInobjectFieldStats(Map map) {
|
||||
map.IsUnboxedDoubleField(index)) {
|
||||
++stats.unboxed_double_fields_count_;
|
||||
}
|
||||
if (details.representation().IsSmi()) {
|
||||
++stats.smi_fields_count_;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,7 +184,10 @@ void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
|
||||
}
|
||||
tagged_fields_count_ = 0;
|
||||
embedder_fields_count_ = 0;
|
||||
inobject_smi_fields_count_ = 0;
|
||||
unboxed_double_fields_count_ = 0;
|
||||
boxed_double_fields_count_ = 0;
|
||||
string_data_count_ = 0;
|
||||
raw_fields_count_ = 0;
|
||||
}
|
||||
|
||||
@ -208,8 +246,13 @@ void ObjectStats::PrintJSON(const char* key) {
|
||||
PrintF(", \"tagged_fields\": %zu", tagged_fields_count_ * kTaggedSize);
|
||||
PrintF(", \"embedder_fields\": %zu",
|
||||
embedder_fields_count_ * kEmbedderDataSlotSize);
|
||||
PrintF(", \"inobject_smi_fields\": %zu",
|
||||
inobject_smi_fields_count_ * kTaggedSize);
|
||||
PrintF(", \"unboxed_double_fields\": %zu",
|
||||
unboxed_double_fields_count_ * kDoubleSize);
|
||||
PrintF(", \"boxed_double_fields\": %zu",
|
||||
boxed_double_fields_count_ * kDoubleSize);
|
||||
PrintF(", \"string_data\": %zu", string_data_count_ * kTaggedSize);
|
||||
PrintF(", \"other_raw_fields\": %zu", raw_fields_count_ * kSystemPointerSize);
|
||||
PrintF(" }\n");
|
||||
// bucket_sizes
|
||||
@ -263,8 +306,13 @@ void ObjectStats::Dump(std::stringstream& stream) {
|
||||
stream << "\"tagged_fields\":" << (tagged_fields_count_ * kTaggedSize);
|
||||
stream << ",\"embedder_fields\":"
|
||||
<< (embedder_fields_count_ * kEmbedderDataSlotSize);
|
||||
stream << ",\"inobject_smi_fields\": "
|
||||
<< (inobject_smi_fields_count_ * kTaggedSize);
|
||||
stream << ",\"unboxed_double_fields\": "
|
||||
<< (unboxed_double_fields_count_ * kDoubleSize);
|
||||
stream << ",\"boxed_double_fields\": "
|
||||
<< (boxed_double_fields_count_ * kDoubleSize);
|
||||
stream << ",\"string_data\": " << (string_data_count_ * kTaggedSize);
|
||||
stream << ",\"other_raw_fields\":"
|
||||
<< (raw_fields_count_ * kSystemPointerSize);
|
||||
stream << "}, ";
|
||||
@ -427,7 +475,10 @@ ObjectStatsCollectorImpl::ObjectStatsCollectorImpl(Heap* heap,
|
||||
heap->mark_compact_collector()->non_atomic_marking_state()),
|
||||
field_stats_collector_(
|
||||
&stats->tagged_fields_count_, &stats->embedder_fields_count_,
|
||||
&stats->unboxed_double_fields_count_, &stats->raw_fields_count_) {}
|
||||
&stats->inobject_smi_fields_count_,
|
||||
&stats->unboxed_double_fields_count_,
|
||||
&stats->boxed_double_fields_count_, &stats->string_data_count_,
|
||||
&stats->raw_fields_count_) {}
|
||||
|
||||
bool ObjectStatsCollectorImpl::ShouldRecordObject(HeapObject obj,
|
||||
CowMode check_cow_array) {
|
||||
|
@ -167,7 +167,10 @@ class ObjectStats {
|
||||
|
||||
size_t tagged_fields_count_;
|
||||
size_t embedder_fields_count_;
|
||||
size_t inobject_smi_fields_count_;
|
||||
size_t unboxed_double_fields_count_;
|
||||
size_t boxed_double_fields_count_;
|
||||
size_t string_data_count_;
|
||||
size_t raw_fields_count_;
|
||||
|
||||
friend class ObjectStatsCollectorImpl;
|
||||
|
@ -63,9 +63,12 @@ class GlobalTimeline extends HTMLElement {
|
||||
{type: 'number', label: 'Ptr compression benefit'},
|
||||
{type: 'string', role: 'tooltip'},
|
||||
{type: 'number', label: 'Embedder fields'},
|
||||
{type: 'number', label: 'Tagged fields'},
|
||||
{type: 'number', label: 'Tagged fields (excl. in-object Smis)'},
|
||||
{type: 'number', label: 'In-object Smi-only fields'},
|
||||
{type: 'number', label: 'Other raw fields'},
|
||||
{type: 'number', label: 'Unboxed doubles'}
|
||||
{type: 'number', label: 'Unboxed doubles'},
|
||||
{type: 'number', label: 'Boxed doubles'},
|
||||
{type: 'number', label: 'String data'}
|
||||
];
|
||||
const chart_data = [labels];
|
||||
const isolate_data = this.data[this.selection.isolate];
|
||||
@ -78,10 +81,14 @@ class GlobalTimeline extends HTMLElement {
|
||||
const data = [];
|
||||
data.push(gc_data.time * kMillis2Seconds);
|
||||
const total = data_set.tagged_fields +
|
||||
data_set.inobject_smi_fields +
|
||||
data_set.embedder_fields +
|
||||
data_set.other_raw_fields +
|
||||
data_set.unboxed_double_fields;
|
||||
const ptr_compr_benefit = data_set.tagged_fields / 2;
|
||||
data_set.unboxed_double_fields +
|
||||
data_set.boxed_double_fields +
|
||||
data_set.string_data;
|
||||
const ptr_compr_benefit =
|
||||
(data_set.smi_fields + data_set.tagged_fields) / 2;
|
||||
const ptr_compr_benefit_perc = ptr_compr_benefit / total * 100;
|
||||
sum_total += total;
|
||||
sum_ptr_compr_benefit_perc += ptr_compr_benefit_perc;
|
||||
@ -92,9 +99,12 @@ class GlobalTimeline extends HTMLElement {
|
||||
data.push(ptr_compr_benefit / KB);
|
||||
data.push(tooltip);
|
||||
data.push(data_set.embedder_fields / KB);
|
||||
data.push(data_set.inobject_smi_fields / KB);
|
||||
data.push(data_set.tagged_fields / KB);
|
||||
data.push(data_set.other_raw_fields / KB);
|
||||
data.push(data_set.unboxed_double_fields / KB);
|
||||
data.push(data_set.boxed_double_fields / KB);
|
||||
data.push(data_set.string_data / KB);
|
||||
chart_data.push(data);
|
||||
});
|
||||
const avg_ptr_compr_benefit_perc =
|
||||
|
@ -137,11 +137,15 @@ class TraceFileReader extends HTMLElement {
|
||||
}
|
||||
|
||||
addFieldTypeData(data, isolate, gc_id, data_set, tagged_fields,
|
||||
embedder_fields, unboxed_double_fields, other_raw_fields) {
|
||||
inobject_smi_fields, embedder_fields, unboxed_double_fields,
|
||||
boxed_double_fields, string_data, other_raw_fields) {
|
||||
data[isolate].gcs[gc_id][data_set].field_data = {
|
||||
tagged_fields,
|
||||
inobject_smi_fields,
|
||||
embedder_fields,
|
||||
unboxed_double_fields,
|
||||
boxed_double_fields,
|
||||
string_data,
|
||||
other_raw_fields
|
||||
};
|
||||
}
|
||||
@ -217,8 +221,12 @@ class TraceFileReader extends HTMLElement {
|
||||
|
||||
const field_data = entry.field_data;
|
||||
this.addFieldTypeData(data, isolate, gc_id, data_set,
|
||||
field_data.tagged_fields, field_data.embedder_fields,
|
||||
field_data.tagged_fields,
|
||||
field_data.inobject_smi_fields,
|
||||
field_data.embedder_fields,
|
||||
field_data.unboxed_double_fields,
|
||||
field_data.boxed_double_fields,
|
||||
field_data.string_data,
|
||||
field_data.other_raw_fields);
|
||||
|
||||
data[isolate].gcs[gc_id][data_set].bucket_sizes =
|
||||
@ -282,8 +290,9 @@ class TraceFileReader extends HTMLElement {
|
||||
this.createOrUpdateEntryIfNeeded(data, entry);
|
||||
this.createDatasetIfNeeded(data, entry, entry.key);
|
||||
this.addFieldTypeData(data, entry.isolate, entry.id, entry.key,
|
||||
entry.tagged_fields, entry.embedder_fields,
|
||||
entry.unboxed_double_fields, entry.other_raw_fields);
|
||||
entry.tagged_fields, entry.embedder_fields, entry.inobject_smi_fields,
|
||||
entry.unboxed_double_fields, entry.boxed_double_fields,
|
||||
entry.string_data, entry.other_raw_fields);
|
||||
} else if (entry.type === 'instance_type_data') {
|
||||
if (entry.id in data[entry.isolate].gcs) {
|
||||
this.createOrUpdateEntryIfNeeded(data, entry);
|
||||
|
Loading…
Reference in New Issue
Block a user