Commit b8c3ee40 authored by hpayer@chromium.org's avatar hpayer@chromium.org

Tenure allocation sites only when semi-space is maximum size.

BUG=
R=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/309623007

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21623 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent adeaedf5
......@@ -101,6 +101,7 @@ Heap::Heap()
promotion_rate_(0),
semi_space_copied_object_size_(0),
semi_space_copied_rate_(0),
maximum_size_scavenges_(0),
max_gc_pause_(0.0),
total_gc_time_ms_(0.0),
max_alive_after_gc_(0),
......@@ -438,6 +439,13 @@ void Heap::GarbageCollectionPrologue() {
if (isolate()->concurrent_osr_enabled()) {
isolate()->optimizing_compiler_thread()->AgeBufferedOsrJobs();
}
if (new_space_.IsAtMaximumCapacity()) {
maximum_size_scavenges_++;
} else {
maximum_size_scavenges_ = 0;
}
CheckNewSpaceExpansionCriteria();
}
......@@ -485,12 +493,19 @@ void Heap::ProcessPretenuringFeedback() {
// If the scratchpad overflowed, we have to iterate over the allocation
// sites list.
// TODO(hpayer): We iterate over the whole list of allocation sites when
// we grew to the maximum semi-space size to deopt maybe tenured
// allocation sites. We could hold the maybe tenured allocation sites
// in a seperate data structure if this is a performance problem.
bool use_scratchpad =
allocation_sites_scratchpad_length_ < kAllocationSiteScratchpadSize;
allocation_sites_scratchpad_length_ < kAllocationSiteScratchpadSize &&
new_space_.IsAtMaximumCapacity() &&
maximum_size_scavenges_ == 0;
int i = 0;
Object* list_element = allocation_sites_list();
bool trigger_deoptimization = false;
bool maximum_size_scavenge = MaximumSizeScavenge();
while (use_scratchpad ?
i < allocation_sites_scratchpad_length_ :
list_element->IsAllocationSite()) {
......@@ -500,14 +515,17 @@ void Heap::ProcessPretenuringFeedback() {
allocation_mementos_found += site->memento_found_count();
if (site->memento_found_count() > 0) {
active_allocation_sites++;
if (site->DigestPretenuringFeedback(maximum_size_scavenge)) {
trigger_deoptimization = true;
}
if (site->GetPretenureMode() == TENURED) {
tenure_decisions++;
} else {
dont_tenure_decisions++;
}
allocation_sites++;
}
if (site->DigestPretenuringFeedback()) trigger_deoptimization = true;
if (site->GetPretenureMode() == TENURED) {
tenure_decisions++;
} else {
dont_tenure_decisions++;
}
allocation_sites++;
if (use_scratchpad) {
i++;
} else {
......@@ -1433,8 +1451,6 @@ void Heap::Scavenge() {
// Used for updating survived_since_last_expansion_ at function end.
intptr_t survived_watermark = PromotedSpaceSizeOfObjects();
CheckNewSpaceExpansionCriteria();
SelectScavengingVisitorsTable();
incremental_marking()->PrepareForScavenge();
......
......@@ -1359,6 +1359,10 @@ class Heap {
void DeoptMarkedAllocationSites();
bool MaximumSizeScavenge() {
return maximum_size_scavenges_ > 0;
}
// ObjectStats are kept in two arrays, counts and sizes. Related stats are
// stored in a contiguous linear buffer. Stats groups are stored one after
// another.
......@@ -2019,6 +2023,12 @@ class Heap {
intptr_t semi_space_copied_object_size_;
double semi_space_copied_rate_;
// This is the pretenuring trigger for allocation sites that are in maybe
// tenure state. When we switched to the maximum new space size we deoptimize
// the code that belongs to the allocation site and derive the lifetime
// of the allocation site.
unsigned int maximum_size_scavenges_;
// TODO(hpayer): Allocation site pretenuring may make this method obsolete.
// Re-visit incremental marking heuristics.
bool IsHighSurvivalRate() {
......
......@@ -3030,7 +3030,6 @@ void MarkCompactCollector::EvacuateNewSpace() {
// sweep collection by failing allocations. But since we are already in
// a mark-sweep allocation, there is no sense in trying to trigger one.
AlwaysAllocateScope scope(isolate());
heap()->CheckNewSpaceExpansionCriteria();
NewSpace* new_space = heap()->new_space();
......
......@@ -1577,42 +1577,60 @@ inline void AllocationSite::IncrementMementoCreateCount() {
}
inline bool AllocationSite::DigestPretenuringFeedback() {
bool decision_changed = false;
inline bool AllocationSite::MakePretenureDecision(
PretenureDecision current_decision,
double ratio,
bool maximum_size_scavenge) {
// Here we just allow state transitions from undecided or maybe tenure
// to don't tenure, maybe tenure, or tenure.
if ((current_decision == kUndecided || current_decision == kMaybeTenure)) {
if (ratio >= kPretenureRatio) {
// We just transition into tenure state when the semi-space was at
// maximum capacity.
if (maximum_size_scavenge) {
set_deopt_dependent_code(true);
set_pretenure_decision(kTenure);
// Currently we just need to deopt when we make a state transition to
// tenure.
return true;
}
set_pretenure_decision(kMaybeTenure);
} else {
set_pretenure_decision(kDontTenure);
}
}
return false;
}
inline bool AllocationSite::DigestPretenuringFeedback(
bool maximum_size_scavenge) {
bool deopt = false;
int create_count = memento_create_count();
int found_count = memento_found_count();
bool minimum_mementos_created = create_count >= kPretenureMinimumCreated;
double ratio =
minimum_mementos_created || FLAG_trace_pretenuring_statistics ?
static_cast<double>(found_count) / create_count : 0.0;
PretenureFlag current_mode = GetPretenureMode();
// TODO(hpayer): Add an intermediate state MAYBE_TENURE which collects
// more lifetime feedback for tenuring candidates. In the meantime, we
// just allow transitions from undecided to tenured or not tenured.
if (minimum_mementos_created && pretenure_decision() == kUndecided) {
PretenureDecision result = ratio >= kPretenureRatio
? kTenure
: kDontTenure;
set_pretenure_decision(result);
if (current_mode != GetPretenureMode()) {
decision_changed = true;
set_deopt_dependent_code(true);
}
PretenureDecision current_decision = pretenure_decision();
if (minimum_mementos_created) {
deopt = MakePretenureDecision(
current_decision, ratio, maximum_size_scavenge);
}
if (FLAG_trace_pretenuring_statistics) {
PrintF(
"AllocationSite(%p): (created, found, ratio) (%d, %d, %f) %s => %s\n",
static_cast<void*>(this), create_count, found_count, ratio,
current_mode == TENURED ? "tenured" : "not tenured",
GetPretenureMode() == TENURED ? "tenured" : "not tenured");
PretenureDecisionName(current_decision),
PretenureDecisionName(pretenure_decision()));
}
// Clear feedback calculation fields until the next gc.
set_memento_found_count(0);
set_memento_create_count(0);
return decision_changed;
return deopt;
}
......
......@@ -13303,6 +13303,19 @@ void AllocationSite::AddDependentCompilationInfo(Handle<AllocationSite> site,
}
const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
switch (decision) {
case kUndecided: return "undecided";
case kDontTenure: return "don't tenure";
case kMaybeTenure: return "maybe tenure";
case kTenure: return "tenure";
case kZombie: return "zombie";
default: UNREACHABLE();
}
return NULL;
}
void JSObject::UpdateAllocationSite(Handle<JSObject> object,
ElementsKind to_kind) {
if (!object->IsJSArray()) return;
......
......@@ -8412,11 +8412,14 @@ class AllocationSite: public Struct {
enum PretenureDecision {
kUndecided = 0,
kDontTenure = 1,
kTenure = 2,
kZombie = 3,
kMaybeTenure = 2,
kTenure = 3,
kZombie = 4,
kLastPretenureDecisionValue = kZombie
};
const char* PretenureDecisionName(PretenureDecision decision);
DECL_ACCESSORS(transition_info, Object)
// nested_site threads a list of sites that represent nested literals
// walked in a particular order. So [[1, 2], 1, 2] will have one
......@@ -8438,8 +8441,8 @@ class AllocationSite: public Struct {
class DoNotInlineBit: public BitField<bool, 29, 1> {};
// Bitfields for pretenure_data
class MementoFoundCountBits: public BitField<int, 0, 27> {};
class PretenureDecisionBits: public BitField<PretenureDecision, 27, 2> {};
class MementoFoundCountBits: public BitField<int, 0, 26> {};
class PretenureDecisionBits: public BitField<PretenureDecision, 26, 3> {};
class DeoptDependentCodeBit: public BitField<bool, 29, 1> {};
STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
......@@ -8502,7 +8505,11 @@ class AllocationSite: public Struct {
inline void MarkZombie();
inline bool DigestPretenuringFeedback();
inline bool MakePretenureDecision(PretenureDecision current_decision,
double ratio,
bool maximum_size_scavenge);
inline bool DigestPretenuringFeedback(bool maximum_size_scavenge);
ElementsKind GetElementsKind() {
ASSERT(!SitePointsToLiteral());
......
......@@ -2499,6 +2499,10 @@ class NewSpace : public Space {
return to_space_.MaximumCapacity();
}
bool IsAtMaximumCapacity() {
return Capacity() == MaximumCapacity();
}
// Returns the initial capacity of a semispace.
int InitialCapacity() {
ASSERT(to_space_.InitialCapacity() == from_space_.InitialCapacity());
......
......@@ -2200,6 +2200,11 @@ TEST(OptimizedPretenuringAllocationFolding) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2244,6 +2249,11 @@ TEST(OptimizedPretenuringObjectArrayLiterals) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2279,6 +2289,12 @@ TEST(OptimizedPretenuringMixedInObjectProperties) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2320,6 +2336,11 @@ TEST(OptimizedPretenuringDoubleArrayProperties) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2355,6 +2376,11 @@ TEST(OptimizedPretenuringdoubleArrayLiterals) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2390,6 +2416,11 @@ TEST(OptimizedPretenuringNestedMixedArrayLiterals) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2434,6 +2465,11 @@ TEST(OptimizedPretenuringNestedObjectLiterals) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2478,6 +2514,11 @@ TEST(OptimizedPretenuringNestedDoubleLiterals) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
i::OS::SNPrintF(
source,
......@@ -2530,6 +2571,11 @@ TEST(OptimizedPretenuringConstructorCalls) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
// Call new is doing slack tracking for the first
// JSFunction::kGenerousAllocationCount allocations, and we can't find
......@@ -2576,6 +2622,11 @@ TEST(OptimizedPretenuringCallNew) {
if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
v8::HandleScope scope(CcTest::isolate());
// Grow new space unitl maximum capacity reached.
while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
CcTest::heap()->new_space()->Grow();
}
i::ScopedVector<char> source(1024);
// Call new is doing slack tracking for the first
// JSFunction::kGenerousAllocationCount allocations, and we can't find
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment