88e5b8f503
This CL does 2 things: 1) Implements forwarding of histogram reporting from cppgc to v8 via CppHeap. 2) Establishes the pipeline in GCTracer for sending the histograms to the embedder. Currently only cppgc histograms are populated. See crrev.com/c/2916956 for usage. Bug: chromium:1154636 Change-Id: I8150116f757e105d0dfac96a3f6e7dd95717f5bd Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2917033 Commit-Queue: Omer Katz <omerkatz@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#74830}
326 lines
12 KiB
C++
326 lines
12 KiB
C++
// Copyright 2020 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/heap/cppgc/metric-recorder.h"
|
|
|
|
#include "src/heap/cppgc/stats-collector.h"
|
|
#include "test/unittests/heap/cppgc/tests.h"
|
|
|
|
namespace cppgc {
|
|
namespace internal {
|
|
|
|
namespace {
|
|
class MetricRecorderImpl final : public MetricRecorder {
|
|
public:
|
|
void AddMainThreadEvent(const FullCycle& event) final {
|
|
FullCycle_event = event;
|
|
FullCycle_callcount++;
|
|
}
|
|
void AddMainThreadEvent(const MainThreadIncrementalMark& event) final {
|
|
MainThreadIncrementalMark_event = event;
|
|
MainThreadIncrementalMark_callcount++;
|
|
}
|
|
void AddMainThreadEvent(const MainThreadIncrementalSweep& event) final {
|
|
MainThreadIncrementalSweep_event = event;
|
|
MainThreadIncrementalSweep_callcount++;
|
|
}
|
|
|
|
static size_t FullCycle_callcount;
|
|
static FullCycle FullCycle_event;
|
|
static size_t MainThreadIncrementalMark_callcount;
|
|
static MainThreadIncrementalMark MainThreadIncrementalMark_event;
|
|
static size_t MainThreadIncrementalSweep_callcount;
|
|
static MainThreadIncrementalSweep MainThreadIncrementalSweep_event;
|
|
};
|
|
|
|
// static
|
|
size_t MetricRecorderImpl::FullCycle_callcount = 0u;
|
|
MetricRecorderImpl::FullCycle MetricRecorderImpl::FullCycle_event;
|
|
size_t MetricRecorderImpl::MainThreadIncrementalMark_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalMark
|
|
MetricRecorderImpl::MainThreadIncrementalMark_event;
|
|
size_t MetricRecorderImpl::MainThreadIncrementalSweep_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalSweep
|
|
MetricRecorderImpl::MainThreadIncrementalSweep_event;
|
|
|
|
class MetricRecorderTest : public testing::TestWithHeap {
|
|
public:
|
|
MetricRecorderTest() : stats(Heap::From(GetHeap())->stats_collector()) {
|
|
stats->SetMetricRecorder(std::make_unique<MetricRecorderImpl>());
|
|
}
|
|
|
|
void StartGC() {
|
|
stats->NotifyMarkingStarted(
|
|
GarbageCollector::Config::CollectionType::kMajor,
|
|
GarbageCollector::Config::IsForcedGC::kNotForced);
|
|
}
|
|
void EndGC(size_t marked_bytes) {
|
|
stats->NotifyMarkingCompleted(marked_bytes);
|
|
stats->NotifySweepingCompleted();
|
|
}
|
|
|
|
StatsCollector* stats;
|
|
};
|
|
} // namespace
|
|
|
|
TEST_F(MetricRecorderTest, IncrementalScopesReportedImmediately) {
|
|
MetricRecorderImpl::FullCycle_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalMark_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalSweep_callcount = 0u;
|
|
StartGC();
|
|
{
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalMark_callcount);
|
|
{
|
|
StatsCollector::EnabledScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kIncrementalMark);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(1));
|
|
}
|
|
EXPECT_EQ(1u, MetricRecorderImpl::MainThreadIncrementalMark_callcount);
|
|
EXPECT_LT(0u,
|
|
MetricRecorderImpl::MainThreadIncrementalMark_event.duration_us);
|
|
}
|
|
{
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalSweep_callcount);
|
|
{
|
|
StatsCollector::EnabledScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kIncrementalSweep);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(1));
|
|
}
|
|
EXPECT_EQ(1u, MetricRecorderImpl::MainThreadIncrementalSweep_callcount);
|
|
EXPECT_LT(0u,
|
|
MetricRecorderImpl::MainThreadIncrementalSweep_event.duration_us);
|
|
}
|
|
EXPECT_EQ(0u, MetricRecorderImpl::FullCycle_callcount);
|
|
EndGC(0);
|
|
}
|
|
|
|
TEST_F(MetricRecorderTest, NonIncrementlaScopesNotReportedImmediately) {
|
|
MetricRecorderImpl::FullCycle_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalMark_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalSweep_callcount = 0u;
|
|
StartGC();
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicMark);
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicWeak);
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicCompact);
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicSweep);
|
|
}
|
|
{
|
|
StatsCollector::EnabledConcurrentScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kConcurrentMark);
|
|
}
|
|
{
|
|
StatsCollector::EnabledConcurrentScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kConcurrentSweep);
|
|
}
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalMark_callcount);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalSweep_callcount);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::FullCycle_callcount);
|
|
EndGC(0);
|
|
}
|
|
|
|
TEST_F(MetricRecorderTest, CycleEndMetricsReportedOnGcEnd) {
|
|
MetricRecorderImpl::FullCycle_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalMark_callcount = 0u;
|
|
MetricRecorderImpl::MainThreadIncrementalSweep_callcount = 0u;
|
|
StartGC();
|
|
EndGC(0);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalMark_callcount);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::MainThreadIncrementalSweep_callcount);
|
|
EXPECT_EQ(1u, MetricRecorderImpl::FullCycle_callcount);
|
|
}
|
|
|
|
TEST_F(MetricRecorderTest, CycleEndHistogramReportsCorrectValues) {
|
|
StartGC();
|
|
{
|
|
// Warmup scope to make sure everything is loaded in memory and reduce noise
|
|
// in timing measurements.
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kIncrementalMark);
|
|
}
|
|
EndGC(1000);
|
|
StartGC();
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kIncrementalMark);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(10));
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kIncrementalSweep);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(20));
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicMark);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(30));
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicWeak);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(50));
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicCompact);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(60));
|
|
}
|
|
{
|
|
StatsCollector::EnabledScope scope(Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kAtomicSweep);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(70));
|
|
}
|
|
{
|
|
StatsCollector::EnabledConcurrentScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kConcurrentMark);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(80));
|
|
}
|
|
{
|
|
StatsCollector::EnabledConcurrentScope scope(
|
|
Heap::From(GetHeap())->stats_collector(),
|
|
StatsCollector::kConcurrentSweep);
|
|
scope.DecreaseStartTimeForTesting(
|
|
v8::base::TimeDelta::FromMilliseconds(100));
|
|
}
|
|
EndGC(300);
|
|
// Check durations.
|
|
static constexpr int64_t kDurationComparisonTolerance = 5000;
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_incremental
|
|
.mark_duration_us -
|
|
10000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_incremental
|
|
.sweep_duration_us -
|
|
20000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_atomic
|
|
.mark_duration_us -
|
|
30000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_atomic
|
|
.weak_duration_us -
|
|
50000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_atomic
|
|
.compact_duration_us -
|
|
60000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event.main_thread_atomic
|
|
.sweep_duration_us -
|
|
70000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(
|
|
MetricRecorderImpl::FullCycle_event.main_thread.mark_duration_us -
|
|
40000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(
|
|
MetricRecorderImpl::FullCycle_event.main_thread.weak_duration_us -
|
|
50000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(
|
|
MetricRecorderImpl::FullCycle_event.main_thread.compact_duration_us -
|
|
60000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(
|
|
MetricRecorderImpl::FullCycle_event.main_thread.sweep_duration_us -
|
|
90000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(MetricRecorderImpl::FullCycle_event.total.mark_duration_us -
|
|
120000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(MetricRecorderImpl::FullCycle_event.total.weak_duration_us -
|
|
50000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(MetricRecorderImpl::FullCycle_event.total.compact_duration_us -
|
|
60000),
|
|
kDurationComparisonTolerance);
|
|
EXPECT_LT(
|
|
std::abs(MetricRecorderImpl::FullCycle_event.total.sweep_duration_us -
|
|
190000),
|
|
kDurationComparisonTolerance);
|
|
// Check collection rate and efficiency.
|
|
EXPECT_DOUBLE_EQ(
|
|
0.3, MetricRecorderImpl::FullCycle_event.collection_rate_in_percent);
|
|
static constexpr double kEfficiencyComparisonTolerance = 0.0005;
|
|
EXPECT_LT(
|
|
std::abs(MetricRecorderImpl::FullCycle_event.efficiency_in_bytes_per_us -
|
|
(700.0 / (120000 + 50000 + 60000 + 190000))),
|
|
kEfficiencyComparisonTolerance);
|
|
EXPECT_LT(std::abs(MetricRecorderImpl::FullCycle_event
|
|
.main_thread_efficiency_in_bytes_per_us -
|
|
(700.0 / (40000 + 50000 + 60000 + 90000))),
|
|
kEfficiencyComparisonTolerance);
|
|
}
|
|
|
|
TEST_F(MetricRecorderTest, ObjectSizeMetricsNoAllocations) {
|
|
// Populate previous event.
|
|
StartGC();
|
|
EndGC(1000);
|
|
// Populate current event.
|
|
StartGC();
|
|
EndGC(800);
|
|
EXPECT_EQ(1000u, MetricRecorderImpl::FullCycle_event.objects.before_bytes);
|
|
EXPECT_EQ(800u, MetricRecorderImpl::FullCycle_event.objects.after_bytes);
|
|
EXPECT_EQ(200u, MetricRecorderImpl::FullCycle_event.objects.freed_bytes);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::FullCycle_event.memory.before_bytes);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::FullCycle_event.memory.after_bytes);
|
|
EXPECT_EQ(0u, MetricRecorderImpl::FullCycle_event.memory.freed_bytes);
|
|
}
|
|
|
|
TEST_F(MetricRecorderTest, ObjectSizeMetricsWithAllocations) {
|
|
// Populate previous event.
|
|
StartGC();
|
|
EndGC(1000);
|
|
// Populate current event.
|
|
StartGC();
|
|
stats->NotifyAllocation(300);
|
|
stats->NotifyAllocatedMemory(1400);
|
|
stats->NotifyFreedMemory(700);
|
|
stats->NotifyMarkingCompleted(800);
|
|
stats->NotifyAllocation(150);
|
|
stats->NotifyAllocatedMemory(1000);
|
|
stats->NotifyFreedMemory(400);
|
|
stats->NotifySweepingCompleted();
|
|
EXPECT_EQ(1300u, MetricRecorderImpl::FullCycle_event.objects.before_bytes);
|
|
EXPECT_EQ(800, MetricRecorderImpl::FullCycle_event.objects.after_bytes);
|
|
EXPECT_EQ(500u, MetricRecorderImpl::FullCycle_event.objects.freed_bytes);
|
|
EXPECT_EQ(700u, MetricRecorderImpl::FullCycle_event.memory.before_bytes);
|
|
EXPECT_EQ(300u, MetricRecorderImpl::FullCycle_event.memory.after_bytes);
|
|
EXPECT_EQ(400u, MetricRecorderImpl::FullCycle_event.memory.freed_bytes);
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace cppgc
|