Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Unified Diff: src/heap/mark-compact.cc

Issue 1782043004: [heap] Use PageParallelJob for parallel evacuation (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/page-parallel-job.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/heap/mark-compact.cc
diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc
index 438bb4abf2ea076e48da074548eb28129f280260..33bf3da5c71664a5c1d0903daed9d3b7049c1dd3 100644
--- a/src/heap/mark-compact.cc
+++ b/src/heap/mark-compact.cc
@@ -665,11 +665,6 @@ void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
while (it.has_next()) {
Page* p = it.next();
if (p->NeverEvacuate()) continue;
- if (p->IsFlagSet(Page::POPULAR_PAGE)) {
- // This page had slots buffer overflow on previous GC, skip it.
- p->ClearFlag(Page::POPULAR_PAGE);
- continue;
- }
// Invariant: Evacuation candidates are just created when marking is
// started. This means that sweeping has finished. Furthermore, at the end
// of a GC all evacuation candidates are cleared and their slot buffers are
@@ -2958,12 +2953,8 @@ void MarkCompactCollector::EvacuateNewSpaceEpilogue() {
class MarkCompactCollector::Evacuator : public Malloced {
public:
- Evacuator(MarkCompactCollector* collector,
- const List<Page*>& evacuation_candidates,
- const List<NewSpacePage*>& newspace_evacuation_candidates)
+ explicit Evacuator(MarkCompactCollector* collector)
: collector_(collector),
- evacuation_candidates_(evacuation_candidates),
- newspace_evacuation_candidates_(newspace_evacuation_candidates),
compaction_spaces_(collector->heap()),
local_pretenuring_feedback_(HashMap::PointersMatch,
kInitialLocalPretenuringFeedbackCapacity),
@@ -2973,11 +2964,9 @@ class MarkCompactCollector::Evacuator : public Malloced {
old_space_visitor_(collector->heap(), &compaction_spaces_,
&old_to_old_slots_, &old_to_new_slots_),
duration_(0.0),
- bytes_compacted_(0),
- task_id_(0) {}
+ bytes_compacted_(0) {}
- // Evacuate the configured set of pages in parallel.
- inline void EvacuatePages();
+ inline bool EvacuatePage(MemoryChunk* chunk);
// Merge back locally cached info sequentially. Note that this method needs
// to be called from the main thread.
@@ -2985,9 +2974,6 @@ class MarkCompactCollector::Evacuator : public Malloced {
CompactionSpaceCollection* compaction_spaces() { return &compaction_spaces_; }
- uint32_t task_id() { return task_id_; }
- void set_task_id(uint32_t id) { task_id_ = id; }
-
private:
static const int kInitialLocalPretenuringFeedbackCapacity = 256;
@@ -3002,10 +2988,6 @@ class MarkCompactCollector::Evacuator : public Malloced {
MarkCompactCollector* collector_;
- // Pages to process.
- const List<Page*>& evacuation_candidates_;
- const List<NewSpacePage*>& newspace_evacuation_candidates_;
-
// Locally cached collector data.
CompactionSpaceCollection compaction_spaces_;
LocalSlotsBuffer old_to_old_slots_;
@@ -3019,60 +3001,40 @@ class MarkCompactCollector::Evacuator : public Malloced {
// Book keeping info.
double duration_;
intptr_t bytes_compacted_;
-
- // Task id, if this evacuator is executed on a background task instead of
- // the main thread. Can be used to try to abort the task currently scheduled
- // to executed to evacuate pages.
- uint32_t task_id_;
};
bool MarkCompactCollector::Evacuator::EvacuateSinglePage(
MemoryChunk* p, HeapObjectVisitor* visitor) {
- bool success = true;
- if (p->parallel_compaction_state().TrySetValue(
- MemoryChunk::kCompactingDone, MemoryChunk::kCompactingInProgress)) {
- if (p->IsEvacuationCandidate() || p->InNewSpace()) {
- DCHECK_EQ(p->parallel_compaction_state().Value(),
- MemoryChunk::kCompactingInProgress);
- int saved_live_bytes = p->LiveBytes();
- double evacuation_time;
- {
- AlwaysAllocateScope always_allocate(heap()->isolate());
- TimedScope timed_scope(&evacuation_time);
- success = collector_->VisitLiveObjects(p, visitor, kClearMarkbits);
- }
- if (success) {
- ReportCompactionProgress(evacuation_time, saved_live_bytes);
- p->parallel_compaction_state().SetValue(
- MemoryChunk::kCompactingFinalize);
- } else {
- p->parallel_compaction_state().SetValue(
- MemoryChunk::kCompactingAborted);
- }
- } else {
- // There could be popular pages in the list of evacuation candidates
- // which we do not compact.
- p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
- }
+ bool success = false;
+ DCHECK(p->IsEvacuationCandidate() || p->InNewSpace());
+ int saved_live_bytes = p->LiveBytes();
+ double evacuation_time;
+ {
+ AlwaysAllocateScope always_allocate(heap()->isolate());
+ TimedScope timed_scope(&evacuation_time);
+ success = collector_->VisitLiveObjects(p, visitor, kClearMarkbits);
+ }
+ if (success) {
+ ReportCompactionProgress(evacuation_time, saved_live_bytes);
}
return success;
}
-void MarkCompactCollector::Evacuator::EvacuatePages() {
- for (NewSpacePage* p : newspace_evacuation_candidates_) {
- DCHECK(p->InNewSpace());
- DCHECK_EQ(p->concurrent_sweeping_state().Value(),
+bool MarkCompactCollector::Evacuator::EvacuatePage(MemoryChunk* chunk) {
+ bool success = false;
+ if (chunk->InNewSpace()) {
+ DCHECK_EQ(chunk->concurrent_sweeping_state().Value(),
NewSpacePage::kSweepingDone);
- bool success = EvacuateSinglePage(p, &new_space_visitor_);
+ success = EvacuateSinglePage(chunk, &new_space_visitor_);
DCHECK(success);
USE(success);
+ } else {
+ DCHECK(chunk->IsEvacuationCandidate() ||
+ chunk->IsFlagSet(MemoryChunk::RESCAN_ON_EVACUATION));
+ DCHECK_EQ(chunk->concurrent_sweeping_state().Value(), Page::kSweepingDone);
+ success = EvacuateSinglePage(chunk, &old_space_visitor_);
}
- for (Page* p : evacuation_candidates_) {
- DCHECK(p->IsEvacuationCandidate() ||
- p->IsFlagSet(MemoryChunk::RESCAN_ON_EVACUATION));
- DCHECK_EQ(p->concurrent_sweeping_state().Value(), Page::kSweepingDone);
- EvacuateSinglePage(p, &old_space_visitor_);
- }
+ return success;
}
void MarkCompactCollector::Evacuator::Finalize() {
@@ -3105,29 +3067,6 @@ void MarkCompactCollector::Evacuator::Finalize() {
});
}
-class MarkCompactCollector::CompactionTask : public CancelableTask {
- public:
- explicit CompactionTask(Heap* heap, Evacuator* evacuator)
- : CancelableTask(heap->isolate()), heap_(heap), evacuator_(evacuator) {
- evacuator->set_task_id(id());
- }
-
- virtual ~CompactionTask() {}
-
- private:
- // v8::internal::CancelableTask overrides.
- void RunInternal() override {
- evacuator_->EvacuatePages();
- heap_->mark_compact_collector()
- ->pending_compaction_tasks_semaphore_.Signal();
- }
-
- Heap* heap_;
- Evacuator* evacuator_;
-
- DISALLOW_COPY_AND_ASSIGN(CompactionTask);
-};
-
int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages,
intptr_t live_bytes) {
if (!FLAG_parallel_compaction) return 1;
@@ -3158,19 +3097,63 @@ int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages,
return Min(available_cores, tasks_capped_pages);
}
+class EvacuationJobTraits {
+ public:
+ typedef int* PerPageData; // Pointer to number of aborted pages.
+ typedef MarkCompactCollector::Evacuator* PerTaskData;
+
+ static const bool NeedSequentialFinalization = true;
+
+ static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator,
+ MemoryChunk* chunk, PerPageData) {
+ return evacuator->EvacuatePage(chunk);
+ }
+
+ static void FinalizePageSequentially(Heap*, MemoryChunk* chunk, bool success,
+ PerPageData data) {
+ if (chunk->InNewSpace()) {
+ DCHECK(success);
+ } else {
+ Page* p = static_cast<Page*>(chunk);
+ if (success) {
+ DCHECK(p->IsEvacuationCandidate());
+ DCHECK(p->SweepingDone());
+ p->Unlink();
+ } else {
+ // We have partially compacted the page, i.e., some objects may have
+ // moved, others are still in place.
+ // We need to:
+ // - Leave the evacuation candidate flag for later processing of slots
+ // buffer entries.
+ // - Leave the slots buffer there for processing of entries added by
+ // the write barrier.
+ // - Rescan the page as slot recording in the migration buffer only
+ // happens upon moving (which we potentially didn't do).
+ // - Leave the page in the list of pages of a space since we could not
+ // fully evacuate it.
+ DCHECK(p->IsEvacuationCandidate());
+ p->SetFlag(Page::COMPACTION_WAS_ABORTED);
+ *data += 1;
+ }
+ }
+ }
+};
void MarkCompactCollector::EvacuatePagesInParallel() {
- int num_pages = 0;
+ PageParallelJob<EvacuationJobTraits> job(
+ heap_, heap_->isolate()->cancelable_task_manager());
+
+ int abandoned_pages = 0;
intptr_t live_bytes = 0;
for (Page* page : evacuation_candidates_) {
- num_pages++;
live_bytes += page->LiveBytes();
+ job.AddPage(page, &abandoned_pages);
}
for (NewSpacePage* page : newspace_evacuation_candidates_) {
- num_pages++;
live_bytes += page->LiveBytes();
+ job.AddPage(page, &abandoned_pages);
}
- DCHECK_GE(num_pages, 1);
+ DCHECK_GE(job.NumberOfPages(), 1);
// Used for trace summary.
intptr_t compaction_speed = 0;
@@ -3178,113 +3161,32 @@ void MarkCompactCollector::EvacuatePagesInParallel() {
compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
}
- const int num_tasks = NumberOfParallelCompactionTasks(num_pages, live_bytes);
-
- // Set up compaction spaces.
- Evacuator** evacuators = new Evacuator*[num_tasks];
- for (int i = 0; i < num_tasks; i++) {
- evacuators[i] = new Evacuator(this, evacuation_candidates_,
- newspace_evacuation_candidates_);
+ const int wanted_num_tasks =
+ NumberOfParallelCompactionTasks(job.NumberOfPages(), live_bytes);
+ Evacuator** evacuators = new Evacuator*[wanted_num_tasks];
+ for (int i = 0; i < wanted_num_tasks; i++) {
+ evacuators[i] = new Evacuator(this);
}
-
- // Kick off parallel tasks.
- StartParallelCompaction(evacuators, num_tasks);
- // Wait for unfinished and not-yet-started tasks.
- WaitUntilCompactionCompleted(&evacuators[1], num_tasks - 1);
-
- // Finalize local evacuators by merging back all locally cached data.
- for (int i = 0; i < num_tasks; i++) {
+ job.Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
+ for (int i = 0; i < wanted_num_tasks; i++) {
evacuators[i]->Finalize();
delete evacuators[i];
}
delete[] evacuators;
- // Finalize pages sequentially.
- for (NewSpacePage* p : newspace_evacuation_candidates_) {
- DCHECK_EQ(p->parallel_compaction_state().Value(),
- MemoryChunk::kCompactingFinalize);
- p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
- }
-
- int abandoned_pages = 0;
- for (Page* p : evacuation_candidates_) {
- switch (p->parallel_compaction_state().Value()) {
- case MemoryChunk::ParallelCompactingState::kCompactingAborted:
- // We have partially compacted the page, i.e., some objects may have
- // moved, others are still in place.
- // We need to:
- // - Leave the evacuation candidate flag for later processing of
- // slots buffer entries.
- // - Leave the slots buffer there for processing of entries added by
- // the write barrier.
- // - Rescan the page as slot recording in the migration buffer only
- // happens upon moving (which we potentially didn't do).
- // - Leave the page in the list of pages of a space since we could not
- // fully evacuate it.
- // - Mark them for rescanning for store buffer entries as we otherwise
- // might have stale store buffer entries that become "valid" again
- // after reusing the memory. Note that all existing store buffer
- // entries of such pages are filtered before rescanning.
- DCHECK(p->IsEvacuationCandidate());
- p->SetFlag(Page::COMPACTION_WAS_ABORTED);
- abandoned_pages++;
- break;
- case MemoryChunk::kCompactingFinalize:
- DCHECK(p->IsEvacuationCandidate());
- DCHECK(p->SweepingDone());
- p->Unlink();
- break;
- case MemoryChunk::kCompactingDone:
- DCHECK(p->IsFlagSet(Page::POPULAR_PAGE));
- DCHECK(p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
- break;
- default:
- // MemoryChunk::kCompactingInProgress.
- UNREACHABLE();
- }
- p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
- }
if (FLAG_trace_fragmentation) {
PrintIsolate(isolate(),
"%8.0f ms: compaction: parallel=%d pages=%d aborted=%d "
- "tasks=%d cores=%d live_bytes=%" V8_PTR_PREFIX
+ "wanted_tasks=%d 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(), live_bytes,
- compaction_speed);
- }
-}
-
-void MarkCompactCollector::StartParallelCompaction(Evacuator** evacuators,
- int len) {
- compaction_in_progress_ = true;
- for (int i = 1; i < len; i++) {
- CompactionTask* task = new CompactionTask(heap(), evacuators[i]);
- V8::GetCurrentPlatform()->CallOnBackgroundThread(
- task, v8::Platform::kShortRunningTask);
+ job.NumberOfPages(), abandoned_pages, wanted_num_tasks,
+ job.NumberOfTasks(),
+ V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
+ live_bytes, compaction_speed);
}
-
- // Contribute on main thread.
- evacuators[0]->EvacuatePages();
}
-void MarkCompactCollector::WaitUntilCompactionCompleted(Evacuator** evacuators,
- int len) {
- // Try to cancel compaction tasks that have not been run (as they might be
- // stuck in a worker queue). Tasks that cannot be canceled, have either
- // already completed or are still running, hence we need to wait for their
- // semaphore signal.
- for (int i = 0; i < len; i++) {
- if (!heap()->isolate()->cancelable_task_manager()->TryAbort(
- evacuators[i]->task_id())) {
- pending_compaction_tasks_semaphore_.Wait();
- }
- }
- compaction_in_progress_ = false;
-}
-
-
class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
public:
virtual Object* RetainAs(Object* object) {
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/page-parallel-job.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698