Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(585)

Side by Side Diff: src/mark-compact.cc

Issue 9323007: Tweak compaction candidate selection to avoid keeping page with low occupancy around. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/mark-compact.h ('k') | src/mark-compact-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/mark-compact.h ('k') | src/mark-compact-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698