[tracing] Emit heap statistics at every GC.
When the 'disabled-by-default-v8.gc' category is enabled, emit an instant event
with heap statistics after every GC. The data that's emitted is the same as what
the V8 API gives you with `GetHeapStatistics()` and `GetHeapSpaceStatistics()`.
We generate JSON with the following format:
```
{
"isolate": "0x55dd5cf03b50",
"id": 1,
"time_ms": 42.619,
"total_heap_size": 3981312,
"total_heap_size_executable": 573440,
"total_physical_size": 2820440,
"total_available_size": 2195254440,
"used_heap_size": 1799616,
"heap_size_limit": 2197815296,
"malloced_memory": 251024,
"external_memory": 2981,
"peak_malloced_memory": 589280,
"spaces": [
{
"name": "read_only_space",
"size": 262144,
"used_size": 32568,
"available_size": 229256,
"physical_size": 32888
},
{
"name": "new_space",
"size": 2097152,
"used_size": 903392,
"available_size": 143904,
"physical_size": 1856136
},
...
]
}
```
Bug: v8:9186
Change-Id: I0d07aa37b65d45778d6b47dbe6e07a9dd25d1097
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1619763
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Pierre Langlois <pierre.langlois@arm.com>
Cr-Commit-Position: refs/heads/master@{#61667}
diff --git a/src/heap/gc-tracer.cc b/src/heap/gc-tracer.cc
index 9ae2435..bd25740 100644
--- a/src/heap/gc-tracer.cc
+++ b/src/heap/gc-tracer.cc
@@ -363,6 +363,16 @@
if (FLAG_trace_gc) {
heap_->PrintShortHeapStatistics();
}
+
+ if (V8_UNLIKELY(TracingFlags::gc.load(std::memory_order_relaxed) &
+ v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING)) {
+ std::stringstream heap_stats;
+ heap_->DumpJSONHeapStatistics(heap_stats);
+
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"), "V8.GC_Heap_Stats",
+ TRACE_EVENT_SCOPE_THREAD, "stats",
+ TRACE_STR_COPY(heap_stats.str().c_str()));
+ }
}
diff --git a/src/heap/heap.cc b/src/heap/heap.cc
index 6484b5e..ee2a4ce 100644
--- a/src/heap/heap.cc
+++ b/src/heap/heap.cc
@@ -442,6 +442,63 @@
total_gc_time_ms_);
}
+void Heap::DumpJSONHeapStatistics(std::stringstream& stream) {
+ HeapStatistics stats;
+ reinterpret_cast<v8::Isolate*>(isolate())->GetHeapStatistics(&stats);
+
+// clang-format off
+#define DICT(s) "{" << s << "}"
+#define LIST(s) "[" << s << "]"
+#define ESCAPE(s) "\"" << s << "\""
+#define MEMBER(s) ESCAPE(s) << ":"
+
+ auto SpaceStatistics = [this](int space_index) {
+ HeapSpaceStatistics space_stats;
+ reinterpret_cast<v8::Isolate*>(isolate())->GetHeapSpaceStatistics(
+ &space_stats, space_index);
+ std::stringstream stream;
+ stream << DICT(
+ MEMBER("name")
+ << ESCAPE(GetSpaceName(static_cast<AllocationSpace>(space_index)))
+ << ","
+ MEMBER("size") << space_stats.space_size() << ","
+ MEMBER("used_size") << space_stats.space_used_size() << ","
+ MEMBER("available_size") << space_stats.space_available_size() << ","
+ MEMBER("physical_size") << space_stats.physical_space_size());
+ return stream.str();
+ };
+
+ stream << DICT(
+ MEMBER("isolate") << ESCAPE(reinterpret_cast<void*>(isolate())) << ","
+ MEMBER("id") << gc_count() << ","
+ MEMBER("time_ms") << isolate()->time_millis_since_init() << ","
+ MEMBER("total_heap_size") << stats.total_heap_size() << ","
+ MEMBER("total_heap_size_executable")
+ << stats.total_heap_size_executable() << ","
+ MEMBER("total_physical_size") << stats.total_physical_size() << ","
+ MEMBER("total_available_size") << stats.total_available_size() << ","
+ MEMBER("used_heap_size") << stats.used_heap_size() << ","
+ MEMBER("heap_size_limit") << stats.heap_size_limit() << ","
+ MEMBER("malloced_memory") << stats.malloced_memory() << ","
+ MEMBER("external_memory") << stats.external_memory() << ","
+ MEMBER("peak_malloced_memory") << stats.peak_malloced_memory() << ","
+ MEMBER("pages") << LIST(
+ SpaceStatistics(RO_SPACE) << "," <<
+ SpaceStatistics(NEW_SPACE) << "," <<
+ SpaceStatistics(OLD_SPACE) << "," <<
+ SpaceStatistics(CODE_SPACE) << "," <<
+ SpaceStatistics(MAP_SPACE) << "," <<
+ SpaceStatistics(LO_SPACE) << "," <<
+ SpaceStatistics(CODE_LO_SPACE) << "," <<
+ SpaceStatistics(NEW_LO_SPACE)));
+
+#undef DICT
+#undef LIST
+#undef ESCAPE
+#undef MEMBER
+ // clang-format on
+}
+
void Heap::ReportStatisticsAfterGC() {
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);
++i) {
diff --git a/src/heap/heap.h b/src/heap/heap.h
index c2d12f7..73c1d3f 100644
--- a/src/heap/heap.h
+++ b/src/heap/heap.h
@@ -474,6 +474,9 @@
// Print short heap statistics.
void PrintShortHeapStatistics();
+ // Dump heap statistics in JSON format.
+ void DumpJSONHeapStatistics(std::stringstream& stream);
+
bool write_protect_code_memory() const { return write_protect_code_memory_; }
uintptr_t code_space_memory_modification_scope_depth() {
diff --git a/src/logging/counters.cc b/src/logging/counters.cc
index 58f35e8..9feed03 100644
--- a/src/logging/counters.cc
+++ b/src/logging/counters.cc
@@ -18,6 +18,7 @@
namespace internal {
std::atomic_uint TracingFlags::runtime_stats{0};
+std::atomic_uint TracingFlags::gc{0};
std::atomic_uint TracingFlags::gc_stats{0};
std::atomic_uint TracingFlags::ic_stats{0};
diff --git a/src/logging/counters.h b/src/logging/counters.h
index e7fa916..2e21c9b 100644
--- a/src/logging/counters.h
+++ b/src/logging/counters.h
@@ -30,6 +30,7 @@
struct TracingFlags {
static V8_EXPORT_PRIVATE std::atomic_uint runtime_stats;
+ static V8_EXPORT_PRIVATE std::atomic_uint gc;
static V8_EXPORT_PRIVATE std::atomic_uint gc_stats;
static V8_EXPORT_PRIVATE std::atomic_uint ic_stats;
@@ -37,6 +38,10 @@
return runtime_stats.load(std::memory_order_relaxed) != 0;
}
+ static bool is_gc_enabled() {
+ return gc.load(std::memory_order_relaxed) != 0;
+ }
+
static bool is_gc_stats_enabled() {
return gc_stats.load(std::memory_order_relaxed) != 0;
}
diff --git a/src/tracing/tracing-category-observer.cc b/src/tracing/tracing-category-observer.cc
index 276aed1..f524591 100644
--- a/src/tracing/tracing-category-observer.cc
+++ b/src/tracing/tracing-category-observer.cc
@@ -40,6 +40,11 @@
i::TracingFlags::runtime_stats.fetch_or(ENABLED_BY_SAMPLING,
std::memory_order_relaxed);
}
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
+ &enabled);
+ if (enabled) {
+ i::TracingFlags::gc.fetch_or(ENABLED_BY_TRACING, std::memory_order_relaxed);
+ }
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats"),
&enabled);
if (enabled) {
@@ -58,6 +63,8 @@
i::TracingFlags::runtime_stats.fetch_and(
~(ENABLED_BY_TRACING | ENABLED_BY_SAMPLING), std::memory_order_relaxed);
+ i::TracingFlags::gc.fetch_and(~ENABLED_BY_TRACING, std::memory_order_relaxed);
+
i::TracingFlags::gc_stats.fetch_and(~ENABLED_BY_TRACING,
std::memory_order_relaxed);