Commit ff8f4144 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Simplify idle notification handler

This merges the "do-nothing" case with the "done" case as the former
is no longer useful. This also fixes a bug where the idle time handler
would not make progress by always returning "do-nothing".

Change-Id: Ibdd3189e4fd35acc5405aa82a13ea8ee2fd74cc6
Reviewed-on: https://chromium-review.googlesource.com/c/1478695
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59758}
parent 511400ca
...@@ -17,27 +17,6 @@ const double GCIdleTimeHandler::kHighContextDisposalRate = 100; ...@@ -17,27 +17,6 @@ const double GCIdleTimeHandler::kHighContextDisposalRate = 100;
const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1; const size_t GCIdleTimeHandler::kMinTimeForOverApproximatingWeakClosureInMs = 1;
void GCIdleTimeAction::Print() {
switch (type) {
case DONE:
PrintF("done");
break;
case DO_NOTHING:
PrintF("no action");
break;
case DO_INCREMENTAL_STEP:
PrintF("incremental step");
if (additional_work) {
PrintF("; finalized marking");
}
break;
case DO_FULL_GC:
PrintF("full GC");
break;
}
}
void GCIdleTimeHeapState::Print() { void GCIdleTimeHeapState::Print() {
PrintF("contexts_disposed=%d ", contexts_disposed); PrintF("contexts_disposed=%d ", contexts_disposed);
PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate); PrintF("contexts_disposal_rate=%f ", contexts_disposal_rate);
...@@ -96,19 +75,6 @@ bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure( ...@@ -96,19 +75,6 @@ bool GCIdleTimeHandler::ShouldDoOverApproximateWeakClosure(
} }
GCIdleTimeAction GCIdleTimeHandler::NothingOrDone(double idle_time_in_ms) {
if (idle_time_in_ms >= kMinBackgroundIdleTime) {
return GCIdleTimeAction::Nothing();
}
if (idle_times_which_made_no_progress_ >= kMaxNoProgressIdleTimes) {
return GCIdleTimeAction::Done();
} else {
idle_times_which_made_no_progress_++;
return GCIdleTimeAction::Nothing();
}
}
// The following logic is implemented by the controller: // The following logic is implemented by the controller:
// (1) If we don't have any idle time, do nothing, unless a context was // (1) If we don't have any idle time, do nothing, unless a context was
// disposed, incremental marking is stopped, and the heap is small. Then do // disposed, incremental marking is stopped, and the heap is small. Then do
...@@ -128,25 +94,17 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms, ...@@ -128,25 +94,17 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed, if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
heap_state.contexts_disposal_rate, heap_state.contexts_disposal_rate,
heap_state.size_of_objects)) { heap_state.size_of_objects)) {
return GCIdleTimeAction::FullGC(); return GCIdleTimeAction::kFullGC;
} }
} }
return GCIdleTimeAction::Nothing(); return GCIdleTimeAction::kDone;
}
// We are in a context disposal GC scenario. Don't do anything if we do not
// get the right idle signal.
if (ShouldDoContextDisposalMarkCompact(heap_state.contexts_disposed,
heap_state.contexts_disposal_rate,
heap_state.size_of_objects)) {
return NothingOrDone(idle_time_in_ms);
} }
if (!FLAG_incremental_marking || heap_state.incremental_marking_stopped) { if (FLAG_incremental_marking && !heap_state.incremental_marking_stopped) {
return GCIdleTimeAction::Done(); return GCIdleTimeAction::kIncrementalStep;
} }
return GCIdleTimeAction::IncrementalStep(); return GCIdleTimeAction::kDone;
} }
bool GCIdleTimeHandler::Enabled() { return FLAG_incremental_marking; } bool GCIdleTimeHandler::Enabled() { return FLAG_incremental_marking; }
......
...@@ -10,51 +10,12 @@ ...@@ -10,51 +10,12 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
enum GCIdleTimeActionType { enum class GCIdleTimeAction : uint8_t {
DONE, kDone,
DO_NOTHING, kIncrementalStep,
DO_INCREMENTAL_STEP, kFullGC,
DO_FULL_GC,
}; };
class GCIdleTimeAction {
public:
static GCIdleTimeAction Done() {
GCIdleTimeAction result;
result.type = DONE;
result.additional_work = false;
return result;
}
static GCIdleTimeAction Nothing() {
GCIdleTimeAction result;
result.type = DO_NOTHING;
result.additional_work = false;
return result;
}
static GCIdleTimeAction IncrementalStep() {
GCIdleTimeAction result;
result.type = DO_INCREMENTAL_STEP;
result.additional_work = false;
return result;
}
static GCIdleTimeAction FullGC() {
GCIdleTimeAction result;
result.type = DO_FULL_GC;
result.additional_work = false;
return result;
}
void Print();
GCIdleTimeActionType type;
bool additional_work;
};
class GCIdleTimeHeapState { class GCIdleTimeHeapState {
public: public:
void Print(); void Print();
...@@ -117,20 +78,13 @@ class V8_EXPORT_PRIVATE GCIdleTimeHandler { ...@@ -117,20 +78,13 @@ class V8_EXPORT_PRIVATE GCIdleTimeHandler {
static const size_t kMinTimeForOverApproximatingWeakClosureInMs; static const size_t kMinTimeForOverApproximatingWeakClosureInMs;
// Number of times we will return a Nothing action in the current mode GCIdleTimeHandler() = default;
// despite having idle time available before we returning a Done action to
// ensure we don't keep scheduling idle tasks and making no progress.
static const int kMaxNoProgressIdleTimes = 10;
GCIdleTimeHandler() : idle_times_which_made_no_progress_(0) {}
GCIdleTimeAction Compute(double idle_time_in_ms, GCIdleTimeAction Compute(double idle_time_in_ms,
GCIdleTimeHeapState heap_state); GCIdleTimeHeapState heap_state);
bool Enabled(); bool Enabled();
void ResetNoProgressCounter() { idle_times_which_made_no_progress_ = 0; }
static size_t EstimateMarkingStepSize(double idle_time_in_ms, static size_t EstimateMarkingStepSize(double idle_time_in_ms,
double marking_speed_in_bytes_per_ms); double marking_speed_in_bytes_per_ms);
...@@ -148,11 +102,6 @@ class V8_EXPORT_PRIVATE GCIdleTimeHandler { ...@@ -148,11 +102,6 @@ class V8_EXPORT_PRIVATE GCIdleTimeHandler {
static bool ShouldDoOverApproximateWeakClosure(double idle_time_in_ms); static bool ShouldDoOverApproximateWeakClosure(double idle_time_in_ms);
private: private:
GCIdleTimeAction NothingOrDone(double idle_time_in_ms);
// Idle notifications with no progress.
int idle_times_which_made_no_progress_;
DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler); DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
}; };
......
...@@ -1489,7 +1489,6 @@ void Heap::StartIncrementalMarkingIfAllocationLimitIsReached( ...@@ -1489,7 +1489,6 @@ void Heap::StartIncrementalMarkingIfAllocationLimitIsReached(
void Heap::StartIdleIncrementalMarking( void Heap::StartIdleIncrementalMarking(
GarbageCollectionReason gc_reason, GarbageCollectionReason gc_reason,
const GCCallbackFlags gc_callback_flags) { const GCCallbackFlags gc_callback_flags) {
gc_idle_time_handler_->ResetNoProgressCounter();
StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason, StartIncrementalMarking(kReduceMemoryFootprintMask, gc_reason,
gc_callback_flags); gc_callback_flags);
} }
...@@ -3189,11 +3188,11 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, ...@@ -3189,11 +3188,11 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
GCIdleTimeHeapState heap_state, GCIdleTimeHeapState heap_state,
double deadline_in_ms) { double deadline_in_ms) {
bool result = false; bool result = false;
switch (action.type) { switch (action) {
case DONE: case GCIdleTimeAction::kDone:
result = true; result = true;
break; break;
case DO_INCREMENTAL_STEP: { case GCIdleTimeAction::kIncrementalStep: {
incremental_marking()->AdvanceWithDeadline( incremental_marking()->AdvanceWithDeadline(
deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD, deadline_in_ms, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
StepOrigin::kTask); StepOrigin::kTask);
...@@ -3202,15 +3201,13 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action, ...@@ -3202,15 +3201,13 @@ bool Heap::PerformIdleTimeAction(GCIdleTimeAction action,
result = incremental_marking()->IsStopped(); result = incremental_marking()->IsStopped();
break; break;
} }
case DO_FULL_GC: { case GCIdleTimeAction::kFullGC: {
DCHECK_LT(0, contexts_disposed_); DCHECK_LT(0, contexts_disposed_);
HistogramTimerScope scope(isolate_->counters()->gc_context()); HistogramTimerScope scope(isolate_->counters()->gc_context());
TRACE_EVENT0("v8", "V8.GCContext"); TRACE_EVENT0("v8", "V8.GCContext");
CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal); CollectAllGarbage(kNoGCFlags, GarbageCollectionReason::kContextDisposal);
break; break;
} }
case DO_NOTHING:
break;
} }
return result; return result;
...@@ -3226,14 +3223,23 @@ void Heap::IdleNotificationEpilogue(GCIdleTimeAction action, ...@@ -3226,14 +3223,23 @@ void Heap::IdleNotificationEpilogue(GCIdleTimeAction action,
contexts_disposed_ = 0; contexts_disposed_ = 0;
if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) || if (FLAG_trace_idle_notification) {
FLAG_trace_idle_notification_verbose) {
isolate_->PrintWithTimestamp( isolate_->PrintWithTimestamp(
"Idle notification: requested idle time %.2f ms, used idle time %.2f " "Idle notification: requested idle time %.2f ms, used idle time %.2f "
"ms, deadline usage %.2f ms [", "ms, deadline usage %.2f ms [",
idle_time_in_ms, idle_time_in_ms - deadline_difference, idle_time_in_ms, idle_time_in_ms - deadline_difference,
deadline_difference); deadline_difference);
action.Print(); switch (action) {
case GCIdleTimeAction::kDone:
PrintF("done");
break;
case GCIdleTimeAction::kIncrementalStep:
PrintF("incremental step");
break;
case GCIdleTimeAction::kFullGC:
PrintF("full GC");
break;
}
PrintF("]"); PrintF("]");
if (FLAG_trace_idle_notification_verbose) { if (FLAG_trace_idle_notification_verbose) {
PrintF("["); PrintF("[");
......
...@@ -58,7 +58,6 @@ class ArrayBufferCollector; ...@@ -58,7 +58,6 @@ class ArrayBufferCollector;
class ArrayBufferTracker; class ArrayBufferTracker;
class CodeLargeObjectSpace; class CodeLargeObjectSpace;
class ConcurrentMarking; class ConcurrentMarking;
class GCIdleTimeAction;
class GCIdleTimeHandler; class GCIdleTimeHandler;
class GCIdleTimeHeapState; class GCIdleTimeHeapState;
class GCTracer; class GCTracer;
...@@ -145,6 +144,8 @@ enum class YoungGenerationHandling { ...@@ -145,6 +144,8 @@ enum class YoungGenerationHandling {
// Also update src/tools/metrics/histograms/histograms.xml in chromium. // Also update src/tools/metrics/histograms/histograms.xml in chromium.
}; };
enum class GCIdleTimeAction : uint8_t;
class AllocationResult { class AllocationResult {
public: public:
static inline AllocationResult Retry(AllocationSpace space = NEW_SPACE) { static inline AllocationResult Retry(AllocationSpace space = NEW_SPACE) {
......
...@@ -31,7 +31,6 @@ class GCIdleTimeHandlerTest : public ::testing::Test { ...@@ -31,7 +31,6 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
static const size_t kSizeOfObjects = 100 * MB; static const size_t kSizeOfObjects = 100 * MB;
static const size_t kMarkCompactSpeed = 200 * KB; static const size_t kMarkCompactSpeed = 200 * KB;
static const size_t kMarkingSpeed = 200 * KB; static const size_t kMarkingSpeed = 200 * KB;
static const int kMaxNotifications = 100;
private: private:
GCIdleTimeHandler handler_; GCIdleTimeHandler handler_;
...@@ -95,8 +94,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) { ...@@ -95,8 +94,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
heap_state.contexts_disposed = 1; heap_state.contexts_disposed = 1;
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 0; double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DO_NOTHING, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -108,8 +107,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) { ...@@ -108,8 +107,8 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
GCIdleTimeHandler::kHighContextDisposalRate - 1; GCIdleTimeHandler::kHighContextDisposalRate - 1;
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 0; double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kFullGC,
EXPECT_EQ(DO_FULL_GC, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -120,8 +119,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) { ...@@ -120,8 +119,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
heap_state.contexts_disposal_rate = 1.0; heap_state.contexts_disposal_rate = 1.0;
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 0; double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kFullGC,
EXPECT_EQ(DO_FULL_GC, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -133,8 +132,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) { ...@@ -133,8 +132,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
GCIdleTimeHandler::kHighContextDisposalRate; GCIdleTimeHandler::kHighContextDisposalRate;
size_t speed = kMarkCompactSpeed; size_t speed = kMarkCompactSpeed;
double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kIncrementalStep,
EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -146,8 +145,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) { ...@@ -146,8 +145,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
GCIdleTimeHandler::kHighContextDisposalRate; GCIdleTimeHandler::kHighContextDisposalRate;
size_t speed = kMarkCompactSpeed; size_t speed = kMarkCompactSpeed;
double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kIncrementalStep,
EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeHeap) { TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeHeap) {
...@@ -158,16 +157,16 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeHeap) { ...@@ -158,16 +157,16 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeHeap) {
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
heap_state.size_of_objects = 101 * MB; heap_state.size_of_objects = 101 * MB;
double idle_time_ms = 0; double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DO_NOTHING, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) { TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
if (!handler()->Enabled()) return; if (!handler()->Enabled()) return;
GCIdleTimeHeapState heap_state = DefaultHeapState(); GCIdleTimeHeapState heap_state = DefaultHeapState();
double idle_time_ms = 10; double idle_time_ms = 10;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kIncrementalStep,
EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -177,8 +176,8 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) { ...@@ -177,8 +176,8 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
size_t speed = kMarkCompactSpeed; size_t speed = kMarkCompactSpeed;
double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1); double idle_time_ms = static_cast<double>(kSizeOfObjects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DONE, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -187,8 +186,8 @@ TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) { ...@@ -187,8 +186,8 @@ TEST_F(GCIdleTimeHandlerTest, DoNotStartIncrementalMarking) {
GCIdleTimeHeapState heap_state = DefaultHeapState(); GCIdleTimeHeapState heap_state = DefaultHeapState();
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 10.0; double idle_time_ms = 10.0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DONE, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
...@@ -197,32 +196,11 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) { ...@@ -197,32 +196,11 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop) {
GCIdleTimeHeapState heap_state = DefaultHeapState(); GCIdleTimeHeapState heap_state = DefaultHeapState();
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 10.0; double idle_time_ms = 10.0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DONE, action.type); handler()->Compute(idle_time_ms, heap_state));
heap_state.incremental_marking_stopped = false; heap_state.incremental_marking_stopped = false;
action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kIncrementalStep,
EXPECT_EQ(DO_INCREMENTAL_STEP, action.type); handler()->Compute(idle_time_ms, heap_state));
}
TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
if (!handler()->Enabled()) return;
GCIdleTimeHeapState heap_state = DefaultHeapState();
for (int i = 0; i < kMaxNotifications; i++) {
GCIdleTimeAction action = handler()->Compute(0, heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
}
TEST_F(GCIdleTimeHandlerTest, SmallIdleTimeNothingToDo) {
if (!handler()->Enabled()) return;
GCIdleTimeHeapState heap_state = DefaultHeapState();
heap_state.incremental_marking_stopped = true;
for (int i = 0; i < kMaxNotifications; i++) {
GCIdleTimeAction action = handler()->Compute(10, heap_state);
EXPECT_TRUE(DO_NOTHING == action.type || DONE == action.type);
}
} }
...@@ -235,9 +213,9 @@ TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) { ...@@ -235,9 +213,9 @@ TEST_F(GCIdleTimeHandlerTest, DoneIfNotMakingProgressOnIncrementalMarking) {
// Simulate incremental marking stopped and not eligible to start. // Simulate incremental marking stopped and not eligible to start.
heap_state.incremental_marking_stopped = true; heap_state.incremental_marking_stopped = true;
double idle_time_ms = 10.0; double idle_time_ms = 10.0;
// We should return DONE if we cannot start incremental marking. // We should return kDone if we cannot start incremental marking.
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state); EXPECT_EQ(GCIdleTimeAction::kDone,
EXPECT_EQ(DONE, action.type); handler()->Compute(idle_time_ms, heap_state));
} }
} // namespace internal } // namespace internal
......
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