| 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(size) && |
| 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 sweeping_ = true; | 292 sweeping_ = true; |
| 280 Isolate* isolate = Isolate::Current(); | 293 Isolate* isolate = Isolate::Current(); |
| 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(true, "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; |
| 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 : is_enabled_(false), |
| 385 grow_heap_(heap_growth_rate), |
| 386 heap_growth_ratio_(heap_growth_ratio), |
| 387 heap_growth_rate_(heap_growth_rate), |
| 388 garbage_collection_time_ratio_(garbage_collection_time_ratio) { |
| 389 } |
| 390 |
| 391 |
| 392 PageSpaceController::~PageSpaceController() {} |
| 393 |
| 394 |
| 395 bool PageSpaceController::CanGrowPageSpace(intptr_t size_in_bytes) { |
| 396 size_in_bytes = Utils::RoundUp(size_in_bytes, PageSpace::kPageSize); |
| 397 intptr_t size_in_pages = size_in_bytes / PageSpace::kPageSize; |
| 398 if (!is_enabled_) { |
| 399 return true; |
| 400 } |
| 401 if (heap_growth_ratio_ == 100) { |
| 402 return true; |
| 403 } |
| 404 if (grow_heap_ <= 0) { |
| 405 return false; |
| 406 } |
| 407 grow_heap_ -= size_in_pages; |
| 408 return true; |
| 409 } |
| 410 |
| 411 |
| 412 void PageSpaceController::EvaluateGarbageCollection( |
| 413 size_t in_use_before, size_t in_use_after, int64_t start, int64_t end) { |
| 414 ASSERT(in_use_before >= in_use_after); |
| 415 ASSERT(end >= start); |
| 416 history_.AddGarbageCollectionTime(start, end); |
| 417 int collected_garbage_ratio = |
| 418 static_cast<int>((static_cast<double>(in_use_before - in_use_after) / |
| 419 static_cast<double>(in_use_before)) * 100); |
| 420 if ((collected_garbage_ratio > heap_growth_ratio_) && |
| 421 (history_.GarbageCollectionTimeFraction() < |
| 422 garbage_collection_time_ratio_)) { |
| 423 grow_heap_ = 0; |
| 424 } else { |
| 425 grow_heap_ = heap_growth_rate_; |
| 426 } |
| 427 } |
| 428 |
| 429 |
| 430 PageSpaceGarbageCollectionHistory::PageSpaceGarbageCollectionHistory() |
| 431 : index_(0) { |
| 432 for (uint32_t i = 0; i < kHistoryLength; i++) { |
| 433 start_[i] = 0; |
| 434 end_[i] = 0; |
| 435 } |
| 436 } |
| 437 |
| 438 |
| 439 void PageSpaceGarbageCollectionHistory:: |
| 440 AddGarbageCollectionTime(uint64_t start, uint64_t end) { |
| 441 int index = index_ % kHistoryLength; |
| 442 start_[index] = start; |
| 443 end_[index] = end; |
| 444 index_++; |
| 445 } |
| 446 |
| 447 |
| 448 int PageSpaceGarbageCollectionHistory::GarbageCollectionTimeFraction() { |
| 449 int current; |
| 450 int previous; |
| 451 uint64_t gc_time = 0; |
| 452 uint64_t total_time = 0; |
| 453 for (uint32_t i = 1; i < kHistoryLength; i++) { |
| 454 current = (index_ - i) % kHistoryLength; |
| 455 previous = (index_ - 1 - i) % kHistoryLength; |
| 456 if (end_[previous] == 0) { |
| 457 break; |
| 458 } |
| 459 // iterate over the circular buffer in reverse order |
| 460 gc_time += end_[current] - start_[current]; |
| 461 total_time += end_[current] - end_[previous]; |
| 462 } |
| 463 if (total_time == 0) { |
| 464 return 0; |
| 465 } else { |
| 466 return static_cast<int>((static_cast<double>(gc_time) / |
| 467 static_cast<double>(total_time))*100); |
| 468 } |
| 469 } |
| 470 |
| 360 } // namespace dart | 471 } // namespace dart |
| OLD | NEW |