blob: edd5e42e263e356579d5b7568fc970a863dace16 [file] [log] [blame]
// 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 {
enum GCIdleTimeActionType {
DONE,
DO_NOTHING,
DO_INCREMENTAL_MARKING,
DO_SCAVENGE,
DO_FULL_GC,
DO_FINALIZE_SWEEPING
};
class GCIdleTimeAction {
public:
static GCIdleTimeAction Done() {
GCIdleTimeAction result;
result.type = DONE;
result.parameter = 0;
return result;
}
static GCIdleTimeAction Nothing() {
GCIdleTimeAction result;
result.type = DO_NOTHING;
result.parameter = 0;
return result;
}
static GCIdleTimeAction IncrementalMarking(intptr_t step_size) {
GCIdleTimeAction result;
result.type = DO_INCREMENTAL_MARKING;
result.parameter = step_size;
return result;
}
static GCIdleTimeAction Scavenge() {
GCIdleTimeAction result;
result.type = DO_SCAVENGE;
result.parameter = 0;
return result;
}
static GCIdleTimeAction FullGC() {
GCIdleTimeAction result;
result.type = DO_FULL_GC;
result.parameter = 0;
return result;
}
static GCIdleTimeAction FinalizeSweeping() {
GCIdleTimeAction result;
result.type = DO_FINALIZE_SWEEPING;
result.parameter = 0;
return result;
}
void Print();
GCIdleTimeActionType type;
intptr_t parameter;
};
class GCTracer;
// The idle time handler makes decisions about which garbage collection
// operations are executing during IdleNotification.
class GCIdleTimeHandler {
public:
// If we haven't recorded any incremental marking events yet, we carefully
// mark with a conservative lower bound for the marking speed.
static const size_t kInitialConservativeMarkingSpeed = 100 * KB;
// Maximum marking step size returned by EstimateMarkingStepSize.
static const size_t kMaximumMarkingStepSize = 700 * MB;
// 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;
// If we haven't recorded any mark-compact events yet, we use
// conservative lower bound for the mark-compact speed.
static const size_t kInitialConservativeMarkCompactSpeed = 2 * MB;
// Maximum mark-compact time returned by EstimateMarkCompactTime.
static const size_t kMaxMarkCompactTimeInMs;
// Minimum time to finalize sweeping phase. The main thread may wait for
// sweeper threads.
static const size_t kMinTimeForFinalizeSweeping;
// Number of idle mark-compact events, after which idle handler will finish
// idle round.
static const int kMaxMarkCompactsInIdleRound;
// Number of scavenges that will trigger start of new idle round.
static const int kIdleScavengeThreshold;
// Heap size threshold below which we prefer mark-compact over incremental
// step.
static const size_t kSmallHeapSize = 4 * kPointerSize * MB;
// That is the maximum idle time we will have during frame rendering.
static const size_t kMaxFrameRenderingIdleTime = 16;
// 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;
struct HeapState {
int contexts_disposed;
size_t size_of_objects;
bool incremental_marking_stopped;
bool can_start_incremental_marking;
bool sweeping_in_progress;
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 used_new_space_size;
size_t new_space_capacity;
size_t new_space_allocation_throughput_in_bytes_per_ms;
};
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);
void NotifyIdleMarkCompact() {
if (mark_compacts_since_idle_round_started_ < kMaxMarkCompactsInIdleRound) {
++mark_compacts_since_idle_round_started_;
if (mark_compacts_since_idle_round_started_ ==
kMaxMarkCompactsInIdleRound) {
scavenges_since_last_idle_round_ = 0;
}
}
}
void NotifyScavenge() { ++scavenges_since_last_idle_round_; }
static size_t EstimateMarkingStepSize(size_t idle_time_in_ms,
size_t marking_speed_in_bytes_per_ms);
static size_t EstimateMarkCompactTime(
size_t size_of_objects, size_t mark_compact_speed_in_bytes_per_ms);
static bool ShouldDoMarkCompact(size_t idle_time_in_ms,
size_t size_of_objects,
size_t mark_compact_speed_in_bytes_per_ms);
static bool ShouldDoScavenge(
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:
void StartIdleRound() { mark_compacts_since_idle_round_started_ = 0; }
bool IsMarkCompactIdleRoundFinished() {
return mark_compacts_since_idle_round_started_ ==
kMaxMarkCompactsInIdleRound;
}
bool EnoughGarbageSinceLastIdleRound() {
return scavenges_since_last_idle_round_ >= kIdleScavengeThreshold;
}
int mark_compacts_since_idle_round_started_;
int scavenges_since_last_idle_round_;
DISALLOW_COPY_AND_ASSIGN(GCIdleTimeHandler);
};
} // namespace internal
} // namespace v8
#endif // V8_HEAP_GC_IDLE_TIME_HANDLER_H_