From a5a9198a9b91619d913161a0d7edf6e2907c70b9 Mon Sep 17 00:00:00 2001 From: lpy Date: Tue, 4 Oct 2016 17:41:25 -0700 Subject: [PATCH] [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} --- src/heap/mark-compact.cc | 7 +++++ src/heap/object-stats.cc | 64 ++++++++++++++++++++++++++++++++++++++++ src/heap/object-stats.h | 1 + 3 files changed, 72 insertions(+) diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc index 7564522df6..58fd0a8dcb 100644 --- a/src/heap/mark-compact.cc +++ b/src/heap/mark-compact.cc @@ -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"); diff --git a/src/heap/object-stats.cc b/src/heap/object-stats.cc index dd2adc3d92..4bc94bafe8 100644 --- a/src/heap/object-stats.cc +++ b/src/heap/object-stats.cc @@ -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(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(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 diff --git a/src/heap/object-stats.h b/src/heap/object-stats.h index 4780696952..add5a12b04 100644 --- a/src/heap/object-stats.h +++ b/src/heap/object-stats.h @@ -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);