Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
| 6 | 6 |
| 7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
| 8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
| 9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 3292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3303 *cell = 0; | 3303 *cell = 0; |
| 3304 } | 3304 } |
| 3305 p->ResetLiveBytes(); | 3305 p->ResetLiveBytes(); |
| 3306 return true; | 3306 return true; |
| 3307 } | 3307 } |
| 3308 | 3308 |
| 3309 | 3309 |
| 3310 int MarkCompactCollector::NumberOfParallelCompactionTasks() { | 3310 int MarkCompactCollector::NumberOfParallelCompactionTasks() { |
| 3311 if (!FLAG_parallel_compaction) return 1; | 3311 if (!FLAG_parallel_compaction) return 1; |
| 3312 // We cap the number of parallel compaction tasks by | 3312 // We cap the number of parallel compaction tasks by |
| 3313 // - a hard limit | |
| 3313 // - (#cores - 1) | 3314 // - (#cores - 1) |
| 3314 // - a value depending on the live memory in evacuation candidates | 3315 // - a target compaction time, considering compaction speed and live memory |
| 3315 // - a hard limit | 3316 const double kTargetCompactionTimeInMs = 2; |
|
Hannes Payer (out of office)
2015/11/03 04:08:17
Let's aim for 1 ms. Keep the constant, it has at l
Michael Lippautz
2015/11/03 20:57:42
Done.
I also restructured the bottom part (return
| |
| 3316 // | |
| 3317 // TODO(mlippautz): Instead of basing the limit on live memory, we could also | |
| 3318 // compute the number from the time it takes to evacuate memory and a given | |
| 3319 // desired time in which compaction should be finished. | |
| 3320 const int kLiveMemoryPerCompactionTask = 2 * Page::kPageSize; | |
| 3321 const int kMaxCompactionTasks = 8; | 3317 const int kMaxCompactionTasks = 8; |
| 3322 int live_bytes = 0; | 3318 |
| 3319 intptr_t compaction_speed = | |
| 3320 heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); | |
| 3321 if (compaction_speed == 0) return 1; | |
| 3322 | |
| 3323 intptr_t live_bytes = 0; | |
| 3323 for (Page* page : evacuation_candidates_) { | 3324 for (Page* page : evacuation_candidates_) { |
| 3324 live_bytes += page->LiveBytes(); | 3325 live_bytes += page->LiveBytes(); |
| 3325 } | 3326 } |
| 3326 return Min(kMaxCompactionTasks, | 3327 |
| 3327 Min(1 + live_bytes / kLiveMemoryPerCompactionTask, | 3328 return Min( |
| 3328 Max(1, base::SysInfo::NumberOfProcessors() - 1))); | 3329 kMaxCompactionTasks, |
| 3330 Min(1 + static_cast<int>(static_cast<double>(live_bytes) / | |
| 3331 compaction_speed / kTargetCompactionTimeInMs), | |
| 3332 Max(1, base::SysInfo::NumberOfProcessors() - 1))); | |
| 3329 } | 3333 } |
| 3330 | 3334 |
| 3331 | 3335 |
| 3332 void MarkCompactCollector::EvacuatePagesInParallel() { | 3336 void MarkCompactCollector::EvacuatePagesInParallel() { |
| 3333 const int num_pages = evacuation_candidates_.length(); | 3337 const int num_pages = evacuation_candidates_.length(); |
| 3334 if (num_pages == 0) return; | 3338 if (num_pages == 0) return; |
| 3335 | 3339 |
| 3340 // Used for trace summary. | |
| 3341 intptr_t live_bytes = 0; | |
| 3342 intptr_t compaction_speed = 0; | |
| 3343 if (FLAG_trace_fragmentation) { | |
| 3344 for (Page* page : evacuation_candidates_) { | |
| 3345 live_bytes += page->LiveBytes(); | |
| 3346 } | |
| 3347 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); | |
| 3348 } | |
| 3336 const int num_tasks = NumberOfParallelCompactionTasks(); | 3349 const int num_tasks = NumberOfParallelCompactionTasks(); |
| 3337 | 3350 |
| 3351 | |
| 3338 // Set up compaction spaces. | 3352 // Set up compaction spaces. |
| 3339 CompactionSpaceCollection** compaction_spaces_for_tasks = | 3353 CompactionSpaceCollection** compaction_spaces_for_tasks = |
| 3340 new CompactionSpaceCollection*[num_tasks]; | 3354 new CompactionSpaceCollection*[num_tasks]; |
| 3341 for (int i = 0; i < num_tasks; i++) { | 3355 for (int i = 0; i < num_tasks; i++) { |
| 3342 compaction_spaces_for_tasks[i] = new CompactionSpaceCollection(heap()); | 3356 compaction_spaces_for_tasks[i] = new CompactionSpaceCollection(heap()); |
| 3343 } | 3357 } |
| 3344 | 3358 |
| 3345 heap()->old_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, | 3359 heap()->old_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, |
| 3346 num_tasks); | 3360 num_tasks); |
| 3347 heap()->code_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, | 3361 heap()->code_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, |
| 3348 num_tasks); | 3362 num_tasks); |
| 3349 | 3363 |
| 3350 compaction_in_progress_ = true; | 3364 compaction_in_progress_ = true; |
| 3351 // Kick off parallel tasks. | 3365 // Kick off parallel tasks. |
| 3352 for (int i = 1; i < num_tasks; i++) { | 3366 for (int i = 1; i < num_tasks; i++) { |
| 3353 concurrent_compaction_tasks_active_++; | 3367 concurrent_compaction_tasks_active_++; |
| 3354 V8::GetCurrentPlatform()->CallOnBackgroundThread( | 3368 V8::GetCurrentPlatform()->CallOnBackgroundThread( |
| 3355 new CompactionTask(heap(), compaction_spaces_for_tasks[i]), | 3369 new CompactionTask(heap(), compaction_spaces_for_tasks[i]), |
| 3356 v8::Platform::kShortRunningTask); | 3370 v8::Platform::kShortRunningTask); |
| 3357 } | 3371 } |
| 3358 | 3372 |
| 3359 // Contribute in main thread. Counter and signal are in principal not needed. | 3373 // Contribute in main thread. Counter and signal are in principal not needed. |
| 3360 EvacuatePages(compaction_spaces_for_tasks[0], &migration_slots_buffer_); | 3374 EvacuatePages(compaction_spaces_for_tasks[0], &migration_slots_buffer_); |
| 3361 | 3375 |
| 3362 WaitUntilCompactionCompleted(); | 3376 WaitUntilCompactionCompleted(); |
| 3363 | 3377 |
| 3378 double compaction_duration = 0.0; | |
| 3379 intptr_t compacted_memory = 0; | |
| 3364 // Merge back memory (compacted and unused) from compaction spaces. | 3380 // Merge back memory (compacted and unused) from compaction spaces. |
| 3365 for (int i = 0; i < num_tasks; i++) { | 3381 for (int i = 0; i < num_tasks; i++) { |
| 3366 heap()->old_space()->MergeCompactionSpace( | 3382 heap()->old_space()->MergeCompactionSpace( |
| 3367 compaction_spaces_for_tasks[i]->Get(OLD_SPACE)); | 3383 compaction_spaces_for_tasks[i]->Get(OLD_SPACE)); |
| 3368 heap()->code_space()->MergeCompactionSpace( | 3384 heap()->code_space()->MergeCompactionSpace( |
| 3369 compaction_spaces_for_tasks[i]->Get(CODE_SPACE)); | 3385 compaction_spaces_for_tasks[i]->Get(CODE_SPACE)); |
| 3386 compacted_memory += compaction_spaces_for_tasks[i]->bytes_compacted(); | |
| 3387 compaction_duration += compaction_spaces_for_tasks[i]->duration(); | |
| 3370 delete compaction_spaces_for_tasks[i]; | 3388 delete compaction_spaces_for_tasks[i]; |
| 3371 } | 3389 } |
| 3372 delete[] compaction_spaces_for_tasks; | 3390 delete[] compaction_spaces_for_tasks; |
| 3391 heap()->tracer()->AddCompactionEvent(compaction_duration, compacted_memory); | |
| 3373 | 3392 |
| 3374 // Finalize sequentially. | 3393 // Finalize sequentially. |
| 3375 int abandoned_pages = 0; | 3394 int abandoned_pages = 0; |
| 3376 for (int i = 0; i < num_pages; i++) { | 3395 for (int i = 0; i < num_pages; i++) { |
| 3377 Page* p = evacuation_candidates_[i]; | 3396 Page* p = evacuation_candidates_[i]; |
| 3378 switch (p->parallel_compaction_state().Value()) { | 3397 switch (p->parallel_compaction_state().Value()) { |
| 3379 case MemoryChunk::ParallelCompactingState::kCompactingAborted: | 3398 case MemoryChunk::ParallelCompactingState::kCompactingAborted: |
| 3380 // We have partially compacted the page, i.e., some objects may have | 3399 // We have partially compacted the page, i.e., some objects may have |
| 3381 // moved, others are still in place. | 3400 // moved, others are still in place. |
| 3382 // We need to: | 3401 // We need to: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 3403 break; | 3422 break; |
| 3404 default: | 3423 default: |
| 3405 // We should not observe kCompactingInProgress, or kCompactingDone. | 3424 // We should not observe kCompactingInProgress, or kCompactingDone. |
| 3406 UNREACHABLE(); | 3425 UNREACHABLE(); |
| 3407 } | 3426 } |
| 3408 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone); | 3427 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone); |
| 3409 } | 3428 } |
| 3410 if (FLAG_trace_fragmentation) { | 3429 if (FLAG_trace_fragmentation) { |
| 3411 PrintIsolate(isolate(), | 3430 PrintIsolate(isolate(), |
| 3412 "%8.0f ms: compaction: parallel=%d pages=%d aborted=%d " | 3431 "%8.0f ms: compaction: parallel=%d pages=%d aborted=%d " |
| 3413 "tasks=%d cores=%d\n", | 3432 "tasks=%d cores=%d live_bytes=%" V8_PTR_PREFIX |
| 3433 "d compaction_speed=%" V8_PTR_PREFIX "d\n", | |
| 3414 isolate()->time_millis_since_init(), FLAG_parallel_compaction, | 3434 isolate()->time_millis_since_init(), FLAG_parallel_compaction, |
| 3415 num_pages, abandoned_pages, num_tasks, | 3435 num_pages, abandoned_pages, num_tasks, |
| 3416 base::SysInfo::NumberOfProcessors()); | 3436 base::SysInfo::NumberOfProcessors(), live_bytes, |
| 3437 compaction_speed); | |
| 3417 } | 3438 } |
| 3418 } | 3439 } |
| 3419 | 3440 |
| 3420 | 3441 |
| 3421 void MarkCompactCollector::WaitUntilCompactionCompleted() { | 3442 void MarkCompactCollector::WaitUntilCompactionCompleted() { |
| 3422 while (concurrent_compaction_tasks_active_ > 0) { | 3443 while (concurrent_compaction_tasks_active_ > 0) { |
| 3423 pending_compaction_tasks_semaphore_.Wait(); | 3444 pending_compaction_tasks_semaphore_.Wait(); |
| 3424 concurrent_compaction_tasks_active_--; | 3445 concurrent_compaction_tasks_active_--; |
| 3425 } | 3446 } |
| 3426 compaction_in_progress_ = false; | 3447 compaction_in_progress_ = false; |
| 3427 } | 3448 } |
| 3428 | 3449 |
| 3429 | 3450 |
| 3430 void MarkCompactCollector::EvacuatePages( | 3451 void MarkCompactCollector::EvacuatePages( |
| 3431 CompactionSpaceCollection* compaction_spaces, | 3452 CompactionSpaceCollection* compaction_spaces, |
| 3432 SlotsBuffer** evacuation_slots_buffer) { | 3453 SlotsBuffer** evacuation_slots_buffer) { |
| 3433 for (int i = 0; i < evacuation_candidates_.length(); i++) { | 3454 for (int i = 0; i < evacuation_candidates_.length(); i++) { |
| 3434 Page* p = evacuation_candidates_[i]; | 3455 Page* p = evacuation_candidates_[i]; |
| 3435 DCHECK(p->IsEvacuationCandidate() || | 3456 DCHECK(p->IsEvacuationCandidate() || |
| 3436 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); | 3457 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); |
| 3437 DCHECK(static_cast<int>(p->parallel_sweeping_state().Value()) == | 3458 DCHECK(static_cast<int>(p->parallel_sweeping_state().Value()) == |
| 3438 MemoryChunk::kSweepingDone); | 3459 MemoryChunk::kSweepingDone); |
| 3439 if (p->parallel_compaction_state().TrySetValue( | 3460 if (p->parallel_compaction_state().TrySetValue( |
| 3440 MemoryChunk::kCompactingDone, MemoryChunk::kCompactingInProgress)) { | 3461 MemoryChunk::kCompactingDone, MemoryChunk::kCompactingInProgress)) { |
| 3441 if (p->IsEvacuationCandidate()) { | 3462 if (p->IsEvacuationCandidate()) { |
| 3442 DCHECK_EQ(p->parallel_compaction_state().Value(), | 3463 DCHECK_EQ(p->parallel_compaction_state().Value(), |
| 3443 MemoryChunk::kCompactingInProgress); | 3464 MemoryChunk::kCompactingInProgress); |
| 3465 double start = heap_->MonotonicallyIncreasingTimeInMs(); | |
| 3466 intptr_t live_bytes = p->LiveBytes(); | |
|
Hannes Payer (out of office)
2015/11/03 04:08:17
Let's move the time measuring into EvacuateLiveObj
Michael Lippautz
2015/11/03 20:57:42
Done.
| |
| 3444 if (EvacuateLiveObjectsFromPage( | 3467 if (EvacuateLiveObjectsFromPage( |
| 3445 p, compaction_spaces->Get(p->owner()->identity()), | 3468 p, compaction_spaces->Get(p->owner()->identity()), |
| 3446 evacuation_slots_buffer)) { | 3469 evacuation_slots_buffer)) { |
| 3447 p->parallel_compaction_state().SetValue( | 3470 p->parallel_compaction_state().SetValue( |
| 3448 MemoryChunk::kCompactingFinalize); | 3471 MemoryChunk::kCompactingFinalize); |
| 3472 compaction_spaces->ReportCompactionProgress( | |
| 3473 heap_->MonotonicallyIncreasingTimeInMs() - start, live_bytes); | |
| 3449 } else { | 3474 } else { |
| 3450 p->parallel_compaction_state().SetValue( | 3475 p->parallel_compaction_state().SetValue( |
| 3451 MemoryChunk::kCompactingAborted); | 3476 MemoryChunk::kCompactingAborted); |
| 3452 } | 3477 } |
| 3453 } else { | 3478 } else { |
| 3454 // There could be popular pages in the list of evacuation candidates | 3479 // There could be popular pages in the list of evacuation candidates |
| 3455 // which we do compact. | 3480 // which we do compact. |
| 3456 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone); | 3481 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone); |
| 3457 } | 3482 } |
| 3458 } | 3483 } |
| (...skipping 1141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4600 MarkBit mark_bit = Marking::MarkBitFrom(host); | 4625 MarkBit mark_bit = Marking::MarkBitFrom(host); |
| 4601 if (Marking::IsBlack(mark_bit)) { | 4626 if (Marking::IsBlack(mark_bit)) { |
| 4602 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); | 4627 RelocInfo rinfo(pc, RelocInfo::CODE_TARGET, 0, host); |
| 4603 RecordRelocSlot(&rinfo, target); | 4628 RecordRelocSlot(&rinfo, target); |
| 4604 } | 4629 } |
| 4605 } | 4630 } |
| 4606 } | 4631 } |
| 4607 | 4632 |
| 4608 } // namespace internal | 4633 } // namespace internal |
| 4609 } // namespace v8 | 4634 } // namespace v8 |
| OLD | NEW |