"src/heap-snapshot-generator-inl.h",
"src/heap-snapshot-generator.cc",
"src/heap-snapshot-generator.h",
+ "src/heap/gc-idle-time-handler.cc",
+ "src/heap/gc-idle-time-handler.h",
"src/heap/gc-tracer.cc",
"src/heap/gc-tracer.h",
"src/heap/heap-inl.h",
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <climits>
+
+#include "src/v8.h"
+
+#include "src/heap/gc-idle-time-handler.h"
+
+namespace v8 {
+namespace internal {
+
+
+const double GCIdleTimeHandler::kConservativeTimeRatio = 0.9;
+
+
+intptr_t GCIdleTimeHandler::EstimateMarkingStepSize(
+ int idle_time_in_ms, intptr_t marking_speed_in_bytes_per_ms) {
+ DCHECK(idle_time_in_ms > 0);
+
+ if (marking_speed_in_bytes_per_ms == 0) {
+ marking_speed_in_bytes_per_ms =
+ GCIdleTimeHandler::kInitialConservativeMarkingSpeed;
+ }
+
+ intptr_t marking_step_size = marking_speed_in_bytes_per_ms * idle_time_in_ms;
+ if (static_cast<intptr_t>(marking_step_size / idle_time_in_ms) !=
+ marking_speed_in_bytes_per_ms) {
+ // In the case of an overflow we return maximum marking step size.
+ return INT_MAX;
+ }
+
+ return static_cast<intptr_t>(marking_step_size *
+ GCIdleTimeHandler::kConservativeTimeRatio);
+}
+}
+}
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_HEAP_GC_IDLE_TIME_HANDLER_H_
+#define V8_HEAP_GC_IDLE_TIME_HANDLER_H_
+
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+// The idle time handler makes decisions about which garbage collection
+// operations are executing during IdleNotification.
+class GCIdleTimeHandler {
+ public:
+ static intptr_t EstimateMarkingStepSize(
+ int idle_time_in_ms, intptr_t marking_speed_in_bytes_per_ms);
+
+ // If we haven't recorded any incremental marking events yet, we carefully
+ // mark with a conservative lower bound for the marking speed.
+ static const intptr_t kInitialConservativeMarkingSpeed = 100 * KB;
+
+ // We have to make sure that we finish the IdleNotification before
+ // idle_time_in_ms. Hence, we conservatively prune our workload estimate.
+ static const double kConservativeTimeRatio;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_HEAP_GC_IDLE_TIME_HANDLER_H_
#include "src/debug.h"
#include "src/deoptimizer.h"
#include "src/global-handles.h"
+#include "src/heap/gc-idle-time-handler.h"
#include "src/heap/incremental-marking.h"
#include "src/heap/mark-compact.h"
#include "src/heap/objects-visiting-inl.h"
}
-void Heap::AdvanceIdleIncrementalMarking(intptr_t step_size) {
+void Heap::AdvanceIdleIncrementalMarking(int idle_time_in_ms) {
+ intptr_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+ idle_time_in_ms, tracer_.IncrementalMarkingSpeedInBytesPerMillisecond());
+
incremental_marking()->Step(step_size,
IncrementalMarking::NO_GC_VIA_STACK_GUARD, true);
}
-bool Heap::IdleNotification(int hint) {
+bool Heap::IdleNotification(int idle_time_in_ms) {
// If incremental marking is off, we do not perform idle notification.
if (!FLAG_incremental_marking) return true;
- // Hints greater than this value indicate that
- // the embedder is requesting a lot of GC work.
- const int kMaxHint = 1000;
- const int kMinHintForIncrementalMarking = 10;
// Minimal hint that allows to do full GC.
const int kMinHintForFullGC = 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;
-
- isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(hint);
+ isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample(
+ idle_time_in_ms);
HistogramTimerScope idle_notification_scope(
isolate_->counters()->gc_idle_notification());
if (contexts_disposed_ > 0) {
contexts_disposed_ = 0;
int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
- if (hint >= mark_sweep_time && !FLAG_expose_gc &&
+ if (idle_time_in_ms >= mark_sweep_time && !FLAG_expose_gc &&
incremental_marking()->IsStopped()) {
HistogramTimerScope scope(isolate_->counters()->gc_context());
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: contexts disposed");
} else {
- AdvanceIdleIncrementalMarking(step_size);
+ AdvanceIdleIncrementalMarking(idle_time_in_ms);
}
// After context disposal there is likely a lot of garbage remaining, reset
// the code space.
// TODO(ulan): Once we enable code compaction for incremental marking,
// we can get rid of this special case and always start incremental marking.
- if (remaining_mark_sweeps <= 2 && hint >= kMinHintForFullGC) {
+ if (remaining_mark_sweeps <= 2 && idle_time_in_ms >= kMinHintForFullGC) {
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: finalize idle round");
mark_sweeps_since_idle_round_started_++;
- } else if (hint > kMinHintForIncrementalMarking) {
+ } else {
incremental_marking()->Start();
}
}
- if (!incremental_marking()->IsStopped() &&
- hint > kMinHintForIncrementalMarking) {
- AdvanceIdleIncrementalMarking(step_size);
+ if (!incremental_marking()->IsStopped()) {
+ AdvanceIdleIncrementalMarking(idle_time_in_ms);
}
if (mark_sweeps_since_idle_round_started_ >= kMaxMarkSweepsInIdleRound) {
// If the IdleNotifcation is called with a large hint we will wait for
// the sweepter threads here.
- if (hint >= kMinHintForFullGC &&
+ if (idle_time_in_ms >= kMinHintForFullGC &&
mark_compact_collector()->sweeping_in_progress()) {
mark_compact_collector()->EnsureSweepingCompleted();
}
void DisableInlineAllocation();
// Implements the corresponding V8 API function.
- bool IdleNotification(int hint);
+ bool IdleNotification(int idle_time_in_ms);
// Declare all the root indices. This defines the root list order.
enum RootListIndex {
return heap_size_mb / kMbPerMs;
}
- void AdvanceIdleIncrementalMarking(intptr_t step_size);
+ void AdvanceIdleIncrementalMarking(int idle_time_in_ms);
void ClearObjectStats(bool clear_last_time_stats = false);
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <climits>
+
+#include "src/heap/gc-idle-time-handler.h"
+
#include "testing/gtest/include/gtest/gtest.h"
namespace v8 {
namespace internal {
-TEST(HeapTest, Dummy) {
- EXPECT_FALSE(false);
- EXPECT_TRUE(true);
+TEST(EstimateMarkingStepSizeTest, EstimateMarkingStepSizeInitial) {
+ intptr_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(1, 0);
+ EXPECT_EQ(static_cast<intptr_t>(
+ GCIdleTimeHandler::kInitialConservativeMarkingSpeed *
+ GCIdleTimeHandler::kConservativeTimeRatio),
+ step_size);
+}
+
+
+TEST(EstimateMarkingStepSizeTest, EstimateMarkingStepSizeNonZero) {
+ intptr_t marking_speed_in_bytes_per_millisecond = 100;
+ intptr_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(
+ 1, marking_speed_in_bytes_per_millisecond);
+ EXPECT_EQ(static_cast<intptr_t>(marking_speed_in_bytes_per_millisecond *
+ GCIdleTimeHandler::kConservativeTimeRatio),
+ step_size);
+}
+
+
+TEST(EstimateMarkingStepSizeTest, EstimateMarkingStepSizeOverflow1) {
+ intptr_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(10, INT_MAX);
+ EXPECT_EQ(INT_MAX, step_size);
+}
+
+
+TEST(EstimateMarkingStepSizeTest, EstimateMarkingStepSizeOverflow2) {
+ intptr_t step_size = GCIdleTimeHandler::EstimateMarkingStepSize(INT_MAX, 10);
+ EXPECT_EQ(INT_MAX, step_size);
}
} // namespace internal
'../../src/heap-snapshot-generator-inl.h',
'../../src/heap-snapshot-generator.cc',
'../../src/heap-snapshot-generator.h',
+ '../../src/heap/gc-idle-time-handler.cc',
+ '../../src/heap/gc-idle-time-handler.h',
'../../src/heap/gc-tracer.cc',
'../../src/heap/gc-tracer.h',
'../../src/heap/heap-inl.h',