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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 57 if (raw_obj->FindObject(visitor)) { | 64 if (raw_obj->FindObject(visitor)) { |
| 58 return raw_obj; // Found object, return it. | 65 return raw_obj; // Found object, return it. |
| 59 } | 66 } |
| 60 obj_addr += raw_obj->Size(); | 67 obj_addr += raw_obj->Size(); |
| 61 } | 68 } |
| 62 ASSERT(obj_addr == end_addr); | 69 ASSERT(obj_addr == end_addr); |
| 63 return Object::null(); | 70 return Object::null(); |
| 64 } | 71 } |
| 65 | 72 |
| 66 | 73 |
| 67 PageSpace::PageSpace(Heap* heap, intptr_t max_capacity, bool is_executable) | 74 PageSpace::PageSpace(Heap* heap, |
| 75 intptr_t max_capacity, | |
| 76 bool is_executable) | |
|
Ivan Posva
2012/05/29 23:27:37
?
cshapiro
2012/05/30 17:56:24
More noise. Done.
| |
| 68 : freelist_(), | 77 : freelist_(), |
| 69 heap_(heap), | 78 heap_(heap), |
| 70 pages_(NULL), | 79 pages_(NULL), |
| 71 pages_tail_(NULL), | 80 pages_tail_(NULL), |
| 72 large_pages_(NULL), | 81 large_pages_(NULL), |
| 73 bump_page_(NULL), | 82 bump_page_(NULL), |
| 74 max_capacity_(max_capacity), | 83 max_capacity_(max_capacity), |
| 75 capacity_(0), | 84 capacity_(0), |
| 76 in_use_(0), | 85 in_use_(0), |
| 77 count_(0), | 86 count_(0), |
| 78 is_executable_(is_executable), | 87 is_executable_(is_executable), |
| 79 sweeping_(false) { } | 88 sweeping_(false), |
| 89 is_growth_controlled_(false), | |
| 90 page_space_controller_(FLAG_heap_growth_space_ratio, | |
| 91 FLAG_heap_growth_rate, | |
| 92 FLAG_heap_growth_time_ratio) { | |
| 93 } | |
| 80 | 94 |
| 81 | 95 |
| 82 PageSpace::~PageSpace() { | 96 PageSpace::~PageSpace() { |
| 83 FreePages(pages_); | 97 FreePages(pages_); |
| 84 FreePages(large_pages_); | 98 FreePages(large_pages_); |
| 85 } | 99 } |
| 86 | 100 |
| 87 | 101 |
| 88 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { | 102 intptr_t PageSpace::LargePageSizeFor(intptr_t size) { |
| 89 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), | 103 intptr_t page_size = Utils::RoundUp(size + sizeof(HeapPage), |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 | 194 |
| 181 | 195 |
| 182 uword PageSpace::TryAllocate(intptr_t size) { | 196 uword PageSpace::TryAllocate(intptr_t size) { |
| 183 ASSERT(size >= kObjectAlignment); | 197 ASSERT(size >= kObjectAlignment); |
| 184 ASSERT(Utils::IsAligned(size, kObjectAlignment)); | 198 ASSERT(Utils::IsAligned(size, kObjectAlignment)); |
| 185 uword result = 0; | 199 uword result = 0; |
| 186 if (size < kAllocatablePageSize) { | 200 if (size < kAllocatablePageSize) { |
| 187 result = TryBumpAllocate(size); | 201 result = TryBumpAllocate(size); |
| 188 if (result == 0) { | 202 if (result == 0) { |
| 189 result = freelist_.TryAllocate(size); | 203 result = freelist_.TryAllocate(size); |
| 190 if ((result == 0) && CanIncreaseCapacity(kPageSize)) { | 204 if ((result == 0) && |
| 205 (is_growth_controlled_ != true || | |
| 206 page_space_controller_.CanGrowPageSpace()) && | |
| 207 CanIncreaseCapacity(kPageSize)) { | |
| 191 AllocatePage(); | 208 AllocatePage(); |
| 192 result = TryBumpAllocate(size); | 209 result = TryBumpAllocate(size); |
| 193 ASSERT(result != 0); | 210 ASSERT(result != 0); |
| 194 } | 211 } |
| 195 } | 212 } |
| 196 } else { | 213 } else { |
| 197 // Large page allocation. | 214 // Large page allocation. |
| 198 intptr_t page_size = LargePageSizeFor(size); | 215 intptr_t page_size = LargePageSizeFor(size); |
| 199 if (page_size < size) { | 216 if (page_size < size) { |
| 200 // On overflow we fail to allocate. | 217 // On overflow we fail to allocate. |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 281 NoHandleScope no_handles(isolate); | 298 NoHandleScope no_handles(isolate); |
| 282 | 299 |
| 283 if (FLAG_verify_before_gc) { | 300 if (FLAG_verify_before_gc) { |
| 284 OS::PrintErr("Verifying before MarkSweep... "); | 301 OS::PrintErr("Verifying before MarkSweep... "); |
| 285 heap_->Verify(); | 302 heap_->Verify(); |
| 286 OS::PrintErr(" done.\n"); | 303 OS::PrintErr(" done.\n"); |
| 287 } | 304 } |
| 288 | 305 |
| 289 Timer timer(FLAG_verbose_gc, "MarkSweep"); | 306 Timer timer(FLAG_verbose_gc, "MarkSweep"); |
| 290 timer.Start(); | 307 timer.Start(); |
| 308 int64_t start = OS::GetCurrentTimeMillis(); | |
| 291 | 309 |
| 292 // Mark all reachable old-gen objects. | 310 // Mark all reachable old-gen objects. |
| 293 GCMarker marker(heap_); | 311 GCMarker marker(heap_); |
| 294 marker.MarkObjects(isolate, this, invoke_api_callbacks); | 312 marker.MarkObjects(isolate, this, invoke_api_callbacks); |
| 295 | 313 |
| 296 // Reset the bump allocation page to unused. | 314 // Reset the bump allocation page to unused. |
| 297 bump_page_ = NULL; | 315 bump_page_ = NULL; |
| 298 // Reset the freelists and setup sweeping. | 316 // Reset the freelists and setup sweeping. |
| 299 freelist_.Reset(); | 317 freelist_.Reset(); |
| 300 GCSweeper sweeper(heap_); | 318 GCSweeper sweeper(heap_); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 324 FreeLargePage(page, prev_page); | 342 FreeLargePage(page, prev_page); |
| 325 } else { | 343 } else { |
| 326 in_use += page_in_use; | 344 in_use += page_in_use; |
| 327 prev_page = page; | 345 prev_page = page; |
| 328 } | 346 } |
| 329 // Advance to the next page. | 347 // Advance to the next page. |
| 330 page = next_page; | 348 page = next_page; |
| 331 } | 349 } |
| 332 | 350 |
| 333 // Record data and print if requested. | 351 // Record data and print if requested. |
| 352 int64_t end = OS::GetCurrentTimeMillis(); | |
|
Ivan Posva
2012/05/29 23:27:37
Why not use the timer object?
cshapiro
2012/05/30 17:56:24
Okay. The timer does not directly provide this da
| |
| 334 intptr_t in_use_before = in_use_; | 353 intptr_t in_use_before = in_use_; |
| 354 page_space_controller_.EvaluateGarbageCollection(in_use_before, in_use, | |
| 355 start, end); | |
| 335 in_use_ = in_use; | 356 in_use_ = in_use; |
| 336 | 357 |
| 337 timer.Stop(); | 358 timer.Stop(); |
| 338 if (FLAG_verbose_gc) { | 359 if (FLAG_verbose_gc) { |
| 339 const intptr_t KB2 = KB / 2; | 360 const intptr_t KB2 = KB / 2; |
| 340 OS::PrintErr("Mark-Sweep[%d]: %lldus (%dK -> %dK, %dK)\n", | 361 OS::PrintErr("Mark-Sweep[%d]: %lldus (%dK -> %dK, %dK)\n", |
| 341 count_, | 362 count_, |
| 342 timer.TotalElapsedTime(), | 363 timer.TotalElapsedTime(), |
| 343 (in_use_before + (KB2)) / KB, | 364 (in_use_before + (KB2)) / KB, |
| 344 (in_use + (KB2)) / KB, | 365 (in_use + (KB2)) / KB, |
| 345 (capacity_ + KB2) / KB); | 366 (capacity_ + KB2) / KB); |
| 346 } | 367 } |
| 347 | 368 |
| 348 if (FLAG_verify_after_gc) { | 369 if (FLAG_verify_after_gc) { |
| 349 OS::PrintErr("Verifying after MarkSweep... "); | 370 OS::PrintErr("Verifying after MarkSweep... "); |
| 350 heap_->Verify(); | 371 heap_->Verify(); |
| 351 OS::PrintErr(" done.\n"); | 372 OS::PrintErr(" done.\n"); |
| 352 } | 373 } |
| 353 | 374 |
| 354 count_++; | 375 count_++; |
| 355 // Done, reset the marker. | 376 // Done, reset the marker. |
| 356 ASSERT(sweeping_); | 377 ASSERT(sweeping_); |
| 357 sweeping_ = false; | 378 sweeping_ = false; |
| 358 } | 379 } |
| 359 | 380 |
| 381 | |
| 382 PageSpaceController::PageSpaceController(int heap_growth_ratio, | |
| 383 int heap_growth_rate, | |
| 384 int garbage_collection_time_ratio) | |
| 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() { | |
| 396 if (heap_growth_ratio_ == 100) { | |
|
Ivan Posva
2012/05/29 23:27:37
For debugging we might want to add a always_grow_t
cshapiro
2012/05/30 17:56:24
Or, I could suppress the enabling of the controlle
| |
| 397 return true; | |
| 398 } | |
| 399 if (grow_heap_ == 0) { | |
|
Ivan Posva
2012/05/29 23:27:37
<= 0
cshapiro
2012/05/30 17:56:24
Done.
| |
| 400 return false; | |
| 401 } | |
| 402 grow_heap_ -= 1; | |
| 403 return true; | |
| 404 } | |
| 405 | |
| 406 | |
| 407 void PageSpaceController::EvaluateGarbageCollection( | |
| 408 size_t in_use_before, size_t in_use_after, int64_t start, int64_t end) { | |
| 409 ASSERT(in_use_before >= in_use_after); | |
| 410 ASSERT(end >= start); | |
| 411 history_.AddGarbageCollectionTime(start, end); | |
| 412 int collected_garbage_ratio = | |
| 413 static_cast<int>((static_cast<double>(in_use_before - in_use_after) / | |
| 414 static_cast<double>(in_use_before)) * 100); | |
| 415 if ((collected_garbage_ratio > heap_growth_ratio_) && | |
| 416 (history_.GarbageCollectionTimeFraction() < | |
| 417 garbage_collection_time_ratio_)) { | |
| 418 grow_heap_ = 0; | |
| 419 } else { | |
| 420 grow_heap_ = heap_growth_rate_; | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 | |
| 425 PageSpaceGarbageCollectionHistory::PageSpaceGarbageCollectionHistory() | |
| 426 : index_(0) { | |
| 427 for (uint32_t i = 0; i < kHistoryLength; i++) { | |
| 428 start_[i] = 0; | |
| 429 end_[i] = 0; | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 | |
| 434 void PageSpaceGarbageCollectionHistory:: | |
| 435 AddGarbageCollectionTime(uint64_t start, uint64_t end) { | |
| 436 int index = index_ % kHistoryLength; | |
| 437 start_[index] = start; | |
| 438 end_[index] = end; | |
| 439 index_++; | |
| 440 } | |
| 441 | |
| 442 | |
| 443 int PageSpaceGarbageCollectionHistory::GarbageCollectionTimeFraction() { | |
| 444 int current; | |
| 445 int previous; | |
| 446 uint64_t gc_time = 0; | |
| 447 uint64_t total_time = 0; | |
| 448 for (uint32_t i = 1; i < kHistoryLength; i++) { | |
| 449 current = (index_ - i) % kHistoryLength; | |
| 450 previous = (index_ - 1 - i) % kHistoryLength; | |
| 451 if (end_[previous] == 0) { | |
| 452 break; | |
| 453 } | |
| 454 // iterate over the circular buffer in reverse order | |
| 455 gc_time += end_[current] - start_[current]; | |
| 456 total_time += end_[current] - end_[previous]; | |
| 457 } | |
| 458 if (total_time == 0) { | |
| 459 return 0; | |
| 460 } else { | |
| 461 return static_cast<int>((static_cast<double>(gc_time) / | |
| 462 static_cast<double>(total_time))*100); | |
| 463 } | |
| 464 } | |
| 465 | |
| 360 } // namespace dart | 466 } // namespace dart |
| OLD | NEW |