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 |