[Tracing] Integrate GC object statistics with tracing.
Memory infra in tracing currently uses Isolate::GetHeapStatistics to fetch object statistics from V8 at certain frequency, which is not accurate and will have redundant result. This path adds a trace event as well as a trace category at where we collect object statistics after marking before sweeping, and dumps all information to the trace event. In order to use this functionality, we need to enable two flags: --track-gc-object-stats and --noincremental-marking. BUG=v8:5453 Review-Url: https://codereview.chromium.org/2379823004 Cr-Commit-Position: refs/heads/master@{#39966}
This commit is contained in:
parent
fa5b221ec7
commit
a5a9198a9b
@ -2246,6 +2246,13 @@ void MarkCompactCollector::RecordObjectStats() {
|
||||
ObjectStatsVisitor visitor(heap(), heap()->live_object_stats_,
|
||||
heap()->dead_object_stats_);
|
||||
VisitAllObjects(&visitor);
|
||||
std::stringstream live, dead;
|
||||
heap()->live_object_stats_->Dump(live);
|
||||
heap()->dead_object_stats_->Dump(dead);
|
||||
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats"),
|
||||
"V8.GC_Objects_Stats", TRACE_EVENT_SCOPE_THREAD,
|
||||
"live", TRACE_STR_COPY(live.str().c_str()), "dead",
|
||||
TRACE_STR_COPY(dead.str().c_str()));
|
||||
if (FLAG_trace_gc_object_stats) {
|
||||
heap()->live_object_stats_->PrintJSON("live");
|
||||
heap()->dead_object_stats_->PrintJSON("dead");
|
||||
|
@ -42,6 +42,16 @@ V8_NOINLINE static void PrintJSONArray(size_t* array, const int len) {
|
||||
PrintF(" ]");
|
||||
}
|
||||
|
||||
V8_NOINLINE static void DumpJSONArray(std::stringstream& stream, size_t* array,
|
||||
const int len) {
|
||||
stream << "[";
|
||||
for (int i = 0; i < len; i++) {
|
||||
stream << array[i];
|
||||
if (i != (len - 1)) stream << ",";
|
||||
}
|
||||
stream << "]";
|
||||
}
|
||||
|
||||
void ObjectStats::PrintJSON(const char* key) {
|
||||
double time = isolate()->time_millis_since_init();
|
||||
int gc_count = heap()->gc_count();
|
||||
@ -97,6 +107,60 @@ void ObjectStats::PrintJSON(const char* key) {
|
||||
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER)
|
||||
CODE_AGE_LIST_COMPLETE(CODE_AGE_WRAPPER)
|
||||
|
||||
#undef INSTANCE_TYPE_WRAPPER
|
||||
#undef CODE_KIND_WRAPPER
|
||||
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
|
||||
#undef CODE_AGE_WRAPPER
|
||||
#undef PRINT_INSTANCE_TYPE_DATA
|
||||
#undef PRINT_KEY_AND_ID
|
||||
}
|
||||
|
||||
void ObjectStats::Dump(std::stringstream& stream) {
|
||||
double time = isolate()->time_millis_since_init();
|
||||
int gc_count = heap()->gc_count();
|
||||
|
||||
stream << "{";
|
||||
stream << "\"isolate\":\"" << reinterpret_cast<void*>(isolate()) << "\",";
|
||||
stream << "\"id\":" << gc_count << ",";
|
||||
stream << "\"time\":" << time << ",";
|
||||
stream << "\"bucket_sizes\":[";
|
||||
for (int i = 0; i < kNumberOfBuckets; i++) {
|
||||
stream << (1 << (kFirstBucketShift + i));
|
||||
if (i != (kNumberOfBuckets - 1)) stream << ",";
|
||||
}
|
||||
stream << "],";
|
||||
stream << "\"type_data\":{";
|
||||
|
||||
#define PRINT_INSTANCE_TYPE_DATA(name, index) \
|
||||
stream << "\"" << name << "\":{"; \
|
||||
stream << "\"type\":" << static_cast<int>(index) << ","; \
|
||||
stream << "\"overall\":" << object_sizes_[index] << ","; \
|
||||
stream << "\"count\":" << object_counts_[index] << ","; \
|
||||
stream << "\"over_allocated\":" << over_allocated_[index] << ","; \
|
||||
stream << "\"histogram\":"; \
|
||||
DumpJSONArray(stream, size_histogram_[index], kNumberOfBuckets); \
|
||||
stream << ",\"over_allocated_histogram\":"; \
|
||||
DumpJSONArray(stream, over_allocated_histogram_[index], kNumberOfBuckets); \
|
||||
stream << "},";
|
||||
|
||||
#define INSTANCE_TYPE_WRAPPER(name) PRINT_INSTANCE_TYPE_DATA(#name, name)
|
||||
#define CODE_KIND_WRAPPER(name) \
|
||||
PRINT_INSTANCE_TYPE_DATA("*CODE_" #name, \
|
||||
FIRST_CODE_KIND_SUB_TYPE + Code::name)
|
||||
#define FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER(name) \
|
||||
PRINT_INSTANCE_TYPE_DATA("*FIXED_ARRAY_" #name, \
|
||||
FIRST_FIXED_ARRAY_SUB_TYPE + name)
|
||||
#define CODE_AGE_WRAPPER(name) \
|
||||
PRINT_INSTANCE_TYPE_DATA( \
|
||||
"*CODE_AGE_" #name, \
|
||||
FIRST_CODE_AGE_SUB_TYPE + Code::k##name##CodeAge - Code::kFirstCodeAge)
|
||||
|
||||
INSTANCE_TYPE_LIST(INSTANCE_TYPE_WRAPPER);
|
||||
CODE_KIND_LIST(CODE_KIND_WRAPPER);
|
||||
FIXED_ARRAY_SUB_INSTANCE_TYPE_LIST(FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER);
|
||||
CODE_AGE_LIST_COMPLETE(CODE_AGE_WRAPPER);
|
||||
stream << "\"END\":{}}}";
|
||||
|
||||
#undef INSTANCE_TYPE_WRAPPER
|
||||
#undef CODE_KIND_WRAPPER
|
||||
#undef FIXED_ARRAY_SUB_INSTANCE_TYPE_WRAPPER
|
||||
|
@ -35,6 +35,7 @@ class ObjectStats {
|
||||
|
||||
void CheckpointObjectStats();
|
||||
void PrintJSON(const char* key);
|
||||
void Dump(std::stringstream& stream);
|
||||
|
||||
void RecordObjectStats(InstanceType type, size_t size) {
|
||||
DCHECK(type <= LAST_TYPE);
|
||||
|
Loading…
Reference in New Issue
Block a user