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) { ...@@ -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) { void GCTracer::AddSurvivalRatio(double promotion_ratio) {
survival_events_.push_front(SurvivalEvent(promotion_ratio)); survival_events_.push_front(SurvivalEvent(promotion_ratio));
} }
...@@ -535,7 +542,8 @@ void GCTracer::PrintNVP() const { ...@@ -535,7 +542,8 @@ void GCTracer::PrintNVP() const {
"semi_space_copy_rate=%.1f%% " "semi_space_copy_rate=%.1f%% "
"new_space_allocation_throughput=%" V8_PTR_PREFIX "new_space_allocation_throughput=%" V8_PTR_PREFIX
"d " "d "
"context_disposal_rate=%.1f\n", "context_disposal_rate=%.1f "
"compaction_speed=%" V8_PTR_PREFIX "d\n",
heap_->isolate()->time_millis_since_init(), duration, heap_->isolate()->time_millis_since_init(), duration,
spent_in_mutator, current_.TypeName(true), spent_in_mutator, current_.TypeName(true),
current_.reduce_memory, current_.scopes[Scope::EXTERNAL], current_.reduce_memory, current_.scopes[Scope::EXTERNAL],
...@@ -585,7 +593,8 @@ void GCTracer::PrintNVP() const { ...@@ -585,7 +593,8 @@ void GCTracer::PrintNVP() const {
heap_->promotion_ratio_, AverageSurvivalRatio(), heap_->promotion_ratio_, AverageSurvivalRatio(),
heap_->promotion_rate_, heap_->semi_space_copied_rate_, heap_->promotion_rate_, heap_->semi_space_copied_rate_,
NewSpaceAllocationThroughputInBytesPerMillisecond(), NewSpaceAllocationThroughputInBytesPerMillisecond(),
ContextDisposalRateInMilliseconds()); ContextDisposalRateInMilliseconds(),
CompactionSpeedInBytesPerMillisecond());
break; break;
case Event::START: case Event::START:
break; break;
...@@ -706,6 +715,23 @@ intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond( ...@@ -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 GCTracer::MarkCompactSpeedInBytesPerMillisecond() const {
intptr_t bytes = 0; intptr_t bytes = 0;
double durations = 0.0; double durations = 0.0;
......
...@@ -178,6 +178,18 @@ class GCTracer { ...@@ -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 { class ContextDisposalEvent {
public: public:
// Default constructor leaves the event uninitialized. // Default constructor leaves the event uninitialized.
...@@ -314,6 +326,8 @@ class GCTracer { ...@@ -314,6 +326,8 @@ class GCTracer {
typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize> typedef RingBuffer<ContextDisposalEvent, kRingBufferMaxSize>
ContextDisposalEventBuffer; ContextDisposalEventBuffer;
typedef RingBuffer<CompactionEvent, kRingBufferMaxSize> CompactionEventBuffer;
typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer; typedef RingBuffer<SurvivalEvent, kRingBufferMaxSize> SurvivalEventBuffer;
static const int kThroughputTimeFrameMs = 5000; static const int kThroughputTimeFrameMs = 5000;
...@@ -336,6 +350,8 @@ class GCTracer { ...@@ -336,6 +350,8 @@ class GCTracer {
void AddContextDisposalTime(double time); void AddContextDisposalTime(double time);
void AddCompactionEvent(double duration, intptr_t live_bytes_compacted);
void AddSurvivalRatio(double survival_ratio); void AddSurvivalRatio(double survival_ratio);
// Log an incremental marking step. // Log an incremental marking step.
...@@ -406,6 +422,10 @@ class GCTracer { ...@@ -406,6 +422,10 @@ class GCTracer {
intptr_t ScavengeSpeedInBytesPerMillisecond( intptr_t ScavengeSpeedInBytesPerMillisecond(
ScavengeSpeedMode mode = kForAllObjects) const; 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. // Compute the average mark-sweep speed in bytes/millisecond.
// Returns 0 if no events have been recorded. // Returns 0 if no events have been recorded.
intptr_t MarkCompactSpeedInBytesPerMillisecond() const; intptr_t MarkCompactSpeedInBytesPerMillisecond() const;
...@@ -520,6 +540,9 @@ class GCTracer { ...@@ -520,6 +540,9 @@ class GCTracer {
// RingBuffer for context disposal events. // RingBuffer for context disposal events.
ContextDisposalEventBuffer context_disposal_events_; ContextDisposalEventBuffer context_disposal_events_;
// RingBuffer for compaction events.
CompactionEventBuffer compaction_events_;
// RingBuffer for survival events. // RingBuffer for survival events.
SurvivalEventBuffer survival_events_; SurvivalEventBuffer survival_events_;
......
...@@ -3267,7 +3267,6 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage( ...@@ -3267,7 +3267,6 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage(
DCHECK(p->IsEvacuationCandidate() && !p->WasSwept()); DCHECK(p->IsEvacuationCandidate() && !p->WasSwept());
int offsets[16]; int offsets[16];
for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) { for (MarkBitCellIterator it(p); !it.Done(); it.Advance()) {
Address cell_base = it.CurrentCellBase(); Address cell_base = it.CurrentCellBase();
MarkBit::CellType* cell = it.CurrentCell(); MarkBit::CellType* cell = it.CurrentCell();
...@@ -3309,23 +3308,33 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage( ...@@ -3309,23 +3308,33 @@ bool MarkCompactCollector::EvacuateLiveObjectsFromPage(
int MarkCompactCollector::NumberOfParallelCompactionTasks() { int MarkCompactCollector::NumberOfParallelCompactionTasks() {
if (!FLAG_parallel_compaction) return 1; 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) // - (#cores - 1)
// - a value depending on the live memory in evacuation candidates
// - a hard limit // - a hard limit
// const double kTargetCompactionTimeInMs = 1;
// 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 int kMaxCompactionTasks = 8; 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_) { for (Page* page : evacuation_candidates_) {
live_bytes += page->LiveBytes(); live_bytes += page->LiveBytes();
} }
return Min(kMaxCompactionTasks,
Min(1 + live_bytes / kLiveMemoryPerCompactionTask, const int cores = Max(1, base::SysInfo::NumberOfProcessors() - 1);
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() { ...@@ -3333,8 +3342,18 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
const int num_pages = evacuation_candidates_.length(); const int num_pages = evacuation_candidates_.length();
if (num_pages == 0) return; 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(); const int num_tasks = NumberOfParallelCompactionTasks();
// Set up compaction spaces. // Set up compaction spaces.
CompactionSpaceCollection** compaction_spaces_for_tasks = CompactionSpaceCollection** compaction_spaces_for_tasks =
new CompactionSpaceCollection*[num_tasks]; new CompactionSpaceCollection*[num_tasks];
...@@ -3361,15 +3380,20 @@ void MarkCompactCollector::EvacuatePagesInParallel() { ...@@ -3361,15 +3380,20 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
WaitUntilCompactionCompleted(); WaitUntilCompactionCompleted();
double compaction_duration = 0.0;
intptr_t compacted_memory = 0;
// Merge back memory (compacted and unused) from compaction spaces. // Merge back memory (compacted and unused) from compaction spaces.
for (int i = 0; i < num_tasks; i++) { for (int i = 0; i < num_tasks; i++) {
heap()->old_space()->MergeCompactionSpace( heap()->old_space()->MergeCompactionSpace(
compaction_spaces_for_tasks[i]->Get(OLD_SPACE)); compaction_spaces_for_tasks[i]->Get(OLD_SPACE));
heap()->code_space()->MergeCompactionSpace( heap()->code_space()->MergeCompactionSpace(
compaction_spaces_for_tasks[i]->Get(CODE_SPACE)); 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[i];
} }
delete[] compaction_spaces_for_tasks; delete[] compaction_spaces_for_tasks;
heap()->tracer()->AddCompactionEvent(compaction_duration, compacted_memory);
// Finalize sequentially. // Finalize sequentially.
int abandoned_pages = 0; int abandoned_pages = 0;
...@@ -3410,10 +3434,12 @@ void MarkCompactCollector::EvacuatePagesInParallel() { ...@@ -3410,10 +3434,12 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
if (FLAG_trace_fragmentation) { if (FLAG_trace_fragmentation) {
PrintIsolate(isolate(), PrintIsolate(isolate(),
"%8.0f ms: compaction: parallel=%d pages=%d aborted=%d " "%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, isolate()->time_millis_since_init(), FLAG_parallel_compaction,
num_pages, abandoned_pages, num_tasks, num_pages, abandoned_pages, num_tasks,
base::SysInfo::NumberOfProcessors()); base::SysInfo::NumberOfProcessors(), live_bytes,
compaction_speed);
} }
} }
...@@ -3441,11 +3467,15 @@ void MarkCompactCollector::EvacuatePages( ...@@ -3441,11 +3467,15 @@ void MarkCompactCollector::EvacuatePages(
if (p->IsEvacuationCandidate()) { if (p->IsEvacuationCandidate()) {
DCHECK_EQ(p->parallel_compaction_state().Value(), DCHECK_EQ(p->parallel_compaction_state().Value(),
MemoryChunk::kCompactingInProgress); MemoryChunk::kCompactingInProgress);
double start = heap()->MonotonicallyIncreasingTimeInMs();
intptr_t live_bytes = p->LiveBytes();
if (EvacuateLiveObjectsFromPage( if (EvacuateLiveObjectsFromPage(
p, compaction_spaces->Get(p->owner()->identity()), p, compaction_spaces->Get(p->owner()->identity()),
evacuation_slots_buffer)) { evacuation_slots_buffer)) {
p->parallel_compaction_state().SetValue( p->parallel_compaction_state().SetValue(
MemoryChunk::kCompactingFinalize); MemoryChunk::kCompactingFinalize);
compaction_spaces->ReportCompactionProgress(
heap()->MonotonicallyIncreasingTimeInMs() - start, live_bytes);
} else { } else {
p->parallel_compaction_state().SetValue( p->parallel_compaction_state().SetValue(
MemoryChunk::kCompactingAborted); MemoryChunk::kCompactingAborted);
......
...@@ -2857,7 +2857,9 @@ class CompactionSpaceCollection : public Malloced { ...@@ -2857,7 +2857,9 @@ class CompactionSpaceCollection : public Malloced {
public: public:
explicit CompactionSpaceCollection(Heap* heap) explicit CompactionSpaceCollection(Heap* heap)
: old_space_(heap, OLD_SPACE, Executability::NOT_EXECUTABLE), : 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) { CompactionSpace* Get(AllocationSpace space) {
switch (space) { switch (space) {
...@@ -2872,9 +2874,21 @@ class CompactionSpaceCollection : public Malloced { ...@@ -2872,9 +2874,21 @@ class CompactionSpaceCollection : public Malloced {
return nullptr; 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: private:
CompactionSpace old_space_; CompactionSpace old_space_;
CompactionSpace code_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