[heap] Introduce getters for MemoryReducer::State
This CL hides the ctor of the MemoryReducer::State class and only provides factory methods for creating states. This simplifies creation of states and makes it impossible to misuse the API. Direct field accesses are also replaced with invocations of their corresponding getter methods. The getter method will check whether the current state is allowed to access that field. Bug: v8:13653 Change-Id: I252a6d75d0ddb4813b16a706061ad1951cfa35ea Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4181026 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Dominik Inführ <dinfuehr@chromium.org> Cr-Commit-Position: refs/heads/main@{#85426}
This commit is contained in:
parent
417ce7ef46
commit
d31e52879b
@ -25,7 +25,7 @@ MemoryReducer::MemoryReducer(Heap* heap)
|
||||
: heap_(heap),
|
||||
taskrunner_(V8::GetCurrentPlatform()->GetForegroundTaskRunner(
|
||||
reinterpret_cast<v8::Isolate*>(heap->isolate()))),
|
||||
state_(kDone, 0, 0.0, 0.0, 0),
|
||||
state_(State::CreateUninitialized()),
|
||||
js_calls_counter_(0),
|
||||
js_calls_sample_time_ms_(0.0) {}
|
||||
|
||||
@ -66,19 +66,19 @@ void MemoryReducer::TimerTask::RunInternal() {
|
||||
|
||||
void MemoryReducer::NotifyTimer(const Event& event) {
|
||||
DCHECK_EQ(kTimer, event.type);
|
||||
DCHECK_EQ(kWait, state_.action);
|
||||
DCHECK_EQ(kWait, state_.id());
|
||||
state_ = Step(state_, event);
|
||||
if (state_.action == kRun) {
|
||||
if (state_.id() == kRun) {
|
||||
DCHECK(heap()->incremental_marking()->IsStopped());
|
||||
DCHECK(v8_flags.incremental_marking);
|
||||
if (v8_flags.trace_gc_verbose) {
|
||||
heap()->isolate()->PrintWithTimestamp("Memory reducer: started GC #%d\n",
|
||||
state_.started_gcs);
|
||||
state_.started_gcs());
|
||||
}
|
||||
heap()->StartIdleIncrementalMarking(
|
||||
GarbageCollectionReason::kMemoryReducer,
|
||||
kGCCallbackFlagCollectAllExternalMemory);
|
||||
} else if (state_.action == kWait) {
|
||||
} else if (state_.id() == kWait) {
|
||||
if (!heap()->incremental_marking()->IsStopped() &&
|
||||
heap()->ShouldOptimizeForMemoryUsage()) {
|
||||
// Make progress with pending incremental marking if memory usage has
|
||||
@ -87,11 +87,11 @@ void MemoryReducer::NotifyTimer(const Event& event) {
|
||||
heap()->incremental_marking()->AdvanceAndFinalizeIfComplete();
|
||||
}
|
||||
// Re-schedule the timer.
|
||||
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
|
||||
ScheduleTimer(state_.next_gc_start_ms() - event.time_ms);
|
||||
if (v8_flags.trace_gc_verbose) {
|
||||
heap()->isolate()->PrintWithTimestamp(
|
||||
"Memory reducer: waiting for %.f ms\n",
|
||||
state_.next_gc_start_ms - event.time_ms);
|
||||
state_.next_gc_start_ms() - event.time_ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,17 +110,17 @@ void MemoryReducer::NotifyMarkCompact(size_t committed_memory_before) {
|
||||
heap()->HasHighFragmentation(),
|
||||
false,
|
||||
false};
|
||||
const Action old_action = state_.action;
|
||||
const Id old_action = state_.id();
|
||||
state_ = Step(state_, event);
|
||||
if (old_action != kWait && state_.action == kWait) {
|
||||
if (old_action != kWait && state_.id() == kWait) {
|
||||
// If we are transitioning to the WAIT state, start the timer.
|
||||
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
|
||||
ScheduleTimer(state_.next_gc_start_ms() - event.time_ms);
|
||||
}
|
||||
if (old_action == kRun) {
|
||||
if (v8_flags.trace_gc_verbose) {
|
||||
heap()->isolate()->PrintWithTimestamp(
|
||||
"Memory reducer: finished GC #%d (%s)\n", state_.started_gcs,
|
||||
state_.action == kWait ? "will do more" : "done");
|
||||
"Memory reducer: finished GC #%d (%s)\n", state_.started_gcs(),
|
||||
state_.id() == kWait ? "will do more" : "done");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,17 +132,17 @@ void MemoryReducer::NotifyPossibleGarbage() {
|
||||
0,
|
||||
false,
|
||||
false};
|
||||
const Action old_action = state_.action;
|
||||
const Id old_action = state_.id();
|
||||
state_ = Step(state_, event);
|
||||
if (old_action != kWait && state_.action == kWait) {
|
||||
if (old_action != kWait && state_.id() == kWait) {
|
||||
// If we are transitioning to the WAIT state, start the timer.
|
||||
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
|
||||
ScheduleTimer(state_.next_gc_start_ms() - event.time_ms);
|
||||
}
|
||||
}
|
||||
|
||||
bool MemoryReducer::WatchdogGC(const State& state, const Event& event) {
|
||||
return state.last_gc_time_ms != 0 &&
|
||||
event.time_ms > state.last_gc_time_ms + kWatchdogDelayMs;
|
||||
return state.last_gc_time_ms() != 0 &&
|
||||
event.time_ms > state.last_gc_time_ms() + kWatchdogDelayMs;
|
||||
}
|
||||
|
||||
|
||||
@ -150,63 +150,64 @@ bool MemoryReducer::WatchdogGC(const State& state, const Event& event) {
|
||||
MemoryReducer::State MemoryReducer::Step(const State& state,
|
||||
const Event& event) {
|
||||
if (!v8_flags.incremental_marking || !v8_flags.memory_reducer) {
|
||||
return State(kDone, 0, 0, state.last_gc_time_ms, 0);
|
||||
return State::CreateUninitialized();
|
||||
}
|
||||
switch (state.action) {
|
||||
switch (state.id()) {
|
||||
case kDone:
|
||||
if (event.type == kTimer) {
|
||||
return state;
|
||||
} else if (event.type == kMarkCompact) {
|
||||
if (event.committed_memory <
|
||||
std::max(
|
||||
static_cast<size_t>(state.committed_memory_at_last_run *
|
||||
static_cast<size_t>(state.committed_memory_at_last_run() *
|
||||
kCommittedMemoryFactor),
|
||||
state.committed_memory_at_last_run + kCommittedMemoryDelta)) {
|
||||
state.committed_memory_at_last_run() + kCommittedMemoryDelta)) {
|
||||
return state;
|
||||
} else {
|
||||
return State(kWait, 0, event.time_ms + kLongDelayMs, event.time_ms,
|
||||
0);
|
||||
return State::CreateWait(0, event.time_ms + kLongDelayMs,
|
||||
event.time_ms);
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(kPossibleGarbage, event.type);
|
||||
return State(kWait, 0,
|
||||
event.time_ms + v8_flags.gc_memory_reducer_start_delay_ms,
|
||||
state.last_gc_time_ms, 0);
|
||||
return State::CreateWait(
|
||||
0, event.time_ms + v8_flags.gc_memory_reducer_start_delay_ms,
|
||||
state.last_gc_time_ms());
|
||||
}
|
||||
case kWait:
|
||||
switch (event.type) {
|
||||
case kPossibleGarbage:
|
||||
return state;
|
||||
case kTimer:
|
||||
if (state.started_gcs >= kMaxNumberOfGCs) {
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, state.last_gc_time_ms,
|
||||
event.committed_memory);
|
||||
if (state.started_gcs() >= kMaxNumberOfGCs) {
|
||||
return State::CreateDone(state.last_gc_time_ms(),
|
||||
event.committed_memory);
|
||||
} else if (event.can_start_incremental_gc &&
|
||||
(event.should_start_incremental_gc ||
|
||||
WatchdogGC(state, event))) {
|
||||
if (state.next_gc_start_ms <= event.time_ms) {
|
||||
return State(kRun, state.started_gcs + 1, 0.0,
|
||||
state.last_gc_time_ms, 0);
|
||||
if (state.next_gc_start_ms() <= event.time_ms) {
|
||||
return State::CreateRun(state.started_gcs() + 1);
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
} else {
|
||||
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs,
|
||||
state.last_gc_time_ms, 0);
|
||||
return State::CreateWait(state.started_gcs(),
|
||||
event.time_ms + kLongDelayMs,
|
||||
state.last_gc_time_ms());
|
||||
}
|
||||
case kMarkCompact:
|
||||
return State(kWait, state.started_gcs, event.time_ms + kLongDelayMs,
|
||||
event.time_ms, 0);
|
||||
return State::CreateWait(state.started_gcs(),
|
||||
event.time_ms + kLongDelayMs, event.time_ms);
|
||||
}
|
||||
case kRun:
|
||||
if (event.type == kMarkCompact) {
|
||||
if (state.started_gcs < kMaxNumberOfGCs &&
|
||||
(event.next_gc_likely_to_collect_more || state.started_gcs == 1)) {
|
||||
return State(kWait, state.started_gcs, event.time_ms + kShortDelayMs,
|
||||
event.time_ms, 0);
|
||||
if (state.started_gcs() < kMaxNumberOfGCs &&
|
||||
(event.next_gc_likely_to_collect_more ||
|
||||
state.started_gcs() == 1)) {
|
||||
return State::CreateWait(state.started_gcs(),
|
||||
event.time_ms + kShortDelayMs,
|
||||
event.time_ms);
|
||||
} else {
|
||||
return State(kDone, kMaxNumberOfGCs, 0.0, event.time_ms,
|
||||
event.committed_memory);
|
||||
return State::CreateDone(event.time_ms, event.committed_memory);
|
||||
}
|
||||
} else {
|
||||
return state;
|
||||
@ -224,7 +225,7 @@ void MemoryReducer::ScheduleTimer(double delay_ms) {
|
||||
(delay_ms + kSlackMs) / 1000.0);
|
||||
}
|
||||
|
||||
void MemoryReducer::TearDown() { state_ = State(kDone, 0, 0, 0.0, 0); }
|
||||
void MemoryReducer::TearDown() { state_ = State::CreateUninitialized(); }
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -86,21 +86,61 @@ class Heap;
|
||||
// long_delay_ms, short_delay_ms, and watchdog_delay_ms are constants.
|
||||
class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
public:
|
||||
enum Action { kDone, kWait, kRun };
|
||||
enum Id { kDone, kWait, kRun };
|
||||
|
||||
struct State {
|
||||
State(Action action, int started_gcs, double next_gc_start_ms,
|
||||
class State {
|
||||
public:
|
||||
static State CreateUninitialized() { return {kDone, 0, 0, 0, 0}; }
|
||||
|
||||
static State CreateDone(double last_gc_time_ms, size_t committed_memory) {
|
||||
return {kDone, kMaxNumberOfGCs, 0, last_gc_time_ms, committed_memory};
|
||||
}
|
||||
|
||||
static State CreateWait(int started_gcs, double next_gc_time_ms,
|
||||
double last_gc_time_ms) {
|
||||
return {kWait, started_gcs, next_gc_time_ms, last_gc_time_ms, 0};
|
||||
}
|
||||
|
||||
static State CreateRun(int started_gcs) {
|
||||
return {kRun, started_gcs, 0, 0, 0};
|
||||
}
|
||||
|
||||
Id id() const { return id_; }
|
||||
|
||||
int started_gcs() const {
|
||||
DCHECK(id() == kWait || id() == kRun || id() == kDone);
|
||||
return started_gcs_;
|
||||
}
|
||||
|
||||
double next_gc_start_ms() const {
|
||||
DCHECK_EQ(id(), kWait);
|
||||
return next_gc_start_ms_;
|
||||
}
|
||||
|
||||
double last_gc_time_ms() const {
|
||||
DCHECK(id() == kWait || id() == kDone);
|
||||
return last_gc_time_ms_;
|
||||
}
|
||||
|
||||
size_t committed_memory_at_last_run() const {
|
||||
DCHECK_EQ(id(), kDone);
|
||||
return committed_memory_at_last_run_;
|
||||
}
|
||||
|
||||
private:
|
||||
State(Id action, int started_gcs, double next_gc_start_ms,
|
||||
double last_gc_time_ms, size_t committed_memory_at_last_run)
|
||||
: action(action),
|
||||
started_gcs(started_gcs),
|
||||
next_gc_start_ms(next_gc_start_ms),
|
||||
last_gc_time_ms(last_gc_time_ms),
|
||||
committed_memory_at_last_run(committed_memory_at_last_run) {}
|
||||
Action action;
|
||||
int started_gcs;
|
||||
double next_gc_start_ms;
|
||||
double last_gc_time_ms;
|
||||
size_t committed_memory_at_last_run;
|
||||
: id_(action),
|
||||
started_gcs_(started_gcs),
|
||||
next_gc_start_ms_(next_gc_start_ms),
|
||||
last_gc_time_ms_(last_gc_time_ms),
|
||||
committed_memory_at_last_run_(committed_memory_at_last_run) {}
|
||||
|
||||
Id id_;
|
||||
int started_gcs_;
|
||||
double next_gc_start_ms_;
|
||||
double last_gc_time_ms_;
|
||||
size_t committed_memory_at_last_run_;
|
||||
};
|
||||
|
||||
enum EventType { kTimer, kMarkCompact, kPossibleGarbage };
|
||||
@ -140,7 +180,7 @@ class V8_EXPORT_PRIVATE MemoryReducer {
|
||||
Heap* heap() { return heap_; }
|
||||
|
||||
bool ShouldGrowHeapSlowly() {
|
||||
return state_.action == kDone && state_.started_gcs > 0;
|
||||
return state_.id() == kDone && state_.started_gcs() > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -6982,7 +6982,7 @@ HEAP_TEST(MemoryReducerActivationForSmallHeaps) {
|
||||
LocalContext env;
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Heap* heap = isolate->heap();
|
||||
CHECK_EQ(heap->memory_reducer()->state_.action, MemoryReducer::Action::kDone);
|
||||
CHECK_EQ(heap->memory_reducer()->state_.id(), MemoryReducer::kDone);
|
||||
HandleScope scope(isolate);
|
||||
const size_t kActivationThreshold = 1 * MB;
|
||||
size_t initial_capacity = heap->OldGenerationCapacity();
|
||||
@ -6990,7 +6990,7 @@ HEAP_TEST(MemoryReducerActivationForSmallHeaps) {
|
||||
initial_capacity + kActivationThreshold) {
|
||||
isolate->factory()->NewFixedArray(1 * KB, AllocationType::kOld);
|
||||
}
|
||||
CHECK_EQ(heap->memory_reducer()->state_.action, MemoryReducer::Action::kWait);
|
||||
CHECK_EQ(heap->memory_reducer()->state_.id(), MemoryReducer::kWait);
|
||||
}
|
||||
|
||||
TEST(AllocateExternalBackingStore) {
|
||||
|
@ -11,26 +11,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
MemoryReducer::State DoneState() {
|
||||
return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0, 0);
|
||||
}
|
||||
|
||||
MemoryReducer::State DoneState(size_t committed_memory) {
|
||||
return MemoryReducer::State(MemoryReducer::kDone, 0, 0.0, 1.0,
|
||||
committed_memory);
|
||||
}
|
||||
|
||||
MemoryReducer::State WaitState(int started_gcs, double next_gc_start_ms) {
|
||||
return MemoryReducer::State(MemoryReducer::kWait, started_gcs,
|
||||
next_gc_start_ms, 1.0, 0);
|
||||
}
|
||||
|
||||
|
||||
MemoryReducer::State RunState(int started_gcs, double next_gc_start_ms) {
|
||||
return MemoryReducer::State(MemoryReducer::kRun, started_gcs,
|
||||
next_gc_start_ms, 1.0, 0);
|
||||
}
|
||||
|
||||
MemoryReducer::Event MarkCompactEvent(double time_ms,
|
||||
bool next_gc_likely_to_collect_more,
|
||||
size_t committed_memory) {
|
||||
@ -88,248 +68,241 @@ MemoryReducer::Event PossibleGarbageEvent(double time_ms) {
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromDoneToDone) {
|
||||
MemoryReducer::State state0(DoneState()), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateDone(1.0, 0)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventGarbageLeft(0, MemoryReducer::kCommittedMemoryDelta - 1));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
|
||||
state0 = DoneState(1000 * MB);
|
||||
state0 = MemoryReducer::State::CreateDone(1, 1000 * MB);
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, MarkCompactEventGarbageLeft(
|
||||
0, static_cast<size_t>(
|
||||
1000 * MB * MemoryReducer::kCommittedMemoryFactor) -
|
||||
1));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromDoneToWait) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(DoneState()), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateDone(1.0, 0)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventGarbageLeft(2, MemoryReducer::kCommittedMemoryDelta));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(v8_flags.gc_memory_reducer_start_delay_ms + 2,
|
||||
state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms);
|
||||
state1.next_gc_start_ms());
|
||||
EXPECT_EQ(0, state1.started_gcs());
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms());
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
MarkCompactEventNoGarbageLeft(2, MemoryReducer::kCommittedMemoryDelta));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(v8_flags.gc_memory_reducer_start_delay_ms + 2,
|
||||
state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms);
|
||||
state1.next_gc_start_ms());
|
||||
EXPECT_EQ(0, state1.started_gcs());
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(v8_flags.gc_memory_reducer_start_delay_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(v8_flags.gc_memory_reducer_start_delay_ms,
|
||||
state1.next_gc_start_ms());
|
||||
EXPECT_EQ(0, state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
|
||||
state0 = DoneState(1000 * MB);
|
||||
state0 = MemoryReducer::State::CreateDone(1, 1000 * MB);
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, MarkCompactEventGarbageLeft(
|
||||
2, static_cast<size_t>(
|
||||
1000 * MB * MemoryReducer::kCommittedMemoryFactor)));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(v8_flags.gc_memory_reducer_start_delay_ms + 2,
|
||||
state1.next_gc_start_ms);
|
||||
EXPECT_EQ(0, state1.started_gcs);
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms);
|
||||
state1.next_gc_start_ms());
|
||||
EXPECT_EQ(0, state1.started_gcs());
|
||||
EXPECT_EQ(2, state1.last_gc_time_ms());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromWaitToWait) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(WaitState(2, 1000.0)), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateWait(2, 1000.0, 1)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(state0.next_gc_start_ms(), state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, TimerEventLowAllocationRate(state0.next_gc_start_ms - 1));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
state0, TimerEventLowAllocationRate(state0.next_gc_start_ms() - 1));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(state0.next_gc_start_ms(), state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms());
|
||||
|
||||
state0 = MemoryReducer::State::CreateWait(2, 1000.0, 0);
|
||||
|
||||
state0.last_gc_time_ms = 0;
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 1));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(MemoryReducer::kWatchdogDelayMs + 1 + MemoryReducer::kLongDelayMs,
|
||||
state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
|
||||
state0.last_gc_time_ms = 1;
|
||||
state0 = MemoryReducer::State::CreateWait(2, 1000.0, 1);
|
||||
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kLongDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromWaitToRun) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(WaitState(0, 1000.0)), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateWait(0, 1000.0, 1)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0, TimerEventLowAllocationRate(state0.next_gc_start_ms + 1));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs);
|
||||
state0, TimerEventLowAllocationRate(state0.next_gc_start_ms() + 1));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs() + 1, state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(
|
||||
state0,
|
||||
TimerEventHighAllocationRate(MemoryReducer::kWatchdogDelayMs + 2));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs + 1, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs() + 1, state1.started_gcs());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromWaitToDone) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(WaitState(2, 0.0)), state1(DoneState());
|
||||
|
||||
state0.started_gcs = MemoryReducer::kMaxNumberOfGCs;
|
||||
MemoryReducer::State state0(
|
||||
MemoryReducer::State::CreateWait(MemoryReducer::kMaxNumberOfGCs, 0.0, 1)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs());
|
||||
EXPECT_EQ(state0.last_gc_time_ms(), state1.last_gc_time_ms());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromRunToRun) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(RunState(1, 0.0)), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateRun(1)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventLowAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventHighAllocationRate(2000));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, TimerEventPendingGC(2000));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
|
||||
state1 = MemoryReducer::Step(state0, PossibleGarbageEvent(2000));
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.action);
|
||||
EXPECT_EQ(state0.next_gc_start_ms, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(state0.last_gc_time_ms, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kRun, state1.id());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromRunToDone) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateRun(2)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
EXPECT_EQ(MemoryReducer::kMaxNumberOfGCs, state1.started_gcs());
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms());
|
||||
|
||||
state0.started_gcs = MemoryReducer::kMaxNumberOfGCs;
|
||||
state0 = MemoryReducer::State::CreateRun(MemoryReducer::kMaxNumberOfGCs);
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.action);
|
||||
EXPECT_EQ(0, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kDone, state1.id());
|
||||
EXPECT_EQ(state1.started_gcs(), state1.started_gcs());
|
||||
}
|
||||
|
||||
|
||||
TEST(MemoryReducer, FromRunToWait) {
|
||||
if (!v8_flags.incremental_marking) return;
|
||||
|
||||
MemoryReducer::State state0(RunState(2, 0.0)), state1(DoneState());
|
||||
MemoryReducer::State state0(MemoryReducer::State::CreateRun(2)),
|
||||
state1(MemoryReducer::State::CreateDone(1.0, 0));
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms());
|
||||
|
||||
state0.started_gcs = 1;
|
||||
state0 = MemoryReducer::State::CreateRun(1);
|
||||
|
||||
state1 = MemoryReducer::Step(state0, MarkCompactEventNoGarbageLeft(2000, 0));
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.action);
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms);
|
||||
EXPECT_EQ(state0.started_gcs, state1.started_gcs);
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms);
|
||||
EXPECT_EQ(MemoryReducer::kWait, state1.id());
|
||||
EXPECT_EQ(2000 + MemoryReducer::kShortDelayMs, state1.next_gc_start_ms());
|
||||
EXPECT_EQ(state0.started_gcs(), state1.started_gcs());
|
||||
EXPECT_EQ(2000, state1.last_gc_time_ms());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
Loading…
Reference in New Issue
Block a user