Commit 27d23eee authored by ulan's avatar ulan Committed by Commit bot

Add the rate of js invocations from the api as a signal of idleness

for starting major GC in the memory reducer.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#31655}
parent 5fc75b26
......@@ -159,6 +159,7 @@ class CallDepthScope {
do_callback_(do_callback) {
// TODO(dcarney): remove this when blink stops crashing.
DCHECK(!isolate_->external_caught_exception());
isolate_->IncrementJsCallsFromApiCounter();
isolate_->handle_scope_implementer()->IncrementCallDepth();
if (!context_.IsEmpty()) context_->Enter();
}
......
......@@ -13,7 +13,7 @@
namespace v8 {
namespace internal {
const int MemoryReducer::kLongDelayMs = 20000;
const int MemoryReducer::kLongDelayMs = 8000;
const int MemoryReducer::kShortDelayMs = 500;
const int MemoryReducer::kWatchdogDelayMs = 100000;
const int MemoryReducer::kMaxNumberOfGCs = 3;
......@@ -24,15 +24,27 @@ MemoryReducer::TimerTask::TimerTask(MemoryReducer* memory_reducer)
void MemoryReducer::TimerTask::RunInternal() {
const double kJsCallsPerMsThreshold = 0.25;
Heap* heap = memory_reducer_->heap();
Event event;
double time_ms = heap->MonotonicallyIncreasingTimeInMs();
heap->tracer()->SampleAllocation(time_ms, heap->NewSpaceAllocationCounter(),
heap->OldGenerationAllocationCounter());
double js_call_rate = memory_reducer_->SampleAndGetJsCallsPerMs(time_ms);
bool low_allocation_rate = heap->HasLowAllocationRate();
bool is_idle = js_call_rate < kJsCallsPerMsThreshold && low_allocation_rate;
bool optimize_for_memory = heap->ShouldOptimizeForMemoryUsage();
if (FLAG_trace_gc_verbose) {
PrintIsolate(heap->isolate(), "Memory reducer: call rate %.3lf, %s, %s\n",
js_call_rate, low_allocation_rate ? "low alloc" : "high alloc",
optimize_for_memory ? "background" : "foreground");
}
event.type = kTimer;
event.time_ms = time_ms;
event.should_start_incremental_gc =
heap->HasLowAllocationRate() || heap->ShouldOptimizeForMemoryUsage();
// The memory reducer will start incremental markig if
// 1) mutator is likely idle: js call rate is low and allocation rate is low.
// 2) mutator is in background: optimize for memory flag is set.
event.should_start_incremental_gc = is_idle || optimize_for_memory;
event.can_start_incremental_gc =
heap->incremental_marking()->IsStopped() &&
heap->incremental_marking()->CanBeActivated();
......@@ -40,6 +52,16 @@ void MemoryReducer::TimerTask::RunInternal() {
}
double MemoryReducer::SampleAndGetJsCallsPerMs(double time_ms) {
unsigned int counter = heap()->isolate()->js_calls_from_api_counter();
unsigned int call_delta = counter - js_calls_counter_;
double time_delta_ms = time_ms - js_calls_sample_time_ms_;
js_calls_counter_ = counter;
js_calls_sample_time_ms_ = time_ms;
return time_delta_ms > 0 ? call_delta / time_delta_ms : 0;
}
void MemoryReducer::NotifyTimer(const Event& event) {
DCHECK_EQ(kTimer, event.type);
DCHECK_EQ(kWait, state_.action);
......@@ -70,7 +92,7 @@ void MemoryReducer::NotifyTimer(const Event& event) {
"Memory reducer: finalize incremental marking");
}
// Re-schedule the timer.
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
ScheduleTimer(event.time_ms, state_.next_gc_start_ms - event.time_ms);
if (FLAG_trace_gc_verbose) {
PrintIsolate(heap()->isolate(), "Memory reducer: waiting for %.f ms\n",
state_.next_gc_start_ms - event.time_ms);
......@@ -85,7 +107,7 @@ void MemoryReducer::NotifyMarkCompact(const Event& event) {
state_ = Step(state_, event);
if (old_action != kWait && state_.action == kWait) {
// If we are transitioning to the WAIT state, start the timer.
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
ScheduleTimer(event.time_ms, state_.next_gc_start_ms - event.time_ms);
}
if (old_action == kRun) {
if (FLAG_trace_gc_verbose) {
......@@ -103,7 +125,7 @@ void MemoryReducer::NotifyContextDisposed(const Event& event) {
state_ = Step(state_, event);
if (old_action != kWait && state_.action == kWait) {
// If we are transitioning to the WAIT state, start the timer.
ScheduleTimer(state_.next_gc_start_ms - event.time_ms);
ScheduleTimer(event.time_ms, state_.next_gc_start_ms - event.time_ms);
}
}
......@@ -172,8 +194,10 @@ MemoryReducer::State MemoryReducer::Step(const State& state,
}
void MemoryReducer::ScheduleTimer(double delay_ms) {
void MemoryReducer::ScheduleTimer(double time_ms, double delay_ms) {
DCHECK(delay_ms > 0);
// Record the time and the js call counter.
SampleAndGetJsCallsPerMs(time_ms);
// Leave some room for precision error in task scheduler.
const double kSlackMs = 100;
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(heap()->isolate());
......
......@@ -107,7 +107,10 @@ class MemoryReducer {
};
explicit MemoryReducer(Heap* heap)
: heap_(heap), state_(kDone, 0, 0.0, 0.0) {}
: heap_(heap),
state_(kDone, 0, 0.0, 0.0),
js_calls_counter_(0),
js_calls_sample_time_ms_(0.0) {}
// Callbacks.
void NotifyMarkCompact(const Event& event);
void NotifyContextDisposed(const Event& event);
......@@ -116,7 +119,7 @@ class MemoryReducer {
// the incoming event.
static State Step(const State& state, const Event& event);
// Posts a timer task that will call NotifyTimer after the given delay.
void ScheduleTimer(double delay_ms);
void ScheduleTimer(double time_ms, double delay_ms);
void TearDown();
static const int kLongDelayMs;
static const int kShortDelayMs;
......@@ -145,8 +148,16 @@ class MemoryReducer {
static bool WatchdogGC(const State& state, const Event& event);
// Returns the rate of JS calls initiated from the API.
double SampleAndGetJsCallsPerMs(double time_ms);
Heap* heap_;
State state_;
unsigned int js_calls_counter_;
double js_calls_sample_time_ms_;
// Used in cctest.
friend class HeapTester;
DISALLOW_COPY_AND_ASSIGN(MemoryReducer);
};
......
......@@ -1792,6 +1792,7 @@ Isolate::Isolate(bool enable_serializer)
virtual_handler_register_(NULL),
virtual_slot_register_(NULL),
next_optimization_id_(0),
js_calls_from_api_counter_(0),
#if TRACE_MAPS
next_unique_sfi_id_(0),
#endif
......
......@@ -1046,6 +1046,12 @@ class Isolate {
return id;
}
void IncrementJsCallsFromApiCounter() { ++js_calls_from_api_counter_; }
unsigned int js_calls_from_api_counter() {
return js_calls_from_api_counter_;
}
// Get (and lazily initialize) the registry for per-isolate symbols.
Handle<JSObject> GetSymbolRegistry();
......@@ -1313,6 +1319,9 @@ class Isolate {
int next_optimization_id_;
// Counts javascript calls from the API. Wraps around on overflow.
unsigned int js_calls_from_api_counter_;
#if TRACE_MAPS
int next_unique_sfi_id_;
#endif
......
......@@ -530,6 +530,13 @@ static inline void DisableInlineAllocationSteps(v8::internal::NewSpace* space) {
}
static inline void CheckDoubleEquals(double expected, double actual) {
const double kEpsilon = 1e-10;
CHECK_LE(expected, actual + kEpsilon);
CHECK_GE(expected, actual - kEpsilon);
}
static int LenFromSize(int size) {
return (size - i::FixedArray::kHeaderSize) / i::kPointerSize;
}
......
......@@ -22,6 +22,7 @@
V(Regression39128) \
V(ResetWeakHandle) \
V(StressHandles) \
V(TestMemoryReducerSampleJsCalls) \
V(TestSizeOfObjects) \
V(WriteBarriersInCopyJSObject)
......
......@@ -35,6 +35,7 @@
#include "src/factory.h"
#include "src/global-handles.h"
#include "src/heap/gc-tracer.h"
#include "src/heap/memory-reducer.h"
#include "src/ic/ic.h"
#include "src/macro-assembler.h"
#include "src/snapshot/snapshot.h"
......@@ -6274,5 +6275,30 @@ TEST(Regress519319) {
}
HEAP_TEST(TestMemoryReducerSampleJsCalls) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Heap* heap = CcTest::heap();
Isolate* isolate = CcTest::i_isolate();
MemoryReducer* memory_reducer = heap->memory_reducer_;
memory_reducer->SampleAndGetJsCallsPerMs(0);
isolate->IncrementJsCallsFromApiCounter();
isolate->IncrementJsCallsFromApiCounter();
isolate->IncrementJsCallsFromApiCounter();
double calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(1);
CheckDoubleEquals(3, calls_per_ms);
calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(2);
CheckDoubleEquals(0, calls_per_ms);
isolate->IncrementJsCallsFromApiCounter();
isolate->IncrementJsCallsFromApiCounter();
isolate->IncrementJsCallsFromApiCounter();
isolate->IncrementJsCallsFromApiCounter();
calls_per_ms = memory_reducer->SampleAndGetJsCallsPerMs(4);
CheckDoubleEquals(2, calls_per_ms);
}
} // namespace internal
} // namespace v8
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