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 // 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 |