Commit d826e2de authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

cppgc: Add AllocationObserver::ResetAllocatedObjectSize

The observers can use ResetAllocatedObjectSize() to e.g. implement a
growing strategy that resets its limit on this call.

Bug: chromium:1056170
Change-Id: Ib9553e00cc530ff89f44e4258c13d47f0b70568e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2228885Reviewed-by: 's avatarAnton Bikineev <bikineev@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68205}
parent 47e501e1
......@@ -83,6 +83,10 @@ void StatsCollector::NotifyMarkingCompleted(size_t marked_bytes) {
allocated_bytes_since_end_of_marking_ = 0;
allocated_bytes_since_safepoint_ = 0;
explicitly_freed_bytes_since_safepoint_ = 0;
ForAllAllocationObservers([marked_bytes](AllocationObserver* observer) {
observer->ResetAllocatedObjectSize(marked_bytes);
});
}
const StatsCollector::Event& StatsCollector::NotifySweepingCompleted() {
......
......@@ -27,6 +27,8 @@ class V8_EXPORT_PRIVATE StatsCollector final {
size_t marked_bytes = 0;
};
// Observer for allocated object size. May be used to implement heap growing
// heuristics.
class AllocationObserver {
public:
// Called after observing at least
......@@ -38,6 +40,12 @@ class V8_EXPORT_PRIVATE StatsCollector final {
// May trigger GC.
virtual void AllocatedObjectSizeIncreased(size_t) = 0;
virtual void AllocatedObjectSizeDecreased(size_t) = 0;
// Called when the exact size of allocated object size is known. In
// practice, this is after marking when marked bytes == allocated bytes.
//
// Must not trigger GC synchronously.
virtual void ResetAllocatedObjectSize(size_t) = 0;
};
// Observers are implemented using virtual calls. Avoid notifications below
......
......@@ -105,6 +105,7 @@ class MockAllocationObserver : public StatsCollector::AllocationObserver {
public:
MOCK_METHOD1(AllocatedObjectSizeIncreased, void(size_t));
MOCK_METHOD1(AllocatedObjectSizeDecreased, void(size_t));
MOCK_METHOD1(ResetAllocatedObjectSize, void(size_t));
};
TEST_F(StatsCollectorTest, RegisterUnregisterObserver) {
......@@ -113,7 +114,7 @@ TEST_F(StatsCollectorTest, RegisterUnregisterObserver) {
stats.UnregisterObserver(&observer);
}
TEST_F(StatsCollectorTest, ObserveAllocatedObjectSize) {
TEST_F(StatsCollectorTest, ObserveAllocatedObjectSizeIncreaseAndDecrease) {
MockAllocationObserver observer;
stats.RegisterObserver(&observer);
EXPECT_CALL(observer, AllocatedObjectSizeIncreased(kMinReportedSize));
......@@ -131,39 +132,63 @@ void FakeGC(StatsCollector* stats, size_t marked_bytes) {
stats->NotifySweepingCompleted();
}
} // namespace
TEST_F(StatsCollectorTest, ObserveResetAllocatedObjectSize) {
MockAllocationObserver observer;
stats.RegisterObserver(&observer);
EXPECT_CALL(observer, AllocatedObjectSizeIncreased(kMinReportedSize));
FakeAllocate(kMinReportedSize);
EXPECT_CALL(observer, ResetAllocatedObjectSize(64));
FakeGC(&stats, 64);
stats.UnregisterObserver(&observer);
}
namespace {
class AllocationObserverTriggeringGC final
: public StatsCollector::AllocationObserver {
public:
explicit AllocationObserverTriggeringGC(StatsCollector* stats)
: stats(stats) {}
AllocationObserverTriggeringGC(StatsCollector* stats, double survival_ratio)
: stats(stats), survival_ratio_(survival_ratio) {}
void AllocatedObjectSizeIncreased(size_t bytes) final {
increase_call_count++;
increased_size_bytes += bytes;
if (increase_call_count == 1) {
FakeGC(stats, bytes);
FakeGC(stats, bytes * survival_ratio_);
}
}
// // Mock out the rest to trigger warnings if used.
MOCK_METHOD1(AllocatedObjectSizeDecreased, void(size_t));
MOCK_METHOD1(ResetAllocatedObjectSize, void(size_t));
size_t increase_call_count = 0;
size_t increased_size_bytes = 0;
StatsCollector* stats;
double survival_ratio_;
};
} // namespace
TEST_F(StatsCollectorTest, ObserverTriggersGC) {
AllocationObserverTriggeringGC gc_observer(&stats);
constexpr double kSurvivalRatio = 0.5;
AllocationObserverTriggeringGC gc_observer(&stats, kSurvivalRatio);
MockAllocationObserver mock_observer;
// // Internal detail: First registered observer is also notified first.
// Internal detail: First registered observer is also notified first.
stats.RegisterObserver(&gc_observer);
stats.RegisterObserver(&mock_observer);
// Since the GC clears counters, it should see an increase call with a delta
// of zero bytes.
// Both observers see the exact allocated object size byte count.
EXPECT_CALL(mock_observer,
ResetAllocatedObjectSize(kMinReportedSize * kSurvivalRatio));
EXPECT_CALL(gc_observer,
ResetAllocatedObjectSize(kMinReportedSize * kSurvivalRatio));
// Since the GC clears counters, mock_observer should see an increase call
// with a delta of zero bytes. This expectation makes use of the internal
// detail that first registered observer triggers GC.
EXPECT_CALL(mock_observer, AllocatedObjectSizeIncreased(0));
// Trigger scenario.
......
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