| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/pages.h" | 5 #include "vm/pages.h" |
| 6 | 6 |
| 7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
| 8 #include "vm/compiler_stats.h" | 8 #include "vm/compiler_stats.h" |
| 9 #include "vm/gc_marker.h" | 9 #include "vm/gc_marker.h" |
| 10 #include "vm/gc_sweeper.h" | 10 #include "vm/gc_sweeper.h" |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 | 111 |
| 112 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity) | 112 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity) |
| 113 : freelist_(), | 113 : freelist_(), |
| 114 heap_(heap), | 114 heap_(heap), |
| 115 pages_(NULL), | 115 pages_(NULL), |
| 116 pages_tail_(NULL), | 116 pages_tail_(NULL), |
| 117 large_pages_(NULL), | 117 large_pages_(NULL), |
| 118 max_capacity_(max_capacity), | 118 max_capacity_(max_capacity), |
| 119 capacity_(0), | 119 capacity_(0), |
| 120 in_use_(0), | 120 in_use_(0), |
| 121 count_(0), | |
| 122 sweeping_(false), | 121 sweeping_(false), |
| 123 page_space_controller_(FLAG_heap_growth_space_ratio, | 122 page_space_controller_(FLAG_heap_growth_space_ratio, |
| 124 FLAG_heap_growth_rate, | 123 FLAG_heap_growth_rate, |
| 125 FLAG_heap_growth_time_ratio) { | 124 FLAG_heap_growth_time_ratio) { |
| 126 } | 125 } |
| 127 | 126 |
| 128 | 127 |
| 129 PageSpace::~PageSpace() { | 128 PageSpace::~PageSpace() { |
| 130 FreePages(pages_); | 129 FreePages(pages_); |
| 131 FreePages(large_pages_); | 130 FreePages(large_pages_); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 page = page->next(); | 394 page = page->next(); |
| 396 } | 395 } |
| 397 page = large_pages_; | 396 page = large_pages_; |
| 398 while (page != NULL) { | 397 while (page != NULL) { |
| 399 page->WriteProtect(read_only); | 398 page->WriteProtect(read_only); |
| 400 page = page->next(); | 399 page = page->next(); |
| 401 } | 400 } |
| 402 } | 401 } |
| 403 | 402 |
| 404 | 403 |
| 405 void PageSpace::MarkSweep(bool invoke_api_callbacks, const char* gc_reason) { | 404 void PageSpace::MarkSweep(bool invoke_api_callbacks) { |
| 406 // MarkSweep is not reentrant. Make sure that is the case. | 405 // MarkSweep is not reentrant. Make sure that is the case. |
| 407 ASSERT(!sweeping_); | 406 ASSERT(!sweeping_); |
| 408 sweeping_ = true; | 407 sweeping_ = true; |
| 409 Isolate* isolate = Isolate::Current(); | 408 Isolate* isolate = Isolate::Current(); |
| 410 NoHandleScope no_handles(isolate); | 409 NoHandleScope no_handles(isolate); |
| 411 | 410 |
| 412 if (HeapTrace::is_enabled()) { | 411 if (HeapTrace::is_enabled()) { |
| 413 isolate->heap()->trace()->TraceMarkSweepStart(); | 412 isolate->heap()->trace()->TraceMarkSweepStart(); |
| 414 } | 413 } |
| 415 | 414 |
| 416 if (FLAG_print_free_list_before_gc) { | 415 if (FLAG_print_free_list_before_gc) { |
| 417 OS::Print("Data Freelist (before GC):\n"); | 416 OS::Print("Data Freelist (before GC):\n"); |
| 418 freelist_[HeapPage::kData].Print(); | 417 freelist_[HeapPage::kData].Print(); |
| 419 OS::Print("Executable Freelist (before GC):\n"); | 418 OS::Print("Executable Freelist (before GC):\n"); |
| 420 freelist_[HeapPage::kExecutable].Print(); | 419 freelist_[HeapPage::kExecutable].Print(); |
| 421 } | 420 } |
| 422 | 421 |
| 423 if (FLAG_verify_before_gc) { | 422 if (FLAG_verify_before_gc) { |
| 424 OS::PrintErr("Verifying before MarkSweep..."); | 423 OS::PrintErr("Verifying before MarkSweep..."); |
| 425 heap_->Verify(); | 424 heap_->Verify(); |
| 426 OS::PrintErr(" done.\n"); | 425 OS::PrintErr(" done.\n"); |
| 427 } | 426 } |
| 428 | 427 |
| 429 if (FLAG_verbose_gc) { | 428 int64_t start = OS::GetCurrentTimeMicros(); |
| 430 OS::PrintErr("Start mark sweep for %s collection\n", gc_reason); | |
| 431 } | |
| 432 Timer timer(true, "MarkSweep"); | |
| 433 timer.Start(); | |
| 434 int64_t start = OS::GetCurrentTimeMillis(); | |
| 435 | 429 |
| 436 // Mark all reachable old-gen objects. | 430 // Mark all reachable old-gen objects. |
| 437 GCMarker marker(heap_); | 431 GCMarker marker(heap_); |
| 438 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 432 marker.MarkObjects(isolate, this, invoke_api_callbacks); |
| 439 | 433 |
| 434 int64_t mid1 = OS::GetCurrentTimeMicros(); |
| 435 |
| 440 // Reset the bump allocation page to unused. | 436 // Reset the bump allocation page to unused. |
| 441 // Reset the freelists and setup sweeping. | 437 // Reset the freelists and setup sweeping. |
| 442 freelist_[HeapPage::kData].Reset(); | 438 freelist_[HeapPage::kData].Reset(); |
| 443 freelist_[HeapPage::kExecutable].Reset(); | 439 freelist_[HeapPage::kExecutable].Reset(); |
| 440 |
| 441 int64_t mid2 = OS::GetCurrentTimeMicros(); |
| 442 |
| 444 GCSweeper sweeper(heap_); | 443 GCSweeper sweeper(heap_); |
| 445 intptr_t in_use = 0; | 444 intptr_t in_use = 0; |
| 446 | 445 |
| 447 HeapPage* prev_page = NULL; | 446 HeapPage* prev_page = NULL; |
| 448 HeapPage* page = pages_; | 447 HeapPage* page = pages_; |
| 449 while (page != NULL) { | 448 while (page != NULL) { |
| 450 HeapPage* next_page = page->next(); | 449 HeapPage* next_page = page->next(); |
| 451 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_[page->type()]); | 450 intptr_t page_in_use = sweeper.SweepPage(page, &freelist_[page->type()]); |
| 452 if (page_in_use == 0) { | 451 if (page_in_use == 0) { |
| 453 FreePage(page, prev_page); | 452 FreePage(page, prev_page); |
| 454 } else { | 453 } else { |
| 455 in_use += page_in_use; | 454 in_use += page_in_use; |
| 456 prev_page = page; | 455 prev_page = page; |
| 457 } | 456 } |
| 458 // Advance to the next page. | 457 // Advance to the next page. |
| 459 page = next_page; | 458 page = next_page; |
| 460 } | 459 } |
| 461 | 460 |
| 461 int64_t mid3 = OS::GetCurrentTimeMicros(); |
| 462 |
| 462 prev_page = NULL; | 463 prev_page = NULL; |
| 463 page = large_pages_; | 464 page = large_pages_; |
| 464 while (page != NULL) { | 465 while (page != NULL) { |
| 465 intptr_t page_in_use = sweeper.SweepLargePage(page); | 466 intptr_t page_in_use = sweeper.SweepLargePage(page); |
| 466 HeapPage* next_page = page->next(); | 467 HeapPage* next_page = page->next(); |
| 467 if (page_in_use == 0) { | 468 if (page_in_use == 0) { |
| 468 FreeLargePage(page, prev_page); | 469 FreeLargePage(page, prev_page); |
| 469 } else { | 470 } else { |
| 470 in_use += page_in_use; | 471 in_use += page_in_use; |
| 471 prev_page = page; | 472 prev_page = page; |
| 472 } | 473 } |
| 473 // Advance to the next page. | 474 // Advance to the next page. |
| 474 page = next_page; | 475 page = next_page; |
| 475 } | 476 } |
| 476 | 477 |
| 477 // Record data and print if requested. | 478 // Record data and print if requested. |
| 478 intptr_t in_use_before = in_use_; | 479 intptr_t in_use_before = in_use_; |
| 479 in_use_ = in_use; | 480 in_use_ = in_use; |
| 480 | 481 |
| 481 int64_t end = OS::GetCurrentTimeMillis(); | 482 int64_t end = OS::GetCurrentTimeMicros(); |
| 482 timer.Stop(); | |
| 483 | 483 |
| 484 // Record signals for growth control. | 484 // Record signals for growth control. |
| 485 page_space_controller_.EvaluateGarbageCollection(in_use_before, in_use, | 485 page_space_controller_.EvaluateGarbageCollection(in_use_before, in_use, |
| 486 start, end); | 486 start, end); |
| 487 | 487 |
| 488 if (FLAG_verbose_gc) { | 488 heap_->RecordTime(0, mid1 - start); |
| 489 const intptr_t KB2 = KB / 2; | 489 heap_->RecordTime(1, mid2 - mid1); |
| 490 OS::PrintErr("Mark-Sweep[%d]: %"Pd64"us (%"Pd"K -> %"Pd"K, %"Pd"K)\n", | 490 heap_->RecordTime(2, mid3 - mid2); |
| 491 count_, | 491 heap_->RecordTime(3, end - mid3); |
| 492 timer.TotalElapsedTime(), | |
| 493 (in_use_before + (KB2)) / KB, | |
| 494 (in_use + (KB2)) / KB, | |
| 495 (capacity_ + KB2) / KB); | |
| 496 } | |
| 497 | 492 |
| 498 if (FLAG_print_free_list_after_gc) { | 493 if (FLAG_print_free_list_after_gc) { |
| 499 OS::Print("Data Freelist (after GC):\n"); | 494 OS::Print("Data Freelist (after GC):\n"); |
| 500 freelist_[HeapPage::kData].Print(); | 495 freelist_[HeapPage::kData].Print(); |
| 501 OS::Print("Executable Freelist (after GC):\n"); | 496 OS::Print("Executable Freelist (after GC):\n"); |
| 502 freelist_[HeapPage::kExecutable].Print(); | 497 freelist_[HeapPage::kExecutable].Print(); |
| 503 } | 498 } |
| 504 | 499 |
| 505 if (FLAG_verify_after_gc) { | 500 if (FLAG_verify_after_gc) { |
| 506 OS::PrintErr("Verifying after MarkSweep..."); | 501 OS::PrintErr("Verifying after MarkSweep..."); |
| 507 heap_->Verify(); | 502 heap_->Verify(); |
| 508 OS::PrintErr(" done.\n"); | 503 OS::PrintErr(" done.\n"); |
| 509 } | 504 } |
| 510 | 505 |
| 511 if (HeapTrace::is_enabled()) { | 506 if (HeapTrace::is_enabled()) { |
| 512 isolate->heap()->trace()->TraceMarkSweepFinish(); | 507 isolate->heap()->trace()->TraceMarkSweepFinish(); |
| 513 } | 508 } |
| 514 | 509 |
| 515 count_++; | |
| 516 // Done, reset the marker. | 510 // Done, reset the marker. |
| 517 ASSERT(sweeping_); | 511 ASSERT(sweeping_); |
| 518 sweeping_ = false; | 512 sweeping_ = false; |
| 519 } | 513 } |
| 520 | 514 |
| 521 | 515 |
| 522 PageSpaceController::PageSpaceController(int heap_growth_ratio, | 516 PageSpaceController::PageSpaceController(int heap_growth_ratio, |
| 523 int heap_growth_rate, | 517 int heap_growth_rate, |
| 524 int garbage_collection_time_ratio) | 518 int garbage_collection_time_ratio) |
| 525 : is_enabled_(false), | 519 : is_enabled_(false), |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 int collected_garbage_ratio = | 553 int collected_garbage_ratio = |
| 560 static_cast<int>((static_cast<double>(in_use_before - in_use_after) / | 554 static_cast<int>((static_cast<double>(in_use_before - in_use_after) / |
| 561 static_cast<double>(in_use_before)) | 555 static_cast<double>(in_use_before)) |
| 562 * 100.0); | 556 * 100.0); |
| 563 bool enough_free_space = | 557 bool enough_free_space = |
| 564 (collected_garbage_ratio >= heap_growth_ratio_); | 558 (collected_garbage_ratio >= heap_growth_ratio_); |
| 565 int garbage_collection_time_fraction = | 559 int garbage_collection_time_fraction = |
| 566 history_.GarbageCollectionTimeFraction(); | 560 history_.GarbageCollectionTimeFraction(); |
| 567 bool enough_free_time = | 561 bool enough_free_time = |
| 568 (garbage_collection_time_fraction <= garbage_collection_time_ratio_); | 562 (garbage_collection_time_fraction <= garbage_collection_time_ratio_); |
| 563 |
| 564 Heap* heap = Isolate::Current()->heap(); |
| 569 if (enough_free_space && enough_free_time) { | 565 if (enough_free_space && enough_free_time) { |
| 570 grow_heap_ = 0; | 566 grow_heap_ = 0; |
| 571 } else { | 567 } else { |
| 572 if (FLAG_verbose_gc) { | |
| 573 OS::PrintErr("PageSpaceController: "); | |
| 574 if (!enough_free_space) { | |
| 575 OS::PrintErr("free space %d%% < %d%%", | |
| 576 collected_garbage_ratio, | |
| 577 heap_growth_ratio_); | |
| 578 } | |
| 579 if (!enough_free_space && !enough_free_time) { | |
| 580 OS::PrintErr(", "); | |
| 581 } | |
| 582 if (!enough_free_time) { | |
| 583 OS::PrintErr("garbage collection time %d%% > %d%%", | |
| 584 garbage_collection_time_fraction, | |
| 585 garbage_collection_time_ratio_); | |
| 586 } | |
| 587 OS::PrintErr("\n"); | |
| 588 } | |
| 589 intptr_t growth_target = static_cast<intptr_t>(in_use_after / | 568 intptr_t growth_target = static_cast<intptr_t>(in_use_after / |
| 590 desired_utilization_); | 569 desired_utilization_); |
| 591 intptr_t growth_in_bytes = Utils::RoundUp(growth_target - in_use_after, | 570 intptr_t growth_in_bytes = Utils::RoundUp(growth_target - in_use_after, |
| 592 PageSpace::kPageSize); | 571 PageSpace::kPageSize); |
| 593 int growth_in_pages = growth_in_bytes / PageSpace::kPageSize; | 572 int growth_in_pages = growth_in_bytes / PageSpace::kPageSize; |
| 594 grow_heap_ = Utils::Maximum(growth_in_pages, heap_growth_rate_); | 573 grow_heap_ = Utils::Maximum(growth_in_pages, heap_growth_rate_); |
| 574 heap->RecordData(2, growth_in_pages); |
| 595 } | 575 } |
| 576 heap->RecordData(0, collected_garbage_ratio); |
| 577 heap->RecordData(1, garbage_collection_time_fraction); |
| 578 heap->RecordData(3, grow_heap_); |
| 596 } | 579 } |
| 597 | 580 |
| 598 | 581 |
| 599 PageSpaceGarbageCollectionHistory::PageSpaceGarbageCollectionHistory() | 582 PageSpaceGarbageCollectionHistory::PageSpaceGarbageCollectionHistory() |
| 600 : index_(0) { | 583 : index_(0) { |
| 601 for (intptr_t i = 0; i < kHistoryLength; i++) { | 584 for (intptr_t i = 0; i < kHistoryLength; i++) { |
| 602 start_[i] = 0; | 585 start_[i] = 0; |
| 603 end_[i] = 0; | 586 end_[i] = 0; |
| 604 } | 587 } |
| 605 } | 588 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 633 return 0; | 616 return 0; |
| 634 } else { | 617 } else { |
| 635 ASSERT(total_time >= gc_time); | 618 ASSERT(total_time >= gc_time); |
| 636 int result= static_cast<int>((static_cast<double>(gc_time) / | 619 int result= static_cast<int>((static_cast<double>(gc_time) / |
| 637 static_cast<double>(total_time)) * 100); | 620 static_cast<double>(total_time)) * 100); |
| 638 return result; | 621 return result; |
| 639 } | 622 } |
| 640 } | 623 } |
| 641 | 624 |
| 642 } // namespace dart | 625 } // namespace dart |
| OLD | NEW |