Commit 297935b3 authored by hpayer's avatar hpayer Committed by Commit bot

Use deadline in IdleNotification.

BUG=417668
LOG=n

Review URL: https://codereview.chromium.org/750813003

Cr-Commit-Position: refs/heads/master@{#25560}
parent e42fda5e
......@@ -5063,17 +5063,23 @@ class V8_EXPORT Isolate {
/**
* Optional notification that the embedder is idle.
* V8 uses the notification to reduce memory footprint.
* V8 uses the notification to perform garbage collection.
* This call can be used repeatedly if the embedder remains idle.
* Returns true if the embedder should stop calling IdleNotification
* until real work has been done. This indicates that V8 has done
* as much cleanup as it will be able to do.
*
* The idle_time_in_ms argument specifies the time V8 has to do reduce
* the memory footprint. There is no guarantee that the actual work will be
* The idle_time_in_ms argument specifies the time V8 has to perform
* garbage collection. There is no guarantee that the actual work will be
* done within the time limit.
* The deadline_in_seconds argument specifies the deadline V8 has to finish
* garbage collection work. deadline_in_seconds is compared with
* MonotonicallyIncreasingTime() and should be based on the same timebase as
* that function. There is no guarantee that the actual work will be done
* within the time limit.
*/
bool IdleNotification(int idle_time_in_ms);
bool IdleNotificationDeadline(double deadline_in_seconds);
/**
* Optional notification that the system is running low on memory.
......
......@@ -6650,6 +6650,15 @@ bool Isolate::IdleNotification(int idle_time_in_ms) {
}
bool Isolate::IdleNotificationDeadline(double deadline_in_seconds) {
// Returning true tells the caller that it need not
// continue to call IdleNotification.
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
if (!i::FLAG_use_idle_notification) return true;
return isolate->heap()->IdleNotification(deadline_in_seconds);
}
void Isolate::LowMemoryNotification() {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
{
......
......@@ -189,9 +189,9 @@ bool GCIdleTimeHandler::ShouldDoFinalIncrementalMarkCompact(
// request, we finalize sweeping here.
// (6) If incremental marking is in progress, we perform a marking step. Note,
// that this currently may trigger a full garbage collection.
GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
GCIdleTimeAction GCIdleTimeHandler::Compute(double idle_time_in_ms,
HeapState heap_state) {
if (idle_time_in_ms == 0) {
if (idle_time_in_ms <= 0.0) {
if (heap_state.incremental_marking_stopped) {
if (ShouldDoContextDisposalMarkCompact(
heap_state.contexts_disposed,
......@@ -203,7 +203,7 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
}
if (ShouldDoScavenge(
idle_time_in_ms, heap_state.new_space_capacity,
static_cast<size_t>(idle_time_in_ms), heap_state.new_space_capacity,
heap_state.used_new_space_size,
heap_state.scavenge_speed_in_bytes_per_ms,
heap_state.new_space_allocation_throughput_in_bytes_per_ms)) {
......@@ -219,7 +219,8 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
}
if (heap_state.incremental_marking_stopped) {
if (ShouldDoMarkCompact(idle_time_in_ms, heap_state.size_of_objects,
if (ShouldDoMarkCompact(static_cast<size_t>(idle_time_in_ms),
heap_state.size_of_objects,
heap_state.mark_compact_speed_in_bytes_per_ms)) {
// If there are no more than two GCs left in this idle round and we are
// allowed to do a full GC, then make those GCs full in order to compact
......@@ -228,7 +229,7 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
// can get rid of this special case and always start incremental marking.
int remaining_mark_sweeps =
kMaxMarkCompactsInIdleRound - mark_compacts_since_idle_round_started_;
if (idle_time_in_ms > kMaxFrameRenderingIdleTime &&
if (static_cast<size_t>(idle_time_in_ms) > kMaxFrameRenderingIdleTime &&
(remaining_mark_sweeps <= 2 ||
!heap_state.can_start_incremental_marking)) {
return GCIdleTimeAction::FullGC();
......@@ -240,7 +241,7 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
}
// TODO(hpayer): Estimate finalize sweeping time.
if (heap_state.sweeping_in_progress &&
idle_time_in_ms >= kMinTimeForFinalizeSweeping) {
static_cast<size_t>(idle_time_in_ms) >= kMinTimeForFinalizeSweeping) {
return GCIdleTimeAction::FinalizeSweeping();
}
......@@ -249,7 +250,8 @@ GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
return GCIdleTimeAction::Nothing();
}
size_t step_size = EstimateMarkingStepSize(
idle_time_in_ms, heap_state.incremental_marking_speed_in_bytes_per_ms);
static_cast<size_t>(idle_time_in_ms),
heap_state.incremental_marking_speed_in_bytes_per_ms);
return GCIdleTimeAction::IncrementalMarking(step_size);
}
}
......
......@@ -148,7 +148,7 @@ class GCIdleTimeHandler {
: mark_compacts_since_idle_round_started_(0),
scavenges_since_last_idle_round_(0) {}
GCIdleTimeAction Compute(size_t idle_time_in_ms, HeapState heap_state);
GCIdleTimeAction Compute(double idle_time_in_ms, HeapState heap_state);
void NotifyIdleMarkCompact() {
if (mark_compacts_since_idle_round_started_ < kMaxMarkCompactsInIdleRound) {
......
......@@ -4386,12 +4386,12 @@ void Heap::IdleMarkCompact(const char* message) {
void Heap::TryFinalizeIdleIncrementalMarking(
size_t idle_time_in_ms, size_t size_of_objects,
double idle_time_in_ms, size_t size_of_objects,
size_t final_incremental_mark_compact_speed_in_bytes_per_ms) {
if (incremental_marking()->IsComplete() ||
(mark_compact_collector()->IsMarkingDequeEmpty() &&
gc_idle_time_handler_.ShouldDoFinalIncrementalMarkCompact(
idle_time_in_ms, size_of_objects,
static_cast<size_t>(idle_time_in_ms), size_of_objects,
final_incremental_mark_compact_speed_in_bytes_per_ms))) {
CollectAllGarbage(kNoGCFlags, "idle notification: finalize incremental");
}
......@@ -4404,11 +4404,24 @@ bool Heap::WorthActivatingIncrementalMarking() {
}
static double MonotonicallyIncreasingTimeInMs() {
return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
static_cast<double>(base::Time::kMillisecondsPerSecond);
}
bool Heap::IdleNotification(int idle_time_in_ms) {
base::ElapsedTimer timer;
timer.Start();
isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
idle_time_in_ms);
return IdleNotification(
V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() +
(static_cast<double>(idle_time_in_ms) /
static_cast<double>(base::Time::kMillisecondsPerSecond)));
}
bool Heap::IdleNotification(double deadline_in_seconds) {
double deadline_in_ms =
deadline_in_seconds *
static_cast<double>(base::Time::kMillisecondsPerSecond);
HistogramTimerScope idle_notification_scope(
isolate_->counters()->gc_idle_notification());
......@@ -4438,11 +4451,13 @@ bool Heap::IdleNotification(int idle_time_in_ms) {
static_cast<size_t>(
tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond());
double idle_time_in_ms = deadline_in_ms - MonotonicallyIncreasingTimeInMs();
GCIdleTimeAction action =
gc_idle_time_handler_.Compute(idle_time_in_ms, heap_state);
isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
static_cast<int>(idle_time_in_ms));
bool result = false;
int actual_time_in_ms = 0;
switch (action.type) {
case DONE:
result = true;
......@@ -4455,9 +4470,9 @@ bool Heap::IdleNotification(int idle_time_in_ms) {
IncrementalMarking::NO_GC_VIA_STACK_GUARD,
IncrementalMarking::FORCE_MARKING,
IncrementalMarking::DO_NOT_FORCE_COMPLETION);
actual_time_in_ms = static_cast<int>(timer.Elapsed().InMilliseconds());
int remaining_idle_time_in_ms = idle_time_in_ms - actual_time_in_ms;
if (remaining_idle_time_in_ms > 0) {
double remaining_idle_time_in_ms =
deadline_in_ms - MonotonicallyIncreasingTimeInMs();
if (remaining_idle_time_in_ms > 0.0) {
TryFinalizeIdleIncrementalMarking(
remaining_idle_time_in_ms, heap_state.size_of_objects,
heap_state.final_incremental_mark_compact_speed_in_bytes_per_ms);
......@@ -4485,21 +4500,25 @@ bool Heap::IdleNotification(int idle_time_in_ms) {
break;
}
actual_time_in_ms = static_cast<int>(timer.Elapsed().InMilliseconds());
if (actual_time_in_ms <= idle_time_in_ms) {
double current_time = MonotonicallyIncreasingTimeInMs();
double deadline_difference = deadline_in_ms - current_time;
if (deadline_difference >= 0) {
if (action.type != DONE && action.type != DO_NOTHING) {
isolate()->counters()->gc_idle_time_limit_undershot()->AddSample(
idle_time_in_ms - actual_time_in_ms);
static_cast<int>(deadline_difference));
}
} else {
isolate()->counters()->gc_idle_time_limit_overshot()->AddSample(
actual_time_in_ms - idle_time_in_ms);
static_cast<int>(-deadline_difference));
}
if ((FLAG_trace_idle_notification && action.type > DO_NOTHING) ||
FLAG_trace_idle_notification_verbose) {
PrintF("Idle notification: requested idle time %d ms, actual time %d ms [",
idle_time_in_ms, actual_time_in_ms);
PrintF(
"Idle notification: requested idle time %.2f ms, used idle time %.2f "
"ms, deadline usage %.2f ms [",
idle_time_in_ms, current_time, deadline_difference);
action.Print();
PrintF("]");
if (FLAG_trace_idle_notification_verbose) {
......
......@@ -1104,6 +1104,7 @@ class Heap {
void DisableInlineAllocation();
// Implements the corresponding V8 API function.
bool IdleNotification(double deadline_in_seconds);
bool IdleNotification(int idle_time_in_ms);
// Declare all the root indices. This defines the root list order.
......@@ -2008,7 +2009,7 @@ class Heap {
void IdleMarkCompact(const char* message);
void TryFinalizeIdleIncrementalMarking(
size_t idle_time_in_ms, size_t size_of_objects,
double idle_time_in_ms, size_t size_of_objects,
size_t mark_compact_speed_in_bytes_per_ms);
bool WorthActivatingIncrementalMarking();
......
......@@ -198,7 +198,7 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeLowRate) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.contexts_disposed = 1;
heap_state.incremental_marking_stopped = true;
int idle_time_ms = 0;
double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
......@@ -210,7 +210,7 @@ TEST_F(GCIdleTimeHandlerTest, ContextDisposeHighRate) {
heap_state.contexts_disposal_rate =
GCIdleTimeHandler::kHighContextDisposalRate - 1;
heap_state.incremental_marking_stopped = true;
int idle_time_ms = 0;
double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_FULL_GC, action.type);
}
......@@ -223,8 +223,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeLargeIdleTime) {
heap_state.incremental_marking_stopped = true;
heap_state.can_start_incremental_marking = false;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms =
static_cast<int>((heap_state.size_of_objects + speed - 1) / speed);
double idle_time_ms =
static_cast<double>((heap_state.size_of_objects + speed - 1) / speed);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_FULL_GC, action.type);
}
......@@ -235,7 +235,7 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeZeroIdleTime) {
heap_state.contexts_disposed = 1;
heap_state.contexts_disposal_rate = 1.0;
heap_state.incremental_marking_stopped = true;
int idle_time_ms = 0;
double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_FULL_GC, action.type);
}
......@@ -247,7 +247,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime1) {
heap_state.contexts_disposal_rate = 1.0;
heap_state.incremental_marking_stopped = true;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
double idle_time_ms =
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
}
......@@ -258,7 +259,8 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
heap_state.contexts_disposed = 1;
heap_state.contexts_disposal_rate = 1.0;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
double idle_time_ms =
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
}
......@@ -267,7 +269,7 @@ TEST_F(GCIdleTimeHandlerTest, AfterContextDisposeSmallIdleTime2) {
TEST_F(GCIdleTimeHandlerTest, IncrementalMarking1) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
int idle_time_ms = 10;
double idle_time_ms = 10;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
......@@ -280,7 +282,7 @@ TEST_F(GCIdleTimeHandlerTest, IncrementalMarking2) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.incremental_marking_stopped = true;
size_t speed = heap_state.incremental_marking_speed_in_bytes_per_ms;
int idle_time_ms = 10;
double idle_time_ms = 10;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
EXPECT_GT(speed * static_cast<size_t>(idle_time_ms),
......@@ -294,7 +296,8 @@ TEST_F(GCIdleTimeHandlerTest, NotEnoughTime) {
heap_state.incremental_marking_stopped = true;
heap_state.can_start_incremental_marking = false;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed - 1);
double idle_time_ms =
static_cast<double>(heap_state.size_of_objects / speed - 1);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
......@@ -305,7 +308,8 @@ TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
heap_state.incremental_marking_stopped = true;
heap_state.can_start_incremental_marking = false;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
double idle_time_ms =
static_cast<double>(heap_state.size_of_objects / speed + 1);
for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_FULL_GC, action.type);
......@@ -318,7 +322,7 @@ TEST_F(GCIdleTimeHandlerTest, StopEventually1) {
TEST_F(GCIdleTimeHandlerTest, StopEventually2) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 10;
double idle_time_ms = 10;
for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_INCREMENTAL_MARKING, action.type);
......@@ -337,7 +341,8 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
heap_state.incremental_marking_stopped = true;
heap_state.can_start_incremental_marking = false;
size_t speed = heap_state.mark_compact_speed_in_bytes_per_ms;
int idle_time_ms = static_cast<int>(heap_state.size_of_objects / speed + 1);
double idle_time_ms =
static_cast<double>(heap_state.size_of_objects / speed + 1);
for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_FULL_GC, action.type);
......@@ -356,7 +361,7 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop1) {
TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 10;
double idle_time_ms = 10;
for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
if (action.type == DONE) break;
......@@ -384,7 +389,8 @@ TEST_F(GCIdleTimeHandlerTest, Scavenge) {
heap_state.used_new_space_size =
heap_state.new_space_capacity -
(kNewSpaceAllocationThroughput * idle_time_ms);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
GCIdleTimeAction action =
handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
EXPECT_EQ(DO_SCAVENGE, action.type);
}
......@@ -397,17 +403,18 @@ TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
heap_state.used_new_space_size =
heap_state.new_space_capacity -
(kNewSpaceAllocationThroughput * idle_time_ms);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
GCIdleTimeAction action =
handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
EXPECT_EQ(DO_SCAVENGE, action.type);
heap_state.used_new_space_size = 0;
action = handler()->Compute(idle_time_ms, heap_state);
action = handler()->Compute(static_cast<double>(idle_time_ms), heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 0;
double idle_time_ms = 0;
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
......@@ -415,7 +422,7 @@ TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeNothingToDo) {
TEST_F(GCIdleTimeHandlerTest, ZeroIdleTimeDoNothingButStartIdleRound) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 10;
double idle_time_ms = 10;
for (int i = 0; i < GCIdleTimeHandler::kMaxMarkCompactsInIdleRound; i++) {
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
if (action.type == DONE) break;
......
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