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

Unified Diff: src/mark-compact.cc

Issue 9605008: Merge 10601,10602,10616,10625,10647 from the bleeding edge to the 3.8 branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/3.8/
Patch Set: Created 8 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/mark-compact.h ('k') | src/mark-compact-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/mark-compact.cc
===================================================================
--- src/mark-compact.cc (revision 10927)
+++ src/mark-compact.cc (working copy)
@@ -230,17 +230,36 @@
}
-bool MarkCompactCollector::StartCompaction() {
+static void TraceFragmentation(PagedSpace* space) {
+ int number_of_pages = space->CountTotalPages();
+ intptr_t reserved = (number_of_pages * space->AreaSize());
+ intptr_t free = reserved - space->SizeOfObjects();
+ PrintF("[%s]: %d pages, %d (%.1f%%) free\n",
+ AllocationSpaceName(space->identity()),
+ number_of_pages,
+ static_cast<int>(free),
+ static_cast<double>(free) * 100 / reserved);
+}
+
+
+bool MarkCompactCollector::StartCompaction(CompactionMode mode) {
if (!compacting_) {
ASSERT(evacuation_candidates_.length() == 0);
CollectEvacuationCandidates(heap()->old_pointer_space());
CollectEvacuationCandidates(heap()->old_data_space());
- if (FLAG_compact_code_space) {
+ if (mode == NON_INCREMENTAL_COMPACTION) {
CollectEvacuationCandidates(heap()->code_space());
+ } else if (FLAG_trace_fragmentation) {
+ TraceFragmentation(heap()->code_space());
}
+ if (FLAG_trace_fragmentation) {
+ TraceFragmentation(heap()->map_space());
+ TraceFragmentation(heap()->cell_space());
+ }
+
heap()->old_pointer_space()->EvictEvacuationCandidatesFromFreeLists();
heap()->old_data_space()->EvictEvacuationCandidatesFromFreeLists();
heap()->code_space()->EvictEvacuationCandidatesFromFreeLists();
@@ -414,6 +433,66 @@
}
+// Returns zero for pages that have so little fragmentation that it is not
+// worth defragmenting them. Otherwise a positive integer that gives an
+// estimate of fragmentation on an arbitrary scale.
+static int FreeListFragmentation(PagedSpace* space, Page* p) {
+ // If page was not swept then there are no free list items on it.
+ if (!p->WasSwept()) {
+ if (FLAG_trace_fragmentation) {
+ PrintF("%p [%s]: %d bytes live (unswept)\n",
+ reinterpret_cast<void*>(p),
+ AllocationSpaceName(space->identity()),
+ p->LiveBytes());
+ }
+ return 0;
+ }
+
+ FreeList::SizeStats sizes;
+ space->CountFreeListItems(p, &sizes);
+
+ intptr_t ratio;
+ intptr_t ratio_threshold;
+ int area_size = space->AreaSize();
+ if (space->identity() == CODE_SPACE) {
+ ratio = (sizes.medium_size_ * 10 + sizes.large_size_ * 2) * 100 /
+ area_size;
+ ratio_threshold = 10;
+ } else {
+ ratio = (sizes.small_size_ * 5 + sizes.medium_size_) * 100 /
+ area_size;
+ ratio_threshold = 15;
+ }
+
+ if (FLAG_trace_fragmentation) {
+ PrintF("%p [%s]: %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %d (%.2f%%) %s\n",
+ reinterpret_cast<void*>(p),
+ AllocationSpaceName(space->identity()),
+ static_cast<int>(sizes.small_size_),
+ static_cast<double>(sizes.small_size_ * 100) /
+ area_size,
+ static_cast<int>(sizes.medium_size_),
+ static_cast<double>(sizes.medium_size_ * 100) /
+ area_size,
+ static_cast<int>(sizes.large_size_),
+ static_cast<double>(sizes.large_size_ * 100) /
+ area_size,
+ static_cast<int>(sizes.huge_size_),
+ static_cast<double>(sizes.huge_size_ * 100) /
+ area_size,
+ (ratio > ratio_threshold) ? "[fragmented]" : "");
+ }
+
+ if (FLAG_always_compact && sizes.Total() != area_size) {
+ return 1;
+ }
+
+ if (ratio <= ratio_threshold) return 0; // Not fragmented.
+
+ return static_cast<int>(ratio - ratio_threshold);
+}
+
+
void MarkCompactCollector::CollectEvacuationCandidates(PagedSpace* space) {
ASSERT(space->identity() == OLD_POINTER_SPACE ||
space->identity() == OLD_DATA_SPACE ||
@@ -421,7 +500,6 @@
int number_of_pages = space->CountTotalPages();
- PageIterator it(space);
const int kMaxMaxEvacuationCandidates = 1000;
int max_evacuation_candidates = Min(
kMaxMaxEvacuationCandidates,
@@ -444,22 +522,89 @@
Page* page_;
};
+ enum CompactionMode {
+ COMPACT_FREE_LISTS,
+ REDUCE_MEMORY_FOOTPRINT
+ };
+
+ CompactionMode mode = COMPACT_FREE_LISTS;
+
+ intptr_t reserved = number_of_pages * space->AreaSize();
+ intptr_t over_reserved = reserved - space->SizeOfObjects();
+ static const intptr_t kFreenessThreshold = 50;
+
+ if (over_reserved >= 2 * space->AreaSize() &&
+ reduce_memory_footprint_) {
+ mode = REDUCE_MEMORY_FOOTPRINT;
+
+ // We expect that empty pages are easier to compact so slightly bump the
+ // limit.
+ max_evacuation_candidates += 2;
+
+ if (FLAG_trace_fragmentation) {
+ PrintF("Estimated over reserved memory: %.1f MB (setting threshold %d)\n",
+ static_cast<double>(over_reserved) / MB,
+ static_cast<int>(kFreenessThreshold));
+ }
+ }
+
+ intptr_t estimated_release = 0;
+
Candidate candidates[kMaxMaxEvacuationCandidates];
int count = 0;
- if (it.has_next()) it.next(); // Never compact the first page.
int fragmentation = 0;
Candidate* least = NULL;
+
+ PageIterator it(space);
+ if (it.has_next()) it.next(); // Never compact the first page.
+
while (it.has_next()) {
Page* p = it.next();
p->ClearEvacuationCandidate();
+
if (FLAG_stress_compaction) {
int counter = space->heap()->ms_count();
uintptr_t page_number = reinterpret_cast<uintptr_t>(p) >> kPageSizeBits;
if ((counter & 1) == (page_number & 1)) fragmentation = 1;
+ } else if (mode == REDUCE_MEMORY_FOOTPRINT) {
+ // Don't try to release too many pages.
+ if (estimated_release >= ((over_reserved * 3) / 4)) {
+ continue;
+ }
+
+ intptr_t free_bytes = 0;
+
+ if (!p->WasSwept()) {
+ free_bytes = (p->size() - p->LiveBytes());
+ } else {
+ FreeList::SizeStats sizes;
+ space->CountFreeListItems(p, &sizes);
+ free_bytes = sizes.Total();
+ }
+
+ int free_pct = static_cast<int>(free_bytes * 100 / p->area_size());
+
+ if (free_pct >= kFreenessThreshold) {
+ estimated_release += p->area_size() +
+ (p->area_size() - free_bytes);
+ fragmentation = free_pct;
+ } else {
+ fragmentation = 0;
+ }
+
+ if (FLAG_trace_fragmentation) {
+ PrintF("%p [%s]: %d (%.2f%%) free %s\n",
+ reinterpret_cast<void*>(p),
+ AllocationSpaceName(space->identity()),
+ static_cast<int>(free_bytes),
+ static_cast<double>(free_bytes * 100) / p->area_size(),
+ (fragmentation > 0) ? "[fragmented]" : "");
+ }
} else {
- fragmentation = space->Fragmentation(p);
+ fragmentation = FreeListFragmentation(space, p);
}
+
if (fragmentation != 0) {
if (count < max_evacuation_candidates) {
candidates[count++] = Candidate(fragmentation, p);
@@ -479,6 +624,7 @@
}
}
}
+
for (int i = 0; i < count; i++) {
AddEvacuationCandidate(candidates[i].page());
}
@@ -552,7 +698,7 @@
// Don't start compaction if we are in the middle of incremental
// marking cycle. We did not collect any slots.
if (!FLAG_never_compact && !was_marked_incrementally_) {
- StartCompaction();
+ StartCompaction(NON_INCREMENTAL_COMPACTION);
}
PagedSpaces spaces;
@@ -664,6 +810,8 @@
isolate_->heap()->mark_compact_collector()->
RecordCodeEntrySlot(slot, target);
+ RecordSharedFunctionInfoCodeSlot(shared);
+
candidate = next_candidate;
}
@@ -686,12 +834,21 @@
candidate->set_code(lazy_compile);
}
+ RecordSharedFunctionInfoCodeSlot(candidate);
+
candidate = next_candidate;
}
shared_function_info_candidates_head_ = NULL;
}
+ void RecordSharedFunctionInfoCodeSlot(SharedFunctionInfo* shared) {
+ Object** slot = HeapObject::RawField(shared,
+ SharedFunctionInfo::kCodeOffset);
+ isolate_->heap()->mark_compact_collector()->
+ RecordSlot(slot, slot, HeapObject::cast(*slot));
+ }
+
static JSFunction** GetNextCandidateField(JSFunction* candidate) {
return reinterpret_cast<JSFunction**>(
candidate->address() + JSFunction::kCodeEntryOffset);
@@ -1168,6 +1325,16 @@
re->SetDataAtUnchecked(JSRegExp::saved_code_index(is_ascii),
code,
heap);
+
+ // Saving a copy might create a pointer into compaction candidate
+ // that was not observed by marker. This might happen if JSRegExp data
+ // was marked through the compilation cache before marker reached JSRegExp
+ // object.
+ FixedArray* data = FixedArray::cast(re->data());
+ Object** slot = data->data_start() + JSRegExp::saved_code_index(is_ascii);
+ heap->mark_compact_collector()->
+ RecordSlot(slot, slot, code);
+
// Set a number in the 0-255 range to guarantee no smi overflow.
re->SetDataAtUnchecked(JSRegExp::code_index(is_ascii),
Smi::FromInt(heap->sweep_generation() & 0xff),
@@ -3251,6 +3418,8 @@
p->set_scan_on_scavenge(false);
slots_buffer_allocator_.DeallocateChain(p->slots_buffer_address());
p->ClearEvacuationCandidate();
+ p->ResetLiveBytes();
+ space->ReleasePage(p);
}
evacuation_candidates_.Rewind(0);
compacting_ = false;
« 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