Commit f4ebc674 authored by Darius Mercadier's avatar Darius Mercadier Committed by Commit Bot

Add FLAG_trace_gc_freelists and _verbose version

With this flag enabled, some statistics about the oldspace's freelists
(and free/used spaced in general) are printed before and after each
major garbage collection.

It is useful to get some intuition about fragmentation and debug
freelists. (This flag helped me track down the issues fixed by CLs
1647162 and 1648476)

Additionally, the verbose version (FLAG_trace_gc_freelists_verbose)
prints the freelists of each page of old_space.

Bug: v8:9329
Change-Id: Ifa80426bf9d97ac9950459154507a585b039326d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1655302
Commit-Queue: Darius Mercadier <dmercadier@google.com>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62150}
parent ee279dc2
......@@ -770,6 +770,13 @@ DEFINE_BOOL(trace_idle_notification_verbose, false,
DEFINE_BOOL(trace_gc_verbose, false,
"print more details following each garbage collection")
DEFINE_IMPLICATION(trace_gc_verbose, trace_gc)
DEFINE_BOOL(trace_gc_freelists, false,
"prints details of each freelist before and after "
"each major garbage collection")
DEFINE_BOOL(trace_gc_freelists_verbose, false,
"prints details of freelists of each page before and after "
"each major garbage collection")
DEFINE_IMPLICATION(trace_gc_freelists_verbose, trace_gc_freelists)
DEFINE_INT(trace_allocation_stack_interval, -1,
"print stack trace after <n> free-list allocations")
......
......@@ -264,6 +264,12 @@ void GCTracer::Start(GarbageCollector collector,
counters->scavenge_reason()->AddSample(static_cast<int>(gc_reason));
} else {
counters->mark_compact_reason()->AddSample(static_cast<int>(gc_reason));
if (FLAG_trace_gc_freelists) {
PrintIsolate(heap_->isolate(),
"FreeLists statistics before collection:\n");
heap_->PrintFreeListsStats();
}
}
}
......@@ -377,6 +383,14 @@ void GCTracer::Stop(GarbageCollector collector) {
}
}
void GCTracer::NotifySweepingCompleted() {
if (FLAG_trace_gc_freelists) {
PrintIsolate(heap_->isolate(),
"FreeLists statistics after sweeping completed:\n");
heap_->PrintFreeListsStats();
}
}
void GCTracer::SampleAllocation(double current_ms,
size_t new_space_counter_bytes,
size_t old_generation_counter_bytes,
......
......@@ -216,6 +216,8 @@ class V8_EXPORT_PRIVATE GCTracer {
// Stop collecting data and print results.
void Stop(GarbageCollector collector);
void NotifySweepingCompleted();
void NotifyYoungGenerationHandling(
YoungGenerationHandling young_generation_handling);
......
......@@ -5,6 +5,7 @@
#include "src/heap/heap.h"
#include <cinttypes>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
......@@ -507,6 +508,76 @@ void Heap::PrintShortHeapStatistics() {
total_gc_time_ms_);
}
void Heap::PrintFreeListsStats() {
DCHECK(FLAG_trace_gc_freelists);
if (FLAG_trace_gc_freelists_verbose) {
PrintIsolate(isolate_,
"Freelists statistics per Page: "
"[category: length || total free bytes]\n");
}
int categories_lengths[kNumberOfCategories] = {0};
size_t categories_sums[kNumberOfCategories] = {0};
unsigned int pageCnt = 0;
// This loops computes freelists lengths and sum.
// If FLAG_trace_gc_freelists_verbose is enabled, it also prints
// the stats of each FreeListCategory of each Page.
for (Page* page : *old_space()) {
std::ostringstream out_str;
if (FLAG_trace_gc_freelists_verbose) {
out_str << "Page " << std::setw(4) << pageCnt;
}
for (int cat = kFirstCategory; cat <= kLastCategory; cat++) {
FreeListCategory* free_list =
page->free_list_category(static_cast<FreeListCategoryType>(cat));
int length = free_list->FreeListLength();
size_t sum = free_list->SumFreeList();
if (FLAG_trace_gc_freelists_verbose) {
out_str << "[" << cat << ": " << std::setw(4) << length << " || "
<< std::setw(6) << sum << " ]"
<< (cat == kLastCategory ? "\n" : ", ");
}
categories_lengths[cat] += length;
categories_sums[cat] += sum;
}
if (FLAG_trace_gc_freelists_verbose) {
PrintIsolate(isolate_, "%s", out_str.str().c_str());
}
pageCnt++;
}
// Print statistics about old_space (pages, free/wasted/used memory...).
PrintIsolate(
isolate_,
"%d pages. Free space: %.1f MB (waste: %.2f). "
"Usage: %.1f/%.1f (MB) -> %.2f%%.\n",
pageCnt, static_cast<double>(old_space_->Available()) / MB,
static_cast<double>(old_space_->Waste()) / MB,
static_cast<double>(old_space_->Size()) / MB,
static_cast<double>(old_space_->Capacity()) / MB,
static_cast<double>(old_space_->Size()) / old_space_->Capacity() * 100);
// Print global statistics of each FreeListCategory (length & sum).
PrintIsolate(isolate_,
"FreeLists global statistics: "
"[category: length || total free KB]\n");
std::ostringstream out_str;
for (int cat = 0; cat <= kLastCategory; cat++) {
out_str << "[" << cat << ": " << categories_lengths[cat] << " || "
<< std::fixed << std::setprecision(2)
<< static_cast<double>(categories_sums[cat]) / KB << " KB]"
<< (cat == kLastCategory ? "\n" : ", ");
}
PrintIsolate(isolate_, "%s", out_str.str().c_str());
}
void Heap::DumpJSONHeapStatistics(std::stringstream& stream) {
HeapStatistics stats;
reinterpret_cast<v8::Isolate*>(isolate())->GetHeapStatistics(&stats);
......
......@@ -483,6 +483,12 @@ class Heap {
// Print short heap statistics.
void PrintShortHeapStatistics();
// Print statistics of freelists of old_space:
// with FLAG_trace_gc_freelists: summary of each FreeListCategory.
// with FLAG_trace_gc_freelists_verbose: also prints the statistics of each
// FreeListCategory of each page.
void PrintFreeListsStats();
// Dump heap statistics in JSON format.
void DumpJSONHeapStatistics(std::stringstream& stream);
......
......@@ -567,6 +567,8 @@ void MarkCompactCollector::EnsureSweepingCompleted() {
heap()->code_space()->RefillFreeList();
heap()->map_space()->RefillFreeList();
heap()->tracer()->NotifySweepingCompleted();
#ifdef VERIFY_HEAP
if (FLAG_verify_heap && !evacuation()) {
FullEvacuationVerifier verifier(heap());
......
......@@ -3213,8 +3213,6 @@ void FreeList::PrintCategories(FreeListCategoryType type) {
PrintF("null\n");
}
#ifdef DEBUG
size_t FreeListCategory::SumFreeList() {
size_t sum = 0;
FreeSpace cur = top();
......@@ -3240,6 +3238,7 @@ int FreeListCategory::FreeListLength() {
return length;
}
#ifdef DEBUG
bool FreeList::IsVeryLong() {
int len = 0;
for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
......
......@@ -188,10 +188,8 @@ class FreeListCategory {
void set_free_list(FreeList* free_list) { free_list_ = free_list; }
#ifdef DEBUG
size_t SumFreeList();
int FreeListLength();
#endif
private:
// For debug builds we accurately compute free lists lengths up until
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment