Commit ad6b41ff authored by hpayer@chromium.org's avatar hpayer@chromium.org

Force scavenge in idle notification if we estimate that it will take long.

BUG=
R=ulan@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24379 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 43ddad10
......@@ -71,30 +71,47 @@ size_t GCIdleTimeHandler::EstimateMarkCompactTime(
}
size_t GCIdleTimeHandler::EstimateScavengeTime(
size_t new_space_size, size_t scavenge_speed_in_bytes_per_ms) {
bool GCIdleTimeHandler::DoScavenge(
size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size,
size_t scavenge_speed_in_bytes_per_ms,
size_t new_space_allocation_throughput_in_bytes_per_ms) {
size_t new_space_allocation_limit =
kMaxFrameRenderingIdleTime * scavenge_speed_in_bytes_per_ms;
// If the limit is larger than the new space size, then scavenging used to be
// really fast. We can take advantage of the whole new space.
if (new_space_allocation_limit > new_space_size) {
new_space_allocation_limit = new_space_size;
}
// We do not know the allocation throughput before the first Scavenge.
// TODO(hpayer): Estimate allocation throughput before the first Scavenge.
if (new_space_allocation_throughput_in_bytes_per_ms == 0) {
new_space_allocation_limit = new_space_size * kConservativeTimeRatio;
} else {
// We have to trigger scavenge before we reach the end of new space.
new_space_allocation_limit -=
new_space_allocation_throughput_in_bytes_per_ms *
kMaxFrameRenderingIdleTime;
}
if (scavenge_speed_in_bytes_per_ms == 0) {
scavenge_speed_in_bytes_per_ms = kInitialConservativeScavengeSpeed;
}
return new_space_size / scavenge_speed_in_bytes_per_ms;
}
bool GCIdleTimeHandler::ScavangeMayHappenSoon(
size_t available_new_space_memory,
size_t new_space_allocation_throughput_in_bytes_per_ms) {
if (available_new_space_memory <=
new_space_allocation_throughput_in_bytes_per_ms *
kMaxFrameRenderingIdleTime) {
return true;
if (new_space_allocation_limit <= used_new_space_size) {
if (used_new_space_size / scavenge_speed_in_bytes_per_ms <=
idle_time_in_ms) {
return true;
}
}
return false;
}
// The following logic is implemented by the controller:
// (1) If the new space is almost full and we can effort a Scavenge, then a
// Scavenge is performed.
// (1) If the new space is almost full and we can affort a Scavenge or if the
// next Scavenge will very likely take long, then a Scavenge is performed.
// (2) If there is currently no MarkCompact idle round going on, we start a
// new idle round if enough garbage was created or we received a context
// disposal event. Otherwise we do not perform garbage collection to keep
......@@ -110,15 +127,13 @@ bool GCIdleTimeHandler::ScavangeMayHappenSoon(
// that this currently may trigger a full garbage collection.
GCIdleTimeAction GCIdleTimeHandler::Compute(size_t idle_time_in_ms,
HeapState heap_state) {
if (idle_time_in_ms <= kMaxFrameRenderingIdleTime &&
ScavangeMayHappenSoon(
heap_state.available_new_space_memory,
heap_state.new_space_allocation_throughput_in_bytes_per_ms) &&
idle_time_in_ms >=
EstimateScavengeTime(heap_state.new_space_capacity,
heap_state.scavenge_speed_in_bytes_per_ms)) {
if (DoScavenge(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)) {
return GCIdleTimeAction::Scavenge();
}
if (IsMarkCompactIdleRoundFinished()) {
if (EnoughGarbageSinceLastIdleRound() || heap_state.contexts_disposed > 0) {
StartIdleRound();
......
......@@ -113,10 +113,6 @@ class GCIdleTimeHandler {
// That is the maximum idle time we will have during frame rendering.
static const size_t kMaxFrameRenderingIdleTime = 16;
// If less than that much memory is left in the new space, we consider it
// as almost full and force a new space collection earlier in the idle time.
static const size_t kNewSpaceAlmostFullTreshold = 100 * KB;
// If we haven't recorded any scavenger events yet, we use a conservative
// lower bound for the scavenger speed.
static const size_t kInitialConservativeScavengeSpeed = 100 * KB;
......@@ -130,7 +126,7 @@ class GCIdleTimeHandler {
size_t mark_compact_speed_in_bytes_per_ms;
size_t incremental_marking_speed_in_bytes_per_ms;
size_t scavenge_speed_in_bytes_per_ms;
size_t available_new_space_memory;
size_t used_new_space_size;
size_t new_space_capacity;
size_t new_space_allocation_throughput_in_bytes_per_ms;
};
......@@ -159,11 +155,9 @@ class GCIdleTimeHandler {
static size_t EstimateMarkCompactTime(
size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
static size_t EstimateScavengeTime(size_t new_space_size,
size_t scavenger_speed_in_bytes_per_ms);
static bool ScavangeMayHappenSoon(
size_t available_new_space_memory,
static bool DoScavenge(
size_t idle_time_in_ms, size_t new_space_size, size_t used_new_space_size,
size_t scavenger_speed_in_bytes_per_ms,
size_t new_space_allocation_throughput_in_bytes_per_ms);
private:
......
......@@ -4314,7 +4314,7 @@ bool Heap::IdleNotification(int idle_time_in_ms) {
tracer()->IncrementalMarkingSpeedInBytesPerMillisecond());
heap_state.scavenge_speed_in_bytes_per_ms =
static_cast<size_t>(tracer()->ScavengeSpeedInBytesPerMillisecond());
heap_state.available_new_space_memory = new_space_.Available();
heap_state.used_new_space_size = new_space_.Size();
heap_state.new_space_capacity = new_space_.Capacity();
heap_state.new_space_allocation_throughput_in_bytes_per_ms =
static_cast<size_t>(
......
......@@ -29,7 +29,7 @@ class GCIdleTimeHandlerTest : public ::testing::Test {
result.mark_compact_speed_in_bytes_per_ms = kMarkCompactSpeed;
result.incremental_marking_speed_in_bytes_per_ms = kMarkingSpeed;
result.scavenge_speed_in_bytes_per_ms = kScavengeSpeed;
result.available_new_space_memory = kNewSpaceCapacity;
result.used_new_space_size = 0;
result.new_space_capacity = kNewSpaceCapacity;
result.new_space_allocation_throughput_in_bytes_per_ms =
kNewSpaceAllocationThroughput;
......@@ -109,38 +109,60 @@ TEST(GCIdleTimeHandler, EstimateMarkCompactTimeMax) {
}
TEST(GCIdleTimeHandler, EstimateScavengeTimeInitial) {
size_t size = 1 * MB;
size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, 0);
EXPECT_EQ(size / GCIdleTimeHandler::kInitialConservativeScavengeSpeed, time);
TEST_F(GCIdleTimeHandlerTest, DoScavengeEmptyNewSpace) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_in_ms = 16;
EXPECT_FALSE(GCIdleTimeHandler::DoScavenge(
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));
}
TEST(GCIdleTimeHandler, EstimateScavengeTimeNonZero) {
size_t size = 1 * MB;
size_t speed = 1 * MB;
size_t time = GCIdleTimeHandler::EstimateScavengeTime(size, speed);
EXPECT_EQ(size / speed, time);
TEST_F(GCIdleTimeHandlerTest, DoScavengeFullNewSpace) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.used_new_space_size = kNewSpaceCapacity;
int idle_time_in_ms = 16;
EXPECT_TRUE(GCIdleTimeHandler::DoScavenge(
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));
}
TEST(GCIdleTimeHandler, ScavangeMayHappenSoonInitial) {
size_t available = 100 * KB;
EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, 0));
TEST_F(GCIdleTimeHandlerTest, DoScavengeUnknownScavengeSpeed) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.used_new_space_size = kNewSpaceCapacity;
heap_state.scavenge_speed_in_bytes_per_ms = 0;
int idle_time_in_ms = 16;
EXPECT_FALSE(GCIdleTimeHandler::DoScavenge(
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));
}
TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroFalse) {
size_t available = (GCIdleTimeHandler::kMaxFrameRenderingIdleTime + 1) * KB;
size_t speed = 1 * KB;
EXPECT_FALSE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
TEST_F(GCIdleTimeHandlerTest, DoScavengeLowScavengeSpeed) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.used_new_space_size = kNewSpaceCapacity;
heap_state.scavenge_speed_in_bytes_per_ms = 1 * KB;
int idle_time_in_ms = 16;
EXPECT_FALSE(GCIdleTimeHandler::DoScavenge(
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));
}
TEST(GCIdleTimeHandler, ScavangeMayHappenSoonNonZeroTrue) {
size_t available = GCIdleTimeHandler::kMaxFrameRenderingIdleTime * KB;
size_t speed = 1 * KB;
EXPECT_TRUE(GCIdleTimeHandler::ScavangeMayHappenSoon(available, speed));
TEST_F(GCIdleTimeHandlerTest, DoScavengeHighScavengeSpeed) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
heap_state.used_new_space_size = kNewSpaceCapacity;
heap_state.scavenge_speed_in_bytes_per_ms = kNewSpaceCapacity;
int idle_time_in_ms = 16;
EXPECT_TRUE(GCIdleTimeHandler::DoScavenge(
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));
}
......@@ -294,8 +316,9 @@ TEST_F(GCIdleTimeHandlerTest, ContinueAfterStop2) {
TEST_F(GCIdleTimeHandlerTest, Scavenge) {
GCIdleTimeHandler::HeapState heap_state = DefaultHeapState();
int idle_time_ms = 10;
heap_state.available_new_space_memory =
kNewSpaceAllocationThroughput * idle_time_ms;
heap_state.used_new_space_size =
heap_state.new_space_capacity -
(kNewSpaceAllocationThroughput * idle_time_ms);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_SCAVENGE, action.type);
}
......@@ -306,11 +329,12 @@ TEST_F(GCIdleTimeHandlerTest, ScavengeAndDone) {
int idle_time_ms = 10;
heap_state.can_start_incremental_marking = false;
heap_state.incremental_marking_stopped = true;
heap_state.available_new_space_memory =
kNewSpaceAllocationThroughput * idle_time_ms;
heap_state.used_new_space_size =
heap_state.new_space_capacity -
(kNewSpaceAllocationThroughput * idle_time_ms);
GCIdleTimeAction action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_SCAVENGE, action.type);
heap_state.available_new_space_memory = kNewSpaceCapacity;
heap_state.used_new_space_size = 0;
action = handler()->Compute(idle_time_ms, heap_state);
EXPECT_EQ(DO_NOTHING, action.type);
}
......
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