[runtime] Refine runtime call stats for IC misses.

Now we are able to distinguish different kind of misses based on which handler/stub did we actually use.

Review-Url: https://codereview.chromium.org/1969733002
Cr-Commit-Position: refs/heads/master@{#36175}
This commit is contained in:
ishell 2016-05-11 05:37:22 -07:00 committed by Commit bot
parent bf90d9a33a
commit 61b49b3c09
5 changed files with 122 additions and 4 deletions

View File

@ -288,6 +288,15 @@ void RuntimeCallStats::Leave(Isolate* isolate, RuntimeCallTimer* timer) {
stats->current_timer_ = timer->Stop();
}
// static
void RuntimeCallStats::CorrectCurrentCounterId(Isolate* isolate,
CounterId counter_id) {
RuntimeCallStats* stats = isolate->counters()->runtime_call_stats();
DCHECK_NOT_NULL(stats->current_timer_);
RuntimeCallCounter* counter = &(stats->*counter_id);
stats->current_timer_->counter_ = counter;
}
void RuntimeCallStats::Print(std::ostream& os) {
RuntimeCallStatEntries entries;
@ -299,6 +308,10 @@ void RuntimeCallStats::Print(std::ostream& os) {
BUILTIN_LIST_C(PRINT_COUNTER)
#undef PRINT_COUNTER
#define PRINT_COUNTER(name) entries.Add(&this->Handler_##name);
FOR_EACH_HANDLER_COUNTER(PRINT_COUNTER)
#undef PRINT_COUNTER
entries.Add(&this->ExternalCallback);
entries.Add(&this->GC);
entries.Add(&this->UnexpectedStubMiss);

View File

@ -501,12 +501,12 @@ class RuntimeCallTimer {
counter_ = counter;
parent_ = parent;
timer_.Start();
counter_->count++;
}
inline RuntimeCallTimer* Stop() {
base::TimeDelta delta = timer_.Elapsed();
timer_.Stop();
counter_->count++;
counter_->time += delta;
if (parent_ != NULL) {
// Adjust parent timer so that it does not include sub timer's time.
@ -520,6 +520,46 @@ class RuntimeCallTimer {
base::ElapsedTimer timer_;
};
#define FOR_EACH_HANDLER_COUNTER(V) \
V(IC_HandlerCacheHit) \
V(KeyedLoadIC_LoadIndexedStringStub) \
V(KeyedLoadIC_LoadIndexedInterceptorStub) \
V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \
V(KeyedLoadIC_LoadFastElementStub) \
V(KeyedLoadIC_LoadDictionaryElementStub) \
V(KeyedLoadIC_PolymorphicElement) \
V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \
V(KeyedStoreIC_StoreFastElementStub) \
V(KeyedStoreIC_StoreElementStub) \
V(KeyedStoreIC_Polymorphic) \
V(LoadIC_FunctionPrototypeStub) \
V(LoadIC_ArrayBufferViewLoadFieldStub) \
V(LoadIC_LoadApiGetterStub) \
V(LoadIC_LoadCallback) \
V(LoadIC_LoadConstant) \
V(LoadIC_LoadConstantStub) \
V(LoadIC_LoadField) \
V(LoadIC_LoadFieldStub) \
V(LoadIC_LoadGlobal) \
V(LoadIC_LoadInterceptor) \
V(LoadIC_LoadNonexistent) \
V(LoadIC_LoadNormal) \
V(LoadIC_LoadScriptContextFieldStub) \
V(LoadIC_LoadViaGetter) \
V(LoadIC_SlowStub) \
V(LoadIC_StringLengthStub) \
V(StoreIC_SlowStub) \
V(StoreIC_StoreCallback) \
V(StoreIC_StoreField) \
V(StoreIC_StoreFieldStub) \
V(StoreIC_StoreGlobal) \
V(StoreIC_StoreGlobalTransition) \
V(StoreIC_StoreInterceptorStub) \
V(StoreIC_StoreNormal) \
V(StoreIC_StoreScriptContextFieldStub) \
V(StoreIC_StoreTransition) \
V(StoreIC_StoreViaSetter)
class RuntimeCallStats {
public:
typedef RuntimeCallCounter RuntimeCallStats::*CounterId;
@ -538,6 +578,10 @@ class RuntimeCallStats {
RuntimeCallCounter Builtin_##name = RuntimeCallCounter(#name);
BUILTIN_LIST_C(CALL_BUILTIN_COUNTER)
#undef CALL_BUILTIN_COUNTER
#define CALL_BUILTIN_COUNTER(name) \
RuntimeCallCounter Handler_##name = RuntimeCallCounter(#name);
FOR_EACH_HANDLER_COUNTER(CALL_BUILTIN_COUNTER)
#undef CALL_BUILTIN_COUNTER
// Starting measuring the time for a function. This will establish the
// connection to the parent counter for properly calculating the own times.
@ -549,6 +593,10 @@ class RuntimeCallStats {
// parent.
static void Leave(Isolate* isolate, RuntimeCallTimer* timer);
// Set counter id for the innermost measurement. It can be used to refine
// event kind when a runtime entry counter is too generic.
static void CorrectCurrentCounterId(Isolate* isolate, CounterId counter_id);
void Reset();
void Print(std::ostream& os);
@ -559,6 +607,17 @@ class RuntimeCallStats {
RuntimeCallTimer* current_timer_ = NULL;
};
#define TRACE_RUNTIME_CALL_STATS(isolate, counter_name) \
do { \
if (FLAG_runtime_call_stats) { \
RuntimeCallStats::CorrectCurrentCounterId( \
isolate, &RuntimeCallStats::counter_name); \
} \
} while (false)
#define TRACE_HANDLER_STATS(isolate, counter_name) \
TRACE_RUNTIME_CALL_STATS(isolate, Handler_##counter_name)
// A RuntimeCallTimerScopes wraps around a RuntimeCallTimer to measure the
// the time of C++ scope.
class RuntimeCallTimerScope {

View File

@ -67,6 +67,7 @@ Handle<Code> NamedLoadHandlerCompiler::ComputeLoadNonexistent(
cache_name, stub_holder_map, Code::LOAD_IC, flag);
if (!handler.is_null()) return handler;
TRACE_HANDLER_STATS(isolate, LoadIC_LoadNonexistent);
NamedLoadHandlerCompiler compiler(isolate, receiver_map, last, flag);
handler = compiler.CompileLoadNonexistent(cache_name);
Map::UpdateCodeCache(stub_holder_map, cache_name, handler);

View File

@ -26,17 +26,22 @@ Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
*receiver_map == isolate->get_initial_js_array_map(elements_kind);
Handle<Code> stub;
if (receiver_map->has_indexed_interceptor()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
stub = LoadIndexedInterceptorStub(isolate).GetCode();
} else if (receiver_map->IsStringMap()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
stub = LoadIndexedStringStub(isolate).GetCode();
} else if (receiver_map->has_sloppy_arguments_elements()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
} else {
DCHECK(receiver_map->has_dictionary_elements());
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
stub = LoadDictionaryElementStub(isolate, LoadICState(extra_ic_state))
.GetCode();
}
@ -126,12 +131,15 @@ Handle<Code> PropertyICCompiler::CompileKeyedStoreMonomorphicHandler(
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
Handle<Code> stub;
if (receiver_map->has_sloppy_arguments_elements()) {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_KeyedStoreSloppyArgumentsStub);
stub = KeyedStoreSloppyArgumentsStub(isolate(), store_mode).GetCode();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind,
store_mode).GetCode();
} else {
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
stub = StoreElementStub(isolate(), elements_kind, store_mode).GetCode();
}
return stub;

View File

@ -631,6 +631,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
}
if (use_ic && LoadScriptContextFieldStub::Accepted(&lookup_result)) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadScriptContextFieldStub);
LoadScriptContextFieldStub stub(isolate(), &lookup_result);
PatchCache(name, stub.GetCode());
}
@ -835,6 +836,7 @@ Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
LoadFieldStub stub(isolate(), index);
return stub.GetCode();
}
@ -946,7 +948,10 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
if (!code.is_null()) {
Handle<Code> handler;
if (maybe_handler_.ToHandle(&handler)) {
if (!handler.is_identical_to(code)) return code;
if (!handler.is_identical_to(code)) {
TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
return code;
}
} else {
// maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
// In MEGAMORPHIC case, check if the handler in the megamorphic stub
@ -955,8 +960,12 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
Code* megamorphic_cached_code =
isolate()->stub_cache()->Get(*lookup->name(), map, code->flags());
if (megamorphic_cached_code != *code) return code;
if (megamorphic_cached_code != *code) {
TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
return code;
}
} else {
TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
return code;
}
}
@ -992,6 +1001,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (receiver->IsStringWrapper() &&
Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
StringLengthStub string_length_stub(isolate());
return string_length_stub.GetCode();
}
@ -1004,6 +1014,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
->map()
->has_non_instance_prototype()) {
Handle<Code> stub;
TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
FunctionPrototypeStub function_prototype_stub(isolate());
return function_prototype_stub.GetCode();
}
@ -1014,6 +1025,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
switch (lookup->state()) {
case LookupIterator::INTERCEPTOR: {
DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
// Perform a lookup behind the interceptor. Copy the LookupIterator since
// the original iterator will be used to fetch the value.
@ -1035,6 +1047,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
}
if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
&object_offset)) {
TRACE_HANDLER_STATS(isolate(), LoadIC_ArrayBufferViewLoadFieldStub);
FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
ArrayBufferViewLoadFieldStub stub(isolate(), index);
return stub.GetCode();
@ -1052,10 +1065,12 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
NamedLoadHandlerCompiler compiler(isolate(), map, holder,
cache_holder);
if (call_optimization.is_simple_api_call()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
int index = lookup->GetAccessorIndex();
return compiler.CompileLoadCallback(lookup->name(),
call_optimization, index);
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
int expected_arguments = Handle<JSFunction>::cast(getter)
->shared()
->internal_formal_parameter_count();
@ -1071,11 +1086,13 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
}
if (!holder->HasFastProperties()) break;
if (receiver_is_holder) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub);
int index = lookup->GetAccessorIndex();
LoadApiGetterStub stub(isolate(), true, index);
return stub.GetCode();
}
if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
NamedLoadHandlerCompiler compiler(isolate(), map, holder,
cache_holder);
return compiler.CompileLoadCallback(lookup->name(), info);
@ -1088,6 +1105,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (lookup->is_dictionary_holder()) {
if (kind() != Code::LOAD_IC) break;
if (holder->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
NamedLoadHandlerCompiler compiler(isolate(), map, holder,
cache_holder);
Handle<PropertyCell> cell = lookup->GetPropertyCell();
@ -1105,6 +1123,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
// property must be found in the object for the stub to be
// applicable.
if (!receiver_is_holder) break;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
return isolate()->builtins()->LoadIC_Normal();
}
@ -1114,6 +1133,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
if (receiver_is_holder) {
return SimpleFieldLoad(field);
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
return compiler.CompileLoadField(lookup->name(), field);
}
@ -1121,16 +1141,18 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
// -------------- Constant properties --------------
DCHECK(lookup->property_details().type() == DATA_CONSTANT);
if (receiver_is_holder) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantStub);
LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
return stub.GetCode();
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
return compiler.CompileLoadConstant(lookup->name(),
lookup->GetConstantIndex());
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
return slow_stub();
break;
case LookupIterator::ACCESS_CHECK:
case LookupIterator::JSPROXY:
case LookupIterator::NOT_FOUND:
@ -1138,6 +1160,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
UNREACHABLE();
}
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
@ -1224,6 +1247,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
}
CodeHandleList handlers(target_receiver_maps.length());
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_PolymorphicElement);
ElementHandlerCompiler compiler(isolate());
compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
@ -1389,6 +1413,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (FLAG_use_ic &&
StoreScriptContextFieldStub::Accepted(&lookup_result)) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
StoreScriptContextFieldStub stub(isolate(), &lookup_result);
PatchCache(name, stub.GetCode());
}
@ -1503,6 +1528,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
auto store_target = lookup->GetStoreTarget();
if (store_target->IsJSGlobalObject()) {
// TODO(dcarney): this currently just deopts. Use the transition cell.
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
auto cell = isolate()->factory()->NewPropertyCell();
cell->set_value(*value);
auto code = PropertyCellStoreHandler(
@ -1519,12 +1545,14 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
}
DCHECK(lookup->IsCacheableTransition());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
return compiler.CompileStoreTransition(transition, lookup->name());
}
case LookupIterator::INTERCEPTOR: {
DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
StoreInterceptorStub stub(isolate());
return stub.GetCode();
}
@ -1553,6 +1581,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
break;
}
if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
return compiler.CompileStoreCallback(receiver, lookup->name(), info,
language_mode());
@ -1567,6 +1596,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
if (call_optimization.is_simple_api_call()) {
if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
return compiler.CompileStoreCallback(receiver, lookup->name(),
call_optimization,
lookup->GetAccessorIndex());
@ -1574,6 +1604,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver");
break;
}
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
int expected_arguments = JSFunction::cast(*setter)
->shared()
->internal_formal_parameter_count();
@ -1587,6 +1618,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::DATA: {
if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
DCHECK(holder.is_identical_to(receiver) ||
receiver->map()->prototype() == *holder);
auto cell = lookup->GetPropertyCell();
@ -1597,6 +1629,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
lookup->name(), cell, updated_type);
return code;
}
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
DCHECK(holder.is_identical_to(receiver));
return isolate()->builtins()->StoreIC_Normal();
}
@ -1610,10 +1643,12 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
use_stub = !field_type->IsClass();
}
if (use_stub) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldStub);
StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
lookup->representation());
return stub.GetCode();
}
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField);
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
return compiler.CompileStoreField(lookup);
}
@ -1630,6 +1665,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::NOT_FOUND:
UNREACHABLE();
}
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
@ -1749,6 +1785,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
}
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_Polymorphic);
MapHandleList transitioned_maps(target_receiver_maps.length());
CodeHandleList handlers(target_receiver_maps.length());
PropertyICCompiler::ComputeKeyedStorePolymorphicHandlers(