Commit bc46d6c4 authored by ulan@chromium.org's avatar ulan@chromium.org

Make sure idle notifications perform a round of incremental GCs after context disposal.

BUG=v8:2107

Review URL: https://chromiumcodereview.appspot.com/10209026

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11469 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6aceff1f
......@@ -4991,8 +4991,10 @@ void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
bool Heap::IdleNotification(int hint) {
const int kMaxHint = 1000;
intptr_t size_factor = Min(Max(hint, 30), kMaxHint) / 10;
// The size factor is in range [3..100].
intptr_t size_factor = Min(Max(hint, 20), kMaxHint) / 4;
// The size factor is in range [5..250]. The numbers here are chosen from
// experiments. If you changes them, make sure to test with
// chrome/performance_ui_tests --gtest_filter="GeneralMixMemoryTest.*
intptr_t step_size = size_factor * IncrementalMarking::kAllocatedThreshold;
if (contexts_disposed_ > 0) {
......@@ -5016,11 +5018,14 @@ bool Heap::IdleNotification(int hint) {
// Take into account that we might have decided to delay full collection
// because incremental marking is in progress.
ASSERT((contexts_disposed_ == 0) || !incremental_marking()->IsStopped());
// After context disposal there is likely a lot of garbage remaining, reset
// the idle notification counters in order to trigger more incremental GCs
// on subsequent idle notifications.
StartIdleRound();
return false;
}
if (hint >= kMaxHint || !FLAG_incremental_marking ||
FLAG_expose_gc || Serializer::enabled()) {
if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
return IdleGlobalGC();
}
......@@ -5059,10 +5064,6 @@ bool Heap::IdleNotification(int hint) {
}
if (incremental_marking()->IsStopped()) {
if (!WorthStartingGCWhenIdle()) {
FinishIdleRound();
return true;
}
incremental_marking()->Start();
}
......
......@@ -1990,13 +1990,6 @@ class Heap {
return (scavenges_since_last_idle_round_ >= kIdleScavengeThreshold);
}
bool WorthStartingGCWhenIdle() {
if (contexts_disposed_ > 0) {
return true;
}
return incremental_marking()->WorthActivating();
}
// Estimates how many milliseconds a Mark-Sweep would take to complete.
// In idle notification handler we assume that this function will return:
// - a number less than 10 for small heaps, which are less than 8Mb.
......
......@@ -13995,75 +13995,104 @@ TEST(SourceURLInStackTrace) {
}
static void CreateGarbageInOldSpace() {
v8::HandleScope scope;
i::AlwaysAllocateScope always_allocate;
for (int i = 0; i < 1000; i++) {
FACTORY->NewFixedArray(1000, i::TENURED);
}
}
// Test that idle notification can be handled and eventually returns true.
// This just checks the contract of the IdleNotification() function,
// and does not verify that it does reasonable work.
THREADED_TEST(IdleNotification) {
TEST(IdleNotification) {
const intptr_t MB = 1024 * 1024;
v8::HandleScope scope;
LocalContext env;
{
// Create garbage in old-space to generate work for idle notification.
i::AlwaysAllocateScope always_allocate;
for (int i = 0; i < 100; i++) {
FACTORY->NewFixedArray(1000, i::TENURED);
}
}
bool finshed_idle_work = false;
for (int i = 0; i < 100 && !finshed_idle_work; i++) {
finshed_idle_work = v8::V8::IdleNotification();
intptr_t initial_size = HEAP->SizeOfObjects();
CreateGarbageInOldSpace();
intptr_t size_with_garbage = HEAP->SizeOfObjects();
CHECK_GT(size_with_garbage, initial_size + MB);
bool finished = false;
for (int i = 0; i < 200 && !finished; i++) {
finished = v8::V8::IdleNotification();
}
CHECK(finshed_idle_work);
intptr_t final_size = HEAP->SizeOfObjects();
CHECK(finished);
CHECK_LT(final_size, initial_size + 1);
}
// Test that idle notification can be handled and eventually returns true.
// This just checks the contract of the IdleNotification() function,
// and does not verify that it does reasonable work.
// Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithSmallHint) {
const intptr_t MB = 1024 * 1024;
const int IdlePauseInMs = 900;
v8::HandleScope scope;
LocalContext env;
{
// Create garbage in old-space to generate work for idle notification.
i::AlwaysAllocateScope always_allocate;
for (int i = 0; i < 100; i++) {
FACTORY->NewFixedArray(1000, i::TENURED);
}
}
intptr_t old_size = HEAP->SizeOfObjects();
bool finshed_idle_work = false;
bool no_idle_work = v8::V8::IdleNotification(10);
for (int i = 0; i < 200 && !finshed_idle_work; i++) {
finshed_idle_work = v8::V8::IdleNotification(10);
intptr_t initial_size = HEAP->SizeOfObjects();
CreateGarbageInOldSpace();
intptr_t size_with_garbage = HEAP->SizeOfObjects();
CHECK_GT(size_with_garbage, initial_size + MB);
bool finished = false;
for (int i = 0; i < 200 && !finished; i++) {
finished = v8::V8::IdleNotification(IdlePauseInMs);
}
intptr_t new_size = HEAP->SizeOfObjects();
CHECK(finshed_idle_work);
CHECK(no_idle_work || new_size < old_size);
intptr_t final_size = HEAP->SizeOfObjects();
CHECK(finished);
CHECK_LT(final_size, initial_size + 1);
}
// This just checks the contract of the IdleNotification() function,
// and does not verify that it does reasonable work.
// Test that idle notification can be handled and eventually collects garbage.
TEST(IdleNotificationWithLargeHint) {
const intptr_t MB = 1024 * 1024;
const int IdlePauseInMs = 900;
v8::HandleScope scope;
LocalContext env;
{
// Create garbage in old-space to generate work for idle notification.
i::AlwaysAllocateScope always_allocate;
for (int i = 0; i < 100; i++) {
FACTORY->NewFixedArray(1000, i::TENURED);
}
}
intptr_t old_size = HEAP->SizeOfObjects();
bool finshed_idle_work = false;
bool no_idle_work = v8::V8::IdleNotification(900);
for (int i = 0; i < 200 && !finshed_idle_work; i++) {
finshed_idle_work = v8::V8::IdleNotification(900);
intptr_t initial_size = HEAP->SizeOfObjects();
CreateGarbageInOldSpace();
intptr_t size_with_garbage = HEAP->SizeOfObjects();
CHECK_GT(size_with_garbage, initial_size + MB);
bool finished = false;
for (int i = 0; i < 200 && !finished; i++) {
finished = v8::V8::IdleNotification(IdlePauseInMs);
}
intptr_t new_size = HEAP->SizeOfObjects();
CHECK(finshed_idle_work);
CHECK(no_idle_work || new_size < old_size);
intptr_t final_size = HEAP->SizeOfObjects();
CHECK(finished);
CHECK_LT(final_size, initial_size + 1);
}
TEST(Regress2107) {
const intptr_t MB = 1024 * 1024;
const int kShortIdlePauseInMs = 100;
const int kLongIdlePauseInMs = 1000;
v8::HandleScope scope;
LocalContext env;
intptr_t initial_size = HEAP->SizeOfObjects();
// Send idle notification to start a round of incremental GCs.
v8::V8::IdleNotification(kShortIdlePauseInMs);
// Emulate 7 page reloads.
for (int i = 0; i < 7; i++) {
v8::Persistent<v8::Context> ctx = v8::Context::New();
ctx->Enter();
CreateGarbageInOldSpace();
ctx->Exit();
ctx.Dispose();
v8::V8::ContextDisposedNotification();
v8::V8::IdleNotification(kLongIdlePauseInMs);
}
// Create garbage and check that idle notification still collects it.
CreateGarbageInOldSpace();
intptr_t size_with_garbage = HEAP->SizeOfObjects();
CHECK_GT(size_with_garbage, initial_size + MB);
bool finished = false;
for (int i = 0; i < 200 && !finished; i++) {
finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
}
intptr_t final_size = HEAP->SizeOfObjects();
CHECK_LT(final_size, initial_size + 1);
}
static uint32_t* stack_limit;
static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) {
......
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