OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
223 } | 223 } |
224 #endif | 224 #endif |
225 | 225 |
226 | 226 |
227 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { | 227 void MarkCompactCollector::AddEvacuationCandidate(Page* p) { |
228 p->MarkEvacuationCandidate(); | 228 p->MarkEvacuationCandidate(); |
229 evacuation_candidates_.Add(p); | 229 evacuation_candidates_.Add(p); |
230 } | 230 } |
231 | 231 |
232 | 232 |
233 static void TraceFragmentation(PagedSpace* space) { | |
234 int number_of_pages = space->CountTotalPages(); | |
235 intptr_t reserved = (number_of_pages * Page::kObjectAreaSize); | |
236 intptr_t free = reserved - space->SizeOfObjects(); | |
237 PrintF("[%s]: %d pages, %d (%.1f%%) free\n", | |
238 AllocationSpaceName(space->identity()), | |
239 number_of_pages, | |
240 static_cast<int>(free), | |
241 static_cast<double>(free) * 100 / reserved); | |
242 } | |
243 | |
244 | |
233 bool MarkCompactCollector::StartCompaction() { | 245 bool MarkCompactCollector::StartCompaction() { |
234 if (!compacting_) { | 246 if (!compacting_) { |
235 ASSERT(evacuation_candidates_.length() == 0); | 247 ASSERT(evacuation_candidates_.length() == 0); |
236 | 248 |
237 CollectEvacuationCandidates(heap()->old_pointer_space()); | 249 CollectEvacuationCandidates(heap()->old_pointer_space()); |
238 CollectEvacuationCandidates(heap()->old_data_space()); | 250 CollectEvacuationCandidates(heap()->old_data_space()); |
239 | 251 |
240 if (FLAG_compact_code_space) { | 252 if (FLAG_compact_code_space) { |
241 CollectEvacuationCandidates(heap()->code_space()); | 253 CollectEvacuationCandidates(heap()->code_space()); |
254 } else if (FLAG_trace_fragmentation) { | |
255 TraceFragmentation(heap()->code_space()); | |
256 } | |
257 | |
258 if (FLAG_trace_fragmentation) { | |
259 TraceFragmentation(heap()->map_space()); | |
260 TraceFragmentation(heap()->cell_space()); | |
242 } | 261 } |
243 | 262 |
244 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); | 263 heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists(); |
245 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); | 264 heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists(); |
246 heap()->code_space()->EvictEvacuationCandidatesFromFreeLists(); | 265 heap()->code_space()->EvictEvacuationCandidatesFromFreeLists(); |
247 | 266 |
248 compacting_ = evacuation_candidates_.length() > 0; | 267 compacting_ = evacuation_candidates_.length() > 0; |
249 } | 268 } |
250 | 269 |
251 return compacting_; | 270 return compacting_; |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
407 case CELL_SPACE: return "CELL_SPACE"; | 426 case CELL_SPACE: return "CELL_SPACE"; |
408 case LO_SPACE: return "LO_SPACE"; | 427 case LO_SPACE: return "LO_SPACE"; |
409 default: | 428 default: |
410 UNREACHABLE(); | 429 UNREACHABLE(); |
411 } | 430 } |
412 | 431 |
413 return NULL; | 432 return NULL; |
414 } | 433 } |
415 | 434 |
416 | 435 |
436 // Returns zero for pages that have so little fragmentation that it is not | |
437 // worth defragmenting them. Otherwise a positive integer that gives an | |
438 // estimate of fragmentation on an arbitrary scale. | |
439 static int FreeListFragmentation(PagedSpace* space, Page* p) { | |
440 // If page was not swept then there are no free list items on it. | |
441 if (!p->WasSwept()) { | |
442 if (FLAG_trace_fragmentation) { | |
443 PrintF("%p [%s]: %d bytes live (unswept)\n", | |
444 reinterpret_cast<void*>(p), | |
445 AllocationSpaceName(space->identity()), | |
446 p->LiveBytes()); | |
447 } | |
448 return 0; | |
449 } | |
450 | |
451 FreeList::SizeStats sizes; | |
452 space->CountFreeListItems(p, &sizes); | |
453 | |
454 intptr_t ratio; | |
455 intptr_t ratio_threshold; | |
456 if (space->identity() == CODE_SPACE) { | |
457 ratio = (sizes.medium_size_ * 10 + sizes.large_size_ * 2) * 100 / | |
458 Page::kObjectAreaSize; | |
459 ratio_threshold = 10; | |
460 } else { | |
461 ratio = (sizes.small_size_ * 5 + sizes.medium_size_) * 100 / | |
462 Page::kObjectAreaSize; | |
463 ratio_threshold = 15; | |
464 } | |
465 | |
466 if (FLAG_trace_fragmentation) { | |
467 PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n", | |
468 reinterpret_cast<void*>(p), | |
469 AllocationSpaceName(space->identity()), | |
470 static_cast<int>(sizes.small_size_), | |
471 static_cast<double>(sizes.small_size_ * 100) / | |
472 Page::kObjectAreaSize, | |
473 static_cast<int>(sizes.medium_size_), | |
474 static_cast<double>(sizes.medium_size_ * 100) / | |
475 Page::kObjectAreaSize, | |
476 static_cast<int>(sizes.large_size_), | |
477 static_cast<double>(sizes.large_size_ * 100) / | |
478 Page::kObjectAreaSize, | |
479 static_cast<int>(sizes.huge_size_), | |
480 static_cast<double>(sizes.huge_size_ * 100) / | |
481 Page::kObjectAreaSize, | |
482 (ratio > ratio_threshold) ? "[fragmented]" : ""); | |
483 } | |
484 | |
485 if (FLAG_always_compact && sizes.Total() != Page::kObjectAreaSize) { | |
486 return 1; | |
487 } | |
488 | |
489 if (ratio <= ratio_threshold) return 0; // Not fragmented. | |
490 | |
491 return static_cast<int>(ratio - ratio_threshold); | |
492 } | |
493 | |
494 | |
417 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { | 495 void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) { |
418 ASSERT(space->identity() == OLD_POINTER_SPACE || | 496 ASSERT(space->identity() == OLD_POINTER_SPACE || |
419 space->identity() == OLD_DATA_SPACE || | 497 space->identity() == OLD_DATA_SPACE || |
420 space->identity() == CODE_SPACE); | 498 space->identity() == CODE_SPACE); |
421 | 499 |
422 int number_of_pages = space->CountTotalPages(); | 500 int number_of_pages = space->CountTotalPages(); |
423 | 501 |
424 PageIterator it(space); | |
425 const int kMaxMaxEvacuationCandidates = 1000; | 502 const int kMaxMaxEvacuationCandidates = 1000; |
426 int max_evacuation_candidates = Min( | 503 int max_evacuation_candidates = Min( |
427 kMaxMaxEvacuationCandidates, | 504 kMaxMaxEvacuationCandidates, |
428 static_cast<int>(sqrt(static_cast<double>(number_of_pages / 2)) + 1)); | 505 static_cast<int>(sqrt(static_cast<double>(number_of_pages / 2)) + 1)); |
429 | 506 |
430 if (FLAG_stress_compaction || FLAG_always_compact) { | 507 if (FLAG_stress_compaction || FLAG_always_compact) { |
431 max_evacuation_candidates = kMaxMaxEvacuationCandidates; | 508 max_evacuation_candidates = kMaxMaxEvacuationCandidates; |
432 } | 509 } |
433 | 510 |
434 class Candidate { | 511 class Candidate { |
435 public: | 512 public: |
436 Candidate() : fragmentation_(0), page_(NULL) { } | 513 Candidate() : fragmentation_(0), page_(NULL) { } |
437 Candidate(int f, Page* p) : fragmentation_(f), page_(p) { } | 514 Candidate(int f, Page* p) : fragmentation_(f), page_(p) { } |
438 | 515 |
439 int fragmentation() { return fragmentation_; } | 516 int fragmentation() { return fragmentation_; } |
440 Page* page() { return page_; } | 517 Page* page() { return page_; } |
441 | 518 |
442 private: | 519 private: |
443 int fragmentation_; | 520 int fragmentation_; |
444 Page* page_; | 521 Page* page_; |
445 }; | 522 }; |
446 | 523 |
524 enum CompactionMode { | |
525 COMPACT_FREE_LISTS, | |
526 REDUCE_MEMORY_FOOTPRINT | |
527 }; | |
528 | |
529 CompactionMode mode = COMPACT_FREE_LISTS; | |
530 | |
531 intptr_t reserved = number_of_pages * Page::kObjectAreaSize; | |
532 intptr_t over_reserved = reserved - space->SizeOfObjects(); | |
533 static const intptr_t kFreenessThreshold = 50; | |
534 | |
535 if (over_reserved >= 2 * Page::kObjectAreaSize && | |
536 reduce_memory_footprint_) { | |
537 mode = REDUCE_MEMORY_FOOTPRINT; | |
538 max_evacuation_candidates = (over_reserved / Page::kObjectAreaSize) / 2; | |
539 | |
540 if (FLAG_trace_fragmentation) { | |
541 PrintF("Estimated over reserved memory: %.1f MB (setting threshold %d)\n", | |
542 static_cast<double>(over_reserved) / MB, | |
543 kFreenessThreshold); | |
544 } | |
545 } | |
546 | |
547 intptr_t estimated_release = 0; | |
548 | |
447 Candidate candidates[kMaxMaxEvacuationCandidates]; | 549 Candidate candidates[kMaxMaxEvacuationCandidates]; |
448 | 550 |
449 int count = 0; | 551 int count = 0; |
450 if (it.has_next()) it.next(); // Never compact the first page. | |
451 int fragmentation = 0; | 552 int fragmentation = 0; |
452 Candidate* least = NULL; | 553 Candidate* least = NULL; |
554 | |
555 PageIterator it(space); | |
556 if (it.has_next()) it.next(); // Never compact the first page. | |
557 | |
453 while (it.has_next()) { | 558 while (it.has_next()) { |
454 Page* p = it.next(); | 559 Page* p = it.next(); |
455 p->ClearEvacuationCandidate(); | 560 p->ClearEvacuationCandidate(); |
561 | |
456 if (FLAG_stress_compaction) { | 562 if (FLAG_stress_compaction) { |
457 int counter = space->heap()->ms_count(); | 563 int counter = space->heap()->ms_count(); |
458 uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits; | 564 uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits; |
459 if ((counter & 1) == (page_number & 1)) fragmentation = 1; | 565 if ((counter & 1) == (page_number & 1)) fragmentation = 1; |
566 } else if (mode == REDUCE_MEMORY_FOOTPRINT) { | |
567 // Don't try to release too many pages. | |
568 if (estimated_release >= ((over_reserved * 3) / 4)) { | |
569 continue; | |
570 } | |
571 | |
572 intptr_t free_bytes = 0; | |
573 | |
574 if (!p->WasSwept()) { | |
575 free_bytes = (Page::kObjectAreaSize - p->LiveBytes()); | |
576 } else { | |
577 FreeList::SizeStats sizes; | |
578 space->CountFreeListItems(p, &sizes); | |
Erik Corry
2012/02/03 10:12:39
This call worries me. It can potentially take a l
| |
579 free_bytes = sizes.Total(); | |
580 } | |
581 | |
582 int free_pct = static_cast<int>(free_bytes * 100 / Page::kObjectAreaSize); | |
583 | |
584 if (free_pct >= kFreenessThreshold) { | |
585 estimated_release += Page::kObjectAreaSize + | |
586 (Page::kObjectAreaSize - free_bytes); | |
587 fragmentation = free_pct; | |
588 } else { | |
589 fragmentation = 0; | |
590 } | |
591 | |
592 if (FLAG_trace_fragmentation) { | |
593 PrintF("%p [%s]: %d (%.2f%%) free %s\n", | |
594 reinterpret_cast<void*>(p), | |
595 AllocationSpaceName(space->identity()), | |
596 free_bytes, | |
597 static_cast<double>(free_bytes * 100) / Page::kObjectAreaSize, | |
598 (fragmentation > 0) ? "[fragmented]" : ""); | |
599 } | |
460 } else { | 600 } else { |
461 fragmentation = space->Fragmentation(p); | 601 fragmentation = FreeListFragmentation(space, p); |
462 } | 602 } |
603 | |
463 if (fragmentation != 0) { | 604 if (fragmentation != 0) { |
464 if (count < max_evacuation_candidates) { | 605 if (count < max_evacuation_candidates) { |
465 candidates[count++] = Candidate(fragmentation, p); | 606 candidates[count++] = Candidate(fragmentation, p); |
466 } else { | 607 } else { |
467 if (least == NULL) { | 608 if (least == NULL) { |
468 for (int i = 0; i < max_evacuation_candidates; i++) { | 609 for (int i = 0; i < max_evacuation_candidates; i++) { |
469 if (least == NULL || | 610 if (least == NULL || |
470 candidates[i].fragmentation() < least->fragmentation()) { | 611 candidates[i].fragmentation() < least->fragmentation()) { |
471 least = candidates + i; | 612 least = candidates + i; |
472 } | 613 } |
473 } | 614 } |
474 } | 615 } |
475 if (least->fragmentation() < fragmentation) { | 616 if (least->fragmentation() < fragmentation) { |
476 *least = Candidate(fragmentation, p); | 617 *least = Candidate(fragmentation, p); |
477 least = NULL; | 618 least = NULL; |
478 } | 619 } |
479 } | 620 } |
480 } | 621 } |
481 } | 622 } |
623 | |
482 for (int i = 0; i < count; i++) { | 624 for (int i = 0; i < count; i++) { |
483 AddEvacuationCandidate(candidates[i].page()); | 625 AddEvacuationCandidate(candidates[i].page()); |
484 } | 626 } |
485 | 627 |
486 if (count > 0 && FLAG_trace_fragmentation) { | 628 if (count > 0 && FLAG_trace_fragmentation) { |
487 PrintF("Collected %d evacuation candidates for space %s\n", | 629 PrintF("Collected %d evacuation candidates for space %s\n", |
488 count, | 630 count, |
489 AllocationSpaceName(space->identity())); | 631 AllocationSpaceName(space->identity())); |
490 } | 632 } |
491 } | 633 } |
(...skipping 2743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3235 slots_buffer_allocator_.DeallocateChain(&migration_slots_buffer_); | 3377 slots_buffer_allocator_.DeallocateChain(&migration_slots_buffer_); |
3236 ASSERT(migration_slots_buffer_ == NULL); | 3378 ASSERT(migration_slots_buffer_ == NULL); |
3237 for (int i = 0; i < npages; i++) { | 3379 for (int i = 0; i < npages; i++) { |
3238 Page* p = evacuation_candidates_[i]; | 3380 Page* p = evacuation_candidates_[i]; |
3239 if (!p->IsEvacuationCandidate()) continue; | 3381 if (!p->IsEvacuationCandidate()) continue; |
3240 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); | 3382 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); |
3241 space->Free(p->ObjectAreaStart(), Page::kObjectAreaSize); | 3383 space->Free(p->ObjectAreaStart(), Page::kObjectAreaSize); |
3242 p->set_scan_on_scavenge(false); | 3384 p->set_scan_on_scavenge(false); |
3243 slots_buffer_allocator_.DeallocateChain(p->slots_buffer_address()); | 3385 slots_buffer_allocator_.DeallocateChain(p->slots_buffer_address()); |
3244 p->ClearEvacuationCandidate(); | 3386 p->ClearEvacuationCandidate(); |
3387 p->ResetLiveBytes(); | |
3388 space->ReleasePage(p); | |
3245 } | 3389 } |
3246 evacuation_candidates_.Rewind(0); | 3390 evacuation_candidates_.Rewind(0); |
3247 compacting_ = false; | 3391 compacting_ = false; |
3248 } | 3392 } |
3249 | 3393 |
3250 | 3394 |
3251 static const int kStartTableEntriesPerLine = 5; | 3395 static const int kStartTableEntriesPerLine = 5; |
3252 static const int kStartTableLines = 171; | 3396 static const int kStartTableLines = 171; |
3253 static const int kStartTableInvalidLine = 127; | 3397 static const int kStartTableInvalidLine = 127; |
3254 static const int kStartTableUnusedEntry = 126; | 3398 static const int kStartTableUnusedEntry = 126; |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3939 while (buffer != NULL) { | 4083 while (buffer != NULL) { |
3940 SlotsBuffer* next_buffer = buffer->next(); | 4084 SlotsBuffer* next_buffer = buffer->next(); |
3941 DeallocateBuffer(buffer); | 4085 DeallocateBuffer(buffer); |
3942 buffer = next_buffer; | 4086 buffer = next_buffer; |
3943 } | 4087 } |
3944 *buffer_address = NULL; | 4088 *buffer_address = NULL; |
3945 } | 4089 } |
3946 | 4090 |
3947 | 4091 |
3948 } } // namespace v8::internal | 4092 } } // namespace v8::internal |
OLD | NEW |