Chromium Code Reviews| 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/gc_marker.h" | 8 #include "vm/gc_marker.h" |
| 9 #include "vm/gc_sweeper.h" | 9 #include "vm/gc_sweeper.h" |
| 10 #include "vm/object.h" | 10 #include "vm/object.h" |
| 11 #include "vm/virtual_memory.h" | 11 #include "vm/virtual_memory.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 DEFINE_FLAG(int, heap_growth_space_ratio, 10, | |
| 16 "The desired maximum percentage of free space after GC"); | |
| 17 DEFINE_FLAG(int, heap_growth_time_ratio, 3, | |
| 18 "The desired maximum percentage of time spent in GC"); | |
| 19 DEFINE_FLAG(int, heap_growth_rate, 4, | |
| 20 "The size the heap is grown, in heap pages"); | |
| 21 | |
| 15 HeapPage* HeapPage::Initialize(VirtualMemory* memory, bool is_executable) { | 22 HeapPage* HeapPage::Initialize(VirtualMemory* memory, bool is_executable) { |
| 16 ASSERT(memory->size() > VirtualMemory::PageSize()); | 23 ASSERT(memory->size() > VirtualMemory::PageSize()); |
| 17 memory->Commit(is_executable); | 24 memory->Commit(is_executable); |
| 18 | 25 |
| 19 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); | 26 HeapPage* result = reinterpret_cast<HeapPage*>(memory->address()); |
| 20 result->memory_ = memory; | 27 result->memory_ = memory; |
| 21 result->next_ = NULL; | 28 result->next_ = NULL; |
| 22 result->used_ = 0; | 29 result->used_ = 0; |
| 23 result->top_ = result->first_object_start(); | 30 result->top_ = result->first_object_start(); |
| 24 return result; | 31 return result; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 heap_(heap), | 76 heap_(heap), |
| 70 pages_(NULL), | 77 pages_(NULL), |
| 71 pages_tail_(NULL), | 78 pages_tail_(NULL), |
| 72 large_pages_(NULL), | 79 large_pages_(NULL), |
| 73 bump_page_(NULL), | 80 bump_page_(NULL), |
| 74 max_capacity_(max_capacity), | 81 max_capacity_(max_capacity), |
| 75 capacity_(0), | 82 capacity_(0), |
| 76 in_use_(0), | 83 in_use_(0), |
| 77 count_(0), | 84 count_(0), |
| 78 is_executable_(is_executable), | 85 is_executable_(is_executable), |
| 79 sweeping_(false) { } | 86 sweeping_(false), |
| 87 page_space_controller_(FLAG_heap_growth_space_ratio, | |
| 88 FLAG_heap_growth_rate, | |
| 89 FLAG_heap_growth_time_ratio) { | |
| 90 } | |
| 80 | 91 |
| 81 | 92 |
| 82 PageSpace::~PageSpace() { | 93 PageSpace::~PageSpace() { |
| 83 FreePages(pages_); | 94 FreePages(pages_); |
| 84 FreePages(large_pages_); | 95 FreePages(large_pages_); |
| 85 } | 96 } |
| 86 | 97 |
| 87 | 98 |
| 88 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { | 99 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { |
| 89 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), | 100 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 | 191 |
| 181 | 192 |
| 182 uword PageSpace::TryAllocate(intptr_t size) { | 193 uword PageSpace::TryAllocate(intptr_t size) { |
| 183 ASSERT(size >= kObjectAlignment); | 194 ASSERT(size >= kObjectAlignment); |
| 184 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 195 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 185 uword result = 0; | 196 uword result = 0; |
| 186 if (size < kAllocatablePageSize) { | 197 if (size < kAllocatablePageSize) { |
| 187 result = TryBumpAllocate(size); | 198 result = TryBumpAllocate(size); |
| 188 if (result == 0) { | 199 if (result == 0) { |
| 189 result = freelist_.TryAllocate(size); | 200 result = freelist_.TryAllocate(size); |
| 190 if ((result == 0) && CanIncreaseCapacity(kPageSize)) { | 201 if ((result == 0) && |
| 202 page_space_controller_.CanGrowPageSpace(kPageSize) && | |
|
Ivan Posva
2012/05/30 20:21:24
Number of pages or byte size?
cshapiro
2012/05/30 23:39:54
Byte size. Done.
| |
| 203 CanIncreaseCapacity(kPageSize)) { | |
| 191 AllocatePage(); | 204 AllocatePage(); |
| 192 result = TryBumpAllocate(size); | 205 result = TryBumpAllocate(size); |
| 193 ASSERT(result != 0); | 206 ASSERT(result != 0); |
| 194 } | 207 } |
| 195 } | 208 } |
| 196 } else { | 209 } else { |
| 197 // Large page allocation. | 210 // Large page allocation. |
| 198 intptr_t page_size = LargePageSizeFor(size); | 211 intptr_t page_size = LargePageSizeFor(size); |
| 199 if (page_size < size) { | 212 if (page_size < size) { |
| 200 // On overflow we fail to allocate. | 213 // On overflow we fail to allocate. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 NoHandleScope no_handles(isolate); | 294 NoHandleScope no_handles(isolate); |
| 282 | 295 |
| 283 if (FLAG_verify_before_gc) { | 296 if (FLAG_verify_before_gc) { |
| 284 OS::PrintErr("Verifying before MarkSweep... "); | 297 OS::PrintErr("Verifying before MarkSweep... "); |
| 285 heap_->Verify(); | 298 heap_->Verify(); |
| 286 OS::PrintErr(" done.\n"); | 299 OS::PrintErr(" done.\n"); |
| 287 } | 300 } |
| 288 | 301 |
| 289 Timer timer(FLAG_verbose_gc, "MarkSweep"); | 302 Timer timer(FLAG_verbose_gc, "MarkSweep"); |
| 290 timer.Start(); | 303 timer.Start(); |
| 304 int64_t start = OS::GetCurrentTimeMillis(); | |
| 291 | 305 |
| 292 // Mark all reachable old-gen objects. | 306 // Mark all reachable old-gen objects. |
| 293 GCMarker marker(heap_); | 307 GCMarker marker(heap_); |
| 294 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 308 marker.MarkObjects(isolate, this, invoke_api_callbacks); |
| 295 | 309 |
| 296 // Reset the bump allocation page to unused. | 310 // Reset the bump allocation page to unused. |
| 297 bump_page_ = NULL; | 311 bump_page_ = NULL; |
| 298 // Reset the freelists and setup sweeping. | 312 // Reset the freelists and setup sweeping. |
| 299 freelist_.Reset(); | 313 freelist_.Reset(); |
| 300 GCSweeper sweeper(heap_); | 314 GCSweeper sweeper(heap_); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 328 } | 342 } |
| 329 // Advance to the next page. | 343 // Advance to the next page. |
| 330 page = next_page; | 344 page = next_page; |
| 331 } | 345 } |
| 332 | 346 |
| 333 // Record data and print if requested. | 347 // Record data and print if requested. |
| 334 intptr_t in_use_before = in_use_; | 348 intptr_t in_use_before = in_use_; |
| 335 in_use_ = in_use; | 349 in_use_ = in_use; |
| 336 | 350 |
| 337 timer.Stop(); | 351 timer.Stop(); |
| 352 | |
| 353 // Record signals for growth control. | |
| 354 int64_t elapsed = timer.TotalElapsedTime() * kMicrosecondsPerMillisecond; | |
|
Ivan Posva
2012/05/30 20:21:24
As discussed this will only work if --verbose_gc i
cshapiro
2012/05/30 23:39:54
Made unconditional. Done.
| |
| 355 page_space_controller_.EvaluateGarbageCollection(in_use_before, in_use, | |
| 356 start, start + elapsed); | |
| 357 | |
| 338 if (FLAG_verbose_gc) { | 358 if (FLAG_verbose_gc) { |
| 339 const intptr_t KB2 = KB / 2; | 359 const intptr_t KB2 = KB / 2; |
| 340 OS::PrintErr("Mark-Sweep[%d]: %lldus (%dK -> %dK, %dK)\n", | 360 OS::PrintErr("Mark-Sweep[%d]: %lldus (%dK -> %dK, %dK)\n", |
| 341 count_, | 361 count_, |
| 342 timer.TotalElapsedTime(), | 362 timer.TotalElapsedTime(), |
| 343 (in_use_before + (KB2)) / KB, | 363 (in_use_before + (KB2)) / KB, |
| 344 (in_use + (KB2)) / KB, | 364 (in_use + (KB2)) / KB, |
| 345 (capacity_ + KB2) / KB); | 365 (capacity_ + KB2) / KB); |
| 346 } | 366 } |
| 347 | 367 |
| 348 if (FLAG_verify_after_gc) { | 368 if (FLAG_verify_after_gc) { |
| 349 OS::PrintErr("Verifying after MarkSweep... "); | 369 OS::PrintErr("Verifying after MarkSweep... "); |
| 350 heap_->Verify(); | 370 heap_->Verify(); |
| 351 OS::PrintErr(" done.\n"); | 371 OS::PrintErr(" done.\n"); |
| 352 } | 372 } |
| 353 | 373 |
| 354 count_++; | 374 count_++; |
| 355 // Done, reset the marker. | 375 // Done, reset the marker. |
| 356 ASSERT(sweeping_); | 376 ASSERT(sweeping_); |
| 357 sweeping_ = false; | 377 sweeping_ = false; |
| 358 } | 378 } |
| 359 | 379 |
| 380 | |
| 381 PageSpaceController::PageSpaceController(int heap_growth_ratio, | |
| 382 int heap_growth_rate, | |
| 383 int garbage_collection_time_ratio) | |
| 384 : grow_heap_(heap_growth_rate), | |
| 385 heap_growth_ratio_(heap_growth_ratio), | |
| 386 heap_growth_rate_(heap_growth_rate), | |
| 387 garbage_collection_time_ratio_(garbage_collection_time_ratio) { | |
| 388 } | |
| 389 | |
| 390 | |
| 391 PageSpaceController::~PageSpaceController() {} | |
| 392 | |
| 393 | |
| 394 bool PageSpaceController::CanGrowPageSpace(intptr_t num_pages) { | |
|
Ivan Posva
2012/05/30 20:21:24
num_pages or byte size?
cshapiro
2012/05/30 23:39:54
Done.
| |
| 395 if (is_disabled_) { | |
| 396 return true; | |
| 397 } | |
| 398 if (heap_growth_ratio_ == 100) { | |
| 399 return true; | |
| 400 } | |
| 401 if (grow_heap_ <= 0) { | |
| 402 return false; | |
| 403 } | |
| 404 grow_heap_ -= num_pages; | |
| 405 return true; | |
| 406 } | |
| 407 | |
| 408 | |
| 409 void PageSpaceController::EvaluateGarbageCollection( | |
| 410 size_t in_use_before, size_t in_use_after, int64_t start, int64_t end) { | |
| 411 ASSERT(in_use_before >= in_use_after); | |
| 412 ASSERT(end >= start); | |
| 413 history_.AddGarbageCollectionTime(start, end); | |
| 414 int collected_garbage_ratio = | |
| 415 static_cast<int>((static_cast<double>(in_use_before - in_use_after) / | |
| 416 static_cast<double>(in_use_before)) * 100); | |
| 417 if ((collected_garbage_ratio > heap_growth_ratio_) && | |
| 418 (history_.GarbageCollectionTimeFraction() < | |
| 419 garbage_collection_time_ratio_)) { | |
| 420 grow_heap_ = 0; | |
| 421 } else { | |
| 422 grow_heap_ = heap_growth_rate_; | |
| 423 } | |
| 424 } | |
| 425 | |
| 426 | |
| 427 PageSpaceGarbageCollectionHistory::PageSpaceGarbageCollectionHistory() | |
| 428 : index_(0) { | |
| 429 for (uint32_t i = 0; i < kHistoryLength; i++) { | |
| 430 start_[i] = 0; | |
| 431 end_[i] = 0; | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 | |
| 436 void PageSpaceGarbageCollectionHistory:: | |
| 437 AddGarbageCollectionTime(uint64_t start, uint64_t end) { | |
| 438 int index = index_ % kHistoryLength; | |
| 439 start_[index] = start; | |
| 440 end_[index] = end; | |
| 441 index_++; | |
| 442 } | |
| 443 | |
| 444 | |
| 445 int PageSpaceGarbageCollectionHistory::GarbageCollectionTimeFraction() { | |
| 446 int current; | |
| 447 int previous; | |
| 448 uint64_t gc_time = 0; | |
| 449 uint64_t total_time = 0; | |
| 450 for (uint32_t i = 1; i < kHistoryLength; i++) { | |
| 451 current = (index_ - i) % kHistoryLength; | |
| 452 previous = (index_ - 1 - i) % kHistoryLength; | |
| 453 if (end_[previous] == 0) { | |
| 454 break; | |
| 455 } | |
| 456 // iterate over the circular buffer in reverse order | |
| 457 gc_time += end_[current] - start_[current]; | |
| 458 total_time += end_[current] - end_[previous]; | |
| 459 } | |
| 460 if (total_time == 0) { | |
| 461 return 0; | |
| 462 } else { | |
| 463 return static_cast<int>((static_cast<double>(gc_time) / | |
| 464 static_cast<double>(total_time))*100); | |
| 465 } | |
| 466 } | |
| 467 | |
| 360 } // namespace dart | 468 } // namespace dart |
| OLD | NEW |