Track number of generic ICs per function

and use it to disable optimization if too many ICs are generic.

R=verwaest@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22887 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 13c6cb72
......@@ -352,6 +352,8 @@ DEFINE_INT(interrupt_budget, 0x1800,
"execution budget before interrupt is triggered")
DEFINE_INT(type_info_threshold, 25,
"percentage of ICs that must have type info to allow optimization")
DEFINE_INT(generic_ic_threshold, 30,
"max percentage of megamorphic/generic ICs to allow optimization")
DEFINE_INT(self_opt_count, 130, "call count before self-optimization")
DEFINE_BOOL(trace_opt_verbose, false, "extra verbose compilation tracing")
......
......@@ -334,13 +334,39 @@ MaybeHandle<Object> IC::ReferenceError(const char* type, Handle<String> name) {
}
static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
bool was_uninitialized =
old_state == UNINITIALIZED || old_state == PREMONOMORPHIC;
bool is_uninitialized =
new_state == UNINITIALIZED || new_state == PREMONOMORPHIC;
return (was_uninitialized && !is_uninitialized) ? 1 :
(!was_uninitialized && is_uninitialized) ? -1 : 0;
static void ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state,
int* polymorphic_delta,
int* generic_delta) {
switch (old_state) {
case UNINITIALIZED:
case PREMONOMORPHIC:
if (new_state == UNINITIALIZED || new_state == PREMONOMORPHIC) break;
if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
*polymorphic_delta = 1;
} else if (new_state == MEGAMORPHIC || new_state == GENERIC) {
*generic_delta = 1;
}
break;
case MONOMORPHIC:
case POLYMORPHIC:
if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) break;
*polymorphic_delta = -1;
if (new_state == MEGAMORPHIC || new_state == GENERIC) {
*generic_delta = 1;
}
break;
case MEGAMORPHIC:
case GENERIC:
if (new_state == MEGAMORPHIC || new_state == GENERIC) break;
*generic_delta = -1;
if (new_state == MONOMORPHIC || new_state == POLYMORPHIC) {
*polymorphic_delta = 1;
}
break;
case PROTOTYPE_FAILURE:
case DEBUG_STUB:
UNREACHABLE();
}
}
......@@ -350,21 +376,20 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) {
inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
if (host->kind() != Code::FUNCTION) return;
if (FLAG_type_info_threshold > 0 &&
old_target->is_inline_cache_stub() &&
target->is_inline_cache_stub()) {
int delta = ComputeTypeInfoCountDelta(old_target->ic_state(),
target->ic_state());
// Call ICs don't have interesting state changes from this point
// of view.
DCHECK(target->kind() != Code::CALL_IC || delta == 0);
// Not all Code objects have TypeFeedbackInfo.
if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) {
TypeFeedbackInfo* info =
TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_ic_with_type_info_count(delta);
}
if (FLAG_type_info_threshold > 0 && old_target->is_inline_cache_stub() &&
target->is_inline_cache_stub() &&
// Call ICs don't have interesting state changes from this point
// of view.
target->kind() != Code::CALL_IC &&
// Not all Code objects have TypeFeedbackInfo.
host->type_feedback_info()->IsTypeFeedbackInfo()) {
int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
int generic_delta = 0; // "Generic" here includes megamorphic.
ComputeTypeInfoCountDelta(old_target->ic_state(), target->ic_state(),
&polymorphic_delta, &generic_delta);
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_ic_with_type_info_count(polymorphic_delta);
info->change_ic_generic_count(generic_delta);
}
if (host->type_feedback_info()->IsTypeFeedbackInfo()) {
TypeFeedbackInfo* info =
......
......@@ -349,6 +349,7 @@ void PolymorphicCodeCache::PolymorphicCodeCacheVerify() {
void TypeFeedbackInfo::TypeFeedbackInfoVerify() {
VerifyObjectField(kStorage1Offset);
VerifyObjectField(kStorage2Offset);
VerifyObjectField(kStorage3Offset);
}
......
......@@ -7071,6 +7071,7 @@ int TypeFeedbackInfo::ic_with_type_info_count() {
void TypeFeedbackInfo::change_ic_with_type_info_count(int delta) {
if (delta == 0) return;
int value = Smi::cast(READ_FIELD(this, kStorage2Offset))->value();
int new_count = ICsWithTypeInfoCountField::decode(value) + delta;
// We can get negative count here when the type-feedback info is
......@@ -7086,9 +7087,25 @@ void TypeFeedbackInfo::change_ic_with_type_info_count(int delta) {
}
int TypeFeedbackInfo::ic_generic_count() {
return Smi::cast(READ_FIELD(this, kStorage3Offset))->value();
}
void TypeFeedbackInfo::change_ic_generic_count(int delta) {
if (delta == 0) return;
int new_count = ic_generic_count() + delta;
if (new_count >= 0) {
new_count &= ~Smi::kMinValue;
WRITE_FIELD(this, kStorage3Offset, Smi::FromInt(new_count));
}
}
void TypeFeedbackInfo::initialize_storage() {
WRITE_FIELD(this, kStorage1Offset, Smi::FromInt(0));
WRITE_FIELD(this, kStorage2Offset, Smi::FromInt(0));
WRITE_FIELD(this, kStorage3Offset, Smi::FromInt(0));
}
......
......@@ -486,7 +486,8 @@ void PolymorphicCodeCache::PolymorphicCodeCachePrint(OStream& os) { // NOLINT
void TypeFeedbackInfo::TypeFeedbackInfoPrint(OStream& os) { // NOLINT
HeapObject::PrintHeader(os, "TypeFeedbackInfo");
os << " - ic_total_count: " << ic_total_count()
<< ", ic_with_type_info_count: " << ic_with_type_info_count() << "\n";
<< ", ic_with_type_info_count: " << ic_with_type_info_count()
<< ", ic_generic_count: " << ic_generic_count() << "\n";
}
......
......@@ -8507,7 +8507,10 @@ class TypeFeedbackInfo: public Struct {
inline void set_ic_total_count(int count);
inline int ic_with_type_info_count();
inline void change_ic_with_type_info_count(int count);
inline void change_ic_with_type_info_count(int delta);
inline int ic_generic_count();
inline void change_ic_generic_count(int delta);
inline void initialize_storage();
......@@ -8526,7 +8529,8 @@ class TypeFeedbackInfo: public Struct {
static const int kStorage1Offset = HeapObject::kHeaderSize;
static const int kStorage2Offset = kStorage1Offset + kPointerSize;
static const int kSize = kStorage2Offset + kPointerSize;
static const int kStorage3Offset = kStorage2Offset + kPointerSize;
static const int kSize = kStorage3Offset + kPointerSize;
// TODO(mvstanton): move these sentinel declarations to shared function info.
// The object that indicates an uninitialized cache.
......
......@@ -57,21 +57,26 @@ RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
}
static void GetICCounts(Code* shared_code,
int* ic_with_type_info_count,
int* ic_total_count,
int* percentage) {
static void GetICCounts(Code* shared_code, int* ic_with_type_info_count,
int* ic_generic_count, int* ic_total_count,
int* type_info_percentage, int* generic_percentage) {
*ic_total_count = 0;
*ic_generic_count = 0;
*ic_with_type_info_count = 0;
Object* raw_info = shared_code->type_feedback_info();
if (raw_info->IsTypeFeedbackInfo()) {
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(raw_info);
*ic_with_type_info_count = info->ic_with_type_info_count();
*ic_generic_count = info->ic_generic_count();
*ic_total_count = info->ic_total_count();
}
*percentage = *ic_total_count > 0
? 100 * *ic_with_type_info_count / *ic_total_count
: 100;
if (*ic_total_count > 0) {
*type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count;
*generic_percentage = 100 * *ic_generic_count / *ic_total_count;
} else {
*type_info_percentage = 100; // Compared against lower bound.
*generic_percentage = 0; // Compared against upper bound.
}
}
......@@ -83,9 +88,12 @@ void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) {
function->ShortPrint();
PrintF(" for recompilation, reason: %s", reason);
if (FLAG_type_info_threshold > 0) {
int typeinfo, total, percentage;
GetICCounts(function->shared()->code(), &typeinfo, &total, &percentage);
PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total, percentage);
int typeinfo, generic, total, type_percentage, generic_percentage;
GetICCounts(function->shared()->code(), &typeinfo, &generic, &total,
&type_percentage, &generic_percentage);
PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total,
type_percentage);
PrintF(", generic ICs: %d/%d (%d%%)", generic, total, generic_percentage);
}
PrintF("]\n");
}
......@@ -227,9 +235,11 @@ void RuntimeProfiler::OptimizeNow() {
int ticks = shared_code->profiler_ticks();
if (ticks >= kProfilerTicksBeforeOptimization) {
int typeinfo, total, percentage;
GetICCounts(shared_code, &typeinfo, &total, &percentage);
if (percentage >= FLAG_type_info_threshold) {
int typeinfo, generic, total, type_percentage, generic_percentage;
GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
&generic_percentage);
if (type_percentage >= FLAG_type_info_threshold &&
generic_percentage <= FLAG_generic_ic_threshold) {
// If this particular function hasn't had any ICs patched for enough
// ticks, optimize it now.
Optimize(function, "hot and stable");
......@@ -240,15 +250,23 @@ void RuntimeProfiler::OptimizeNow() {
if (FLAG_trace_opt_verbose) {
PrintF("[not yet optimizing ");
function->PrintName();
PrintF(", not enough type info: %d/%d (%d%%)]\n",
typeinfo, total, percentage);
PrintF(", not enough type info: %d/%d (%d%%)]\n", typeinfo, total,
type_percentage);
}
}
} else if (!any_ic_changed_ &&
shared_code->instruction_size() < kMaxSizeEarlyOpt) {
// If no IC was patched since the last tick and this function is very
// small, optimistically optimize it now.
Optimize(function, "small function");
int typeinfo, generic, total, type_percentage, generic_percentage;
GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
&generic_percentage);
if (type_percentage >= FLAG_type_info_threshold &&
generic_percentage <= FLAG_generic_ic_threshold) {
Optimize(function, "small function");
} else {
shared_code->set_profiler_ticks(ticks + 1);
}
} else {
shared_code->set_profiler_ticks(ticks + 1);
}
......
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