Commit 5b89001c authored by mlippautz's avatar mlippautz Committed by Commit bot

[heap] Base number of compaction tasks on live memory and compaction speed.

BUG=chromium:524425
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31762}
parent 3573d3cb
......@@ -309,6 +309,13 @@ void GCTracer::AddContextDisposalTime(double time) {
}
void GCTracer::AddCompactionEvent(double duration,
intptr_t live_bytes_compacted) {
compaction_events_.push_front(
CompactionEvent(duration, live_bytes_compacted));
}
void GCTracer::AddSurvivalRatio(double promotion_ratio) {
survival_events_.push_front(SurvivalEvent(promotion_ratio));
}
......@@ -535,7 +542,8 @@ void GCTracer::PrintNVP() const {
"semi_space_copy_rate=%.1f%% "
"new_space_allocation_throughput=%" V8_PTR_PREFIX
"d "
"context_disposal_rate=%.1f\n",
"context_disposal_rate=%.1f "
"compaction_speed=%" V8_PTR_PREFIX "d\n",
heap_->isolate()->time_millis_since_init(), duration,
spent_in_mutator, current_.TypeName(true),
current_.reduce_memory, current_.scopes[Scope::EXTERNAL],
......@@ -585,7 +593,8 @@ void GCTracer::PrintNVP() const {
heap_->promotion_ratio_, AverageSurvivalRatio(),
heap_->promotion_rate_, heap_->semi_space_copied_rate_,
NewSpaceAllocationThroughputInBytesPerMillisecond(),
ContextDisposalRateInMilliseconds());
ContextDisposalRateInMilliseconds(),
CompactionSpeedInBytesPerMillisecond());
break;
case Event::START:
break;
......@@ -706,6 +715,23 @@ intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond(
}
intptr_t GCTracer::CompactionSpeedInBytesPerMillisecond() const {
if (compaction_events_.size() < kRingBufferMaxSize) return 0.0;
intptr_t bytes = 0;
double durations = 0.0;
CompactionEventBuffer::const_iterator iter = compaction_events_.begin();
while (iter != compaction_events_.end()) {
bytes += iter->live_bytes_compacted;
durations += iter->duration;
++iter;
}
if (durations == 0.0) return 0;
// Make sure the result is at least 1.
return Max<intptr_t>(static_cast<intptr_t>(bytes / durations + 0.5), 1);
}
intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const {
intptr_t bytes = 0;
double durations = 0.0;
......
......@@ -178,6 +178,18 @@ class GCTracer {
};
class CompactionEvent {
public:
CompactionEvent() : duration(0), live_bytes_compacted(0) {}
CompactionEvent(double duration, intptr_t live_bytes_compacted)
: duration(duration), live_bytes_compacted(live_bytes_compacted) {}
double duration;
intptr_t live_bytes_compacted;
};
class ContextDisposalEvent {
public:
// Default constructor leaves the event uninitialized.
......@@ -314,6 +326,8 @@ class GCTracer {
typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
ContextDisposalEventBuffer;
typedef RingBuffer<CompactionEvent, kRingBufferMaxSize> CompactionEventBuffer;
typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
static const int kThroughputTimeFrameMs = 5000;
......@@ -336,6 +350,8 @@ class GCTracer {
void AddContextDisposalTime(double time);
void AddCompactionEvent(double duration, intptr_t live_bytes_compacted);
void AddSurvivalRatio(double survival_ratio);
// Log an incremental marking step.
......@@ -406,6 +422,10 @@ class GCTracer {
intptr_t ScavengeSpeedInBytesPerMillisecond(
ScavengeSpeedMode mode = kForAllObjects) const;
// Compute the average compaction speed in bytes/millisecond.
// Returns 0 if not enough events have been recorded.
intptr_t CompactionSpeedInBytesPerMillisecond() const;
// Compute the average mark-sweep speed in bytes/millisecond.
// Returns 0 if no events have been recorded.
intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
......@@ -520,6 +540,9 @@ class GCTracer {
// RingBuffer for context disposal events.
ContextDisposalEventBuffer context_disposal_events_;
// RingBuffer for compaction events.
CompactionEventBuffer compaction_events_;
// RingBuffer for survival events.
SurvivalEventBuffer survival_events_;
......
......@@ -3267,7 +3267,6 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage(
DCHECK(p->IsEvacuationCandidate() && !p->WasSwept());
int offsets[16];
for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) {
Address cell_base = it.CurrentCellBase();
MarkBit::CellType* cell = it.CurrentCell();
......@@ -3309,23 +3308,33 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage(
int MarkCompactCollector::NumberOfParallelCompactionTasks() {
if (!FLAG_parallel_compaction) return 1;
// We cap the number of parallel compaction tasks by
// Compute the number of needed tasks based on a target compaction time, the
// profiled compaction speed and marked live memory.
//
// The number of parallel compaction tasks is limited by:
// - #evacuation pages
// - (#cores - 1)
// - a value depending on the live memory in evacuation candidates
// - a hard limit
//
// TODO(mlippautz): Instead of basing the limit on live memory, we could also
// compute the number from the time it takes to evacuate memory and a given
// desired time in which compaction should be finished.
const int kLiveMemoryPerCompactionTask = 2 * Page::kPageSize;
const double kTargetCompactionTimeInMs = 1;
const int kMaxCompactionTasks = 8;
int live_bytes = 0;
intptr_t compaction_speed =
heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
if (compaction_speed == 0) return 1;
intptr_t live_bytes = 0;
for (Page* page : evacuation_candidates_) {
live_bytes += page->LiveBytes();
}
return Min(kMaxCompactionTasks,
Min(1 + live_bytes / kLiveMemoryPerCompactionTask,
Max(1, base::SysInfo::NumberOfProcessors() - 1)));
const int cores = Max(1, base::SysInfo::NumberOfProcessors() - 1);
const int tasks =
1 + static_cast<int>(static_cast<double>(live_bytes) / compaction_speed /
kTargetCompactionTimeInMs);
const int tasks_capped_pages = Min(evacuation_candidates_.length(), tasks);
const int tasks_capped_cores = Min(cores, tasks_capped_pages);
const int tasks_capped_hard = Min(kMaxCompactionTasks, tasks_capped_cores);
return tasks_capped_hard;
}
......@@ -3333,8 +3342,18 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
const int num_pages = evacuation_candidates_.length();
if (num_pages == 0) return;
// Used for trace summary.
intptr_t live_bytes = 0;
intptr_t compaction_speed = 0;
if (FLAG_trace_fragmentation) {
for (Page* page : evacuation_candidates_) {
live_bytes += page->LiveBytes();
}
compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
}
const int num_tasks = NumberOfParallelCompactionTasks();
// Set up compaction spaces.
CompactionSpaceCollection** compaction_spaces_for_tasks =
new CompactionSpaceCollection*[num_tasks];
......@@ -3361,15 +3380,20 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
WaitUntilCompactionCompleted();
double compaction_duration = 0.0;
intptr_t compacted_memory = 0;
// Merge back memory (compacted and unused) from compaction spaces.
for (int i = 0; i < num_tasks; i++) {
heap()->old_space()->MergeCompactionSpace(
compaction_spaces_for_tasks[i]->Get(OLD_SPACE));
heap()->code_space()->MergeCompactionSpace(
compaction_spaces_for_tasks[i]->Get(CODE_SPACE));
compacted_memory += compaction_spaces_for_tasks[i]->bytes_compacted();
compaction_duration += compaction_spaces_for_tasks[i]->duration();
delete compaction_spaces_for_tasks[i];
}
delete[] compaction_spaces_for_tasks;
heap()->tracer()->AddCompactionEvent(compaction_duration, compacted_memory);
// Finalize sequentially.
int abandoned_pages = 0;
......@@ -3410,10 +3434,12 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
if (FLAG_trace_fragmentation) {
PrintIsolate(isolate(),
"%8.0f ms: compaction: parallel=%d pages=%d aborted=%d "
"tasks=%d cores=%d\n",
"tasks=%d cores=%d live_bytes=%" V8_PTR_PREFIX
"d compaction_speed=%" V8_PTR_PREFIX "d\n",
isolate()->time_millis_since_init(), FLAG_parallel_compaction,
num_pages, abandoned_pages, num_tasks,
base::SysInfo::NumberOfProcessors());
base::SysInfo::NumberOfProcessors(), live_bytes,
compaction_speed);
}
}
......@@ -3441,11 +3467,15 @@ void MarkCompactCollector::EvacuatePages(
if (p->IsEvacuationCandidate()) {
DCHECK_EQ(p->parallel_compaction_state().Value(),
MemoryChunk::kCompactingInProgress);
double start = heap()->MonotonicallyIncreasingTimeInMs();
intptr_t live_bytes = p->LiveBytes();
if (EvacuateLiveObjectsFromPage(
p, compaction_spaces->Get(p->owner()->identity()),
evacuation_slots_buffer)) {
p->parallel_compaction_state().SetValue(
MemoryChunk::kCompactingFinalize);
compaction_spaces->ReportCompactionProgress(
heap()->MonotonicallyIncreasingTimeInMs() - start, live_bytes);
} else {
p->parallel_compaction_state().SetValue(
MemoryChunk::kCompactingAborted);
......
......@@ -2857,7 +2857,9 @@ class CompactionSpaceCollection : public Malloced {
public:
explicit CompactionSpaceCollection(Heap* heap)
: old_space_(heap, OLD_SPACE, Executability::NOT_EXECUTABLE),
code_space_(heap, CODE_SPACE, Executability::EXECUTABLE) {}
code_space_(heap, CODE_SPACE, Executability::EXECUTABLE),
duration_(0.0),
bytes_compacted_(0) {}
CompactionSpace* Get(AllocationSpace space) {
switch (space) {
......@@ -2872,9 +2874,21 @@ class CompactionSpaceCollection : public Malloced {
return nullptr;
}
void ReportCompactionProgress(double duration, intptr_t bytes_compacted) {
duration_ += duration;
bytes_compacted_ += bytes_compacted;
}
double duration() const { return duration_; }
intptr_t bytes_compacted() const { return bytes_compacted_; }
private:
CompactionSpace old_space_;
CompactionSpace code_space_;
// Book keeping.
double duration_;
intptr_t bytes_compacted_;
};
......
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