Commit 12d815b3 authored by jarin's avatar jarin Committed by Commit bot

[profiler] Web UI: add summary of opts/deopts.

This adds optimization and deoptimization counts to the Web UI. Also, the function timeline
now shows optimization and deoptimization marks.

Review-Url: https://codereview.chromium.org/2753543006
Cr-Commit-Position: refs/heads/master@{#44033}
parent 2ff2a0c6
...@@ -105,7 +105,9 @@ class CodeEventListener { ...@@ -105,7 +105,9 @@ class CodeEventListener {
virtual void CodeMovingGCEvent() = 0; virtual void CodeMovingGCEvent() = 0;
virtual void CodeDisableOptEvent(AbstractCode* code, virtual void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) = 0; SharedFunctionInfo* shared) = 0;
virtual void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) = 0; enum DeoptKind { kSoft, kLazy, kEager };
virtual void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
int fp_to_sp_delta) = 0;
}; };
class CodeEventDispatcher { class CodeEventDispatcher {
...@@ -170,8 +172,9 @@ class CodeEventDispatcher { ...@@ -170,8 +172,9 @@ class CodeEventDispatcher {
void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) { void CodeDisableOptEvent(AbstractCode* code, SharedFunctionInfo* shared) {
CODE_EVENT_DISPATCH(CodeDisableOptEvent(code, shared)); CODE_EVENT_DISPATCH(CodeDisableOptEvent(code, shared));
} }
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) { void CodeDeoptEvent(Code* code, CodeEventListener::DeoptKind kind, Address pc,
CODE_EVENT_DISPATCH(CodeDeoptEvent(code, pc, fp_to_sp_delta)); int fp_to_sp_delta) {
CODE_EVENT_DISPATCH(CodeDeoptEvent(code, kind, pc, fp_to_sp_delta));
} }
#undef CODE_EVENT_DISPATCH #undef CODE_EVENT_DISPATCH
......
...@@ -445,6 +445,24 @@ const char* Deoptimizer::MessageFor(BailoutType type) { ...@@ -445,6 +445,24 @@ const char* Deoptimizer::MessageFor(BailoutType type) {
return NULL; return NULL;
} }
namespace {
CodeEventListener::DeoptKind DeoptKindOfBailoutType(
Deoptimizer::BailoutType bailout_type) {
switch (bailout_type) {
case Deoptimizer::EAGER:
return CodeEventListener::kEager;
case Deoptimizer::SOFT:
return CodeEventListener::kSoft;
case Deoptimizer::LAZY:
return CodeEventListener::kLazy;
}
UNREACHABLE();
return CodeEventListener::kEager;
}
} // namespace
Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
BailoutType type, unsigned bailout_id, Address from, BailoutType type, unsigned bailout_id, Address from,
int fp_to_sp_delta) int fp_to_sp_delta)
...@@ -509,7 +527,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, ...@@ -509,7 +527,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
disallow_heap_allocation_ = new DisallowHeapAllocation(); disallow_heap_allocation_ = new DisallowHeapAllocation();
#endif // DEBUG #endif // DEBUG
if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_)); PROFILE(isolate_,
CodeDeoptEvent(compiled_code_, DeoptKindOfBailoutType(type), from_,
fp_to_sp_delta_));
} }
unsigned size = ComputeInputFrameSize(); unsigned size = ComputeInputFrameSize();
int parameter_count = int parameter_count =
......
...@@ -843,12 +843,41 @@ void Logger::SharedLibraryEvent(const std::string& library_path, ...@@ -843,12 +843,41 @@ void Logger::SharedLibraryEvent(const std::string& library_path,
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
void Logger::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
void Logger::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) { int fp_to_sp_delta) {
if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return; if (!log_->IsEnabled()) return;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds()); int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
msg.Append("code-deopt,%d,%d", since_epoch, code->CodeSize()); msg.Append("code-deopt,%d,%d,", since_epoch, code->CodeSize());
msg.AppendAddress(code->address());
// Deoptimization position.
std::ostringstream deopt_location;
int inlining_id = -1;
int script_offset = -1;
if (info.position.IsKnown()) {
info.position.Print(deopt_location, code);
inlining_id = info.position.InliningId();
script_offset = info.position.ScriptOffset();
} else {
deopt_location << "<unknown>";
}
msg.Append(",%d,%d,", inlining_id, script_offset);
switch (kind) {
case kLazy:
msg.Append("\"lazy\",");
break;
case kSoft:
msg.Append("\"soft\",");
break;
case kEager:
msg.Append("\"eager\",");
break;
}
msg.AppendDoubleQuotedString(deopt_location.str().c_str());
msg.Append(",");
msg.AppendDoubleQuotedString(DeoptimizeReasonToString(info.deopt_reason));
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
...@@ -972,6 +1001,10 @@ void Logger::CallbackEventInternal(const char* prefix, Name* name, ...@@ -972,6 +1001,10 @@ void Logger::CallbackEventInternal(const char* prefix, Name* name,
msg.Append("%s,%s,-2,", msg.Append("%s,%s,-2,",
kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT], kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
kLogEventsNames[CodeEventListener::CALLBACK_TAG]); kLogEventsNames[CodeEventListener::CALLBACK_TAG]);
int timestamp = timer_.IsStarted()
? static_cast<int>(timer_.Elapsed().InMicroseconds())
: -1;
msg.Append("%d,", timestamp);
msg.AppendAddress(entry_point); msg.AppendAddress(entry_point);
if (name->IsString()) { if (name->IsString()) {
std::unique_ptr<char[]> str = std::unique_ptr<char[]> str =
...@@ -1007,23 +1040,31 @@ void Logger::SetterCallbackEvent(Name* name, Address entry_point) { ...@@ -1007,23 +1040,31 @@ void Logger::SetterCallbackEvent(Name* name, Address entry_point) {
CallbackEventInternal("set ", name, entry_point); CallbackEventInternal("set ", name, entry_point);
} }
static void AppendCodeCreateHeader(Log::MessageBuilder* msg, namespace {
void AppendCodeCreateHeader(Log::MessageBuilder* msg,
CodeEventListener::LogEventsAndTags tag, CodeEventListener::LogEventsAndTags tag,
AbstractCode* code) { AbstractCode* code, base::ElapsedTimer* timer) {
DCHECK(msg); DCHECK(msg);
msg->Append("%s,%s,%d,", msg->Append("%s,%s,%d,",
kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT], kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
kLogEventsNames[tag], code->kind()); kLogEventsNames[tag], code->kind());
int timestamp = timer->IsStarted()
? static_cast<int>(timer->Elapsed().InMicroseconds())
: -1;
msg->Append("%d,", timestamp);
msg->AppendAddress(code->address()); msg->AppendAddress(code->address());
msg->Append(",%d,", code->ExecutableSize()); msg->Append(",%d,", code->ExecutableSize());
} }
} // namespace
void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, const char* comment) { AbstractCode* code, const char* comment) {
if (!is_logging_code_events()) return; if (!is_logging_code_events()) return;
if (!FLAG_log_code || !log_->IsEnabled()) return; if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, tag, code); AppendCodeCreateHeader(&msg, tag, code, &timer_);
msg.AppendDoubleQuotedString(comment); msg.AppendDoubleQuotedString(comment);
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
...@@ -1033,7 +1074,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, ...@@ -1033,7 +1074,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
if (!is_logging_code_events()) return; if (!is_logging_code_events()) return;
if (!FLAG_log_code || !log_->IsEnabled()) return; if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, tag, code); AppendCodeCreateHeader(&msg, tag, code, &timer_);
if (name->IsString()) { if (name->IsString()) {
msg.Append('"'); msg.Append('"');
msg.AppendDetailed(String::cast(name), false); msg.AppendDetailed(String::cast(name), false);
...@@ -1055,7 +1096,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, ...@@ -1055,7 +1096,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
} }
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, tag, code); AppendCodeCreateHeader(&msg, tag, code, &timer_);
if (name->IsString()) { if (name->IsString()) {
std::unique_ptr<char[]> str = std::unique_ptr<char[]> str =
String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); String::cast(name)->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
...@@ -1079,7 +1120,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, ...@@ -1079,7 +1120,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
if (!is_logging_code_events()) return; if (!is_logging_code_events()) return;
if (!FLAG_log_code || !log_->IsEnabled()) return; if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, tag, code); AppendCodeCreateHeader(&msg, tag, code, &timer_);
std::unique_ptr<char[]> name = std::unique_ptr<char[]> name =
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
msg.Append("\"%s ", name.get()); msg.Append("\"%s ", name.get());
...@@ -1101,7 +1142,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, ...@@ -1101,7 +1142,7 @@ void Logger::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
if (!is_logging_code_events()) return; if (!is_logging_code_events()) return;
if (!FLAG_log_code || !log_->IsEnabled()) return; if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, tag, code); AppendCodeCreateHeader(&msg, tag, code, &timer_);
msg.Append("\"args_count: %d\"", args_count); msg.Append("\"args_count: %d\"", args_count);
msg.WriteToLogFile(); msg.WriteToLogFile();
} }
...@@ -1130,7 +1171,7 @@ void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) { ...@@ -1130,7 +1171,7 @@ void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
if (!is_logging_code_events()) return; if (!is_logging_code_events()) return;
if (!FLAG_log_code || !log_->IsEnabled()) return; if (!FLAG_log_code || !log_->IsEnabled()) return;
Log::MessageBuilder msg(log_); Log::MessageBuilder msg(log_);
AppendCodeCreateHeader(&msg, CodeEventListener::REG_EXP_TAG, code); AppendCodeCreateHeader(&msg, CodeEventListener::REG_EXP_TAG, code, &timer_);
msg.Append('"'); msg.Append('"');
msg.AppendDetailed(source, false); msg.AppendDetailed(source, false);
msg.Append('"'); msg.Append('"');
......
...@@ -185,7 +185,8 @@ class Logger : public CodeEventListener { ...@@ -185,7 +185,8 @@ class Logger : public CodeEventListener {
void CodeNameEvent(Address addr, int pos, const char* code_name); void CodeNameEvent(Address addr, int pos, const char* code_name);
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta); void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
int fp_to_sp_delta);
void ICEvent(const char* type, bool keyed, const Address pc, int line, void ICEvent(const char* type, bool keyed, const Address pc, int line,
int column, Map* map, Object* key, char old_state, int column, Map* map, Object* key, char old_state,
...@@ -394,7 +395,8 @@ class CodeEventLogger : public CodeEventListener { ...@@ -394,7 +395,8 @@ class CodeEventLogger : public CodeEventListener {
void SetterCallbackEvent(Name* name, Address entry_point) override {} void SetterCallbackEvent(Name* name, Address entry_point) override {}
void SharedFunctionInfoMoveEvent(Address from, Address to) override {} void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
void CodeMovingGCEvent() override {} void CodeMovingGCEvent() override {}
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override {} void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
int fp_to_sp_delta) override {}
private: private:
class NameBuffer; class NameBuffer;
......
...@@ -145,7 +145,7 @@ void ProfilerListener::CodeDisableOptEvent(AbstractCode* code, ...@@ -145,7 +145,7 @@ void ProfilerListener::CodeDisableOptEvent(AbstractCode* code,
DispatchCodeEvent(evt_rec); DispatchCodeEvent(evt_rec);
} }
void ProfilerListener::CodeDeoptEvent(Code* code, Address pc, void ProfilerListener::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
int fp_to_sp_delta) { int fp_to_sp_delta) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
......
...@@ -43,7 +43,8 @@ class ProfilerListener : public CodeEventListener { ...@@ -43,7 +43,8 @@ class ProfilerListener : public CodeEventListener {
void CodeMoveEvent(AbstractCode* from, Address to) override; void CodeMoveEvent(AbstractCode* from, Address to) override;
void CodeDisableOptEvent(AbstractCode* code, void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override; SharedFunctionInfo* shared) override;
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override; void CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
int fp_to_sp_delta) override;
void GetterCallbackEvent(Name* name, Address entry_point) override; void GetterCallbackEvent(Name* name, Address entry_point) override;
void RegExpCodeCreateEvent(AbstractCode* code, String* source) override; void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
void SetterCallbackEvent(Name* name, Address entry_point) override; void SetterCallbackEvent(Name* name, Address entry_point) override;
......
...@@ -376,7 +376,7 @@ TEST(LogCallbacks) { ...@@ -376,7 +376,7 @@ TEST(LogCallbacks) {
ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry); ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry);
#endif #endif
i::EmbeddedVector<char, 100> ref_data; i::EmbeddedVector<char, 100> ref_data;
i::SNPrintF(ref_data, "code-creation,Callback,-2,%p,1,\"method1\"", i::SNPrintF(ref_data, "code-creation,Callback,-2,-1,%p,1,\"method1\"",
static_cast<void*>(ObjMethod1_entry)); static_cast<void*>(ObjMethod1_entry));
CHECK(StrNStr(log.start(), ref_data.start(), log.length())); CHECK(StrNStr(log.start(), ref_data.start(), log.length()));
...@@ -429,7 +429,7 @@ TEST(LogAccessorCallbacks) { ...@@ -429,7 +429,7 @@ TEST(LogAccessorCallbacks) {
#endif #endif
EmbeddedVector<char, 100> prop1_getter_record; EmbeddedVector<char, 100> prop1_getter_record;
i::SNPrintF(prop1_getter_record, i::SNPrintF(prop1_getter_record,
"code-creation,Callback,-2,%p,1,\"get prop1\"", "code-creation,Callback,-2,-1,%p,1,\"get prop1\"",
static_cast<void*>(Prop1Getter_entry)); static_cast<void*>(Prop1Getter_entry));
CHECK(StrNStr(log.start(), prop1_getter_record.start(), log.length())); CHECK(StrNStr(log.start(), prop1_getter_record.start(), log.length()));
...@@ -439,7 +439,7 @@ TEST(LogAccessorCallbacks) { ...@@ -439,7 +439,7 @@ TEST(LogAccessorCallbacks) {
#endif #endif
EmbeddedVector<char, 100> prop1_setter_record; EmbeddedVector<char, 100> prop1_setter_record;
i::SNPrintF(prop1_setter_record, i::SNPrintF(prop1_setter_record,
"code-creation,Callback,-2,%p,1,\"set prop1\"", "code-creation,Callback,-2,-1,%p,1,\"set prop1\"",
static_cast<void*>(Prop1Setter_entry)); static_cast<void*>(Prop1Setter_entry));
CHECK(StrNStr(log.start(), prop1_setter_record.start(), log.length())); CHECK(StrNStr(log.start(), prop1_setter_record.start(), log.length()));
...@@ -449,7 +449,7 @@ TEST(LogAccessorCallbacks) { ...@@ -449,7 +449,7 @@ TEST(LogAccessorCallbacks) {
#endif #endif
EmbeddedVector<char, 100> prop2_getter_record; EmbeddedVector<char, 100> prop2_getter_record;
i::SNPrintF(prop2_getter_record, i::SNPrintF(prop2_getter_record,
"code-creation,Callback,-2,%p,1,\"get prop2\"", "code-creation,Callback,-2,-1,%p,1,\"get prop2\"",
static_cast<void*>(Prop2Getter_entry)); static_cast<void*>(Prop2Getter_entry));
CHECK(StrNStr(log.start(), prop2_getter_record.start(), log.length())); CHECK(StrNStr(log.start(), prop2_getter_record.start(), log.length()));
log.Dispose(); log.Dispose();
......
...@@ -78,9 +78,9 @@ ProfileTestDriver.prototype.addFunctions_ = function() { ...@@ -78,9 +78,9 @@ ProfileTestDriver.prototype.addFunctions_ = function() {
this.profile.addLibrary('lib2', 0x21000, 0x22000); this.profile.addLibrary('lib2', 0x21000, 0x22000);
this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900); this.profile.addStaticCode('lib2-f1', 0x21100, 0x21900);
this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500); this.profile.addStaticCode('lib2-f2', 0x21200, 0x21500);
this.profile.addCode('T', 'F1', 0x50100, 0x100); this.profile.addCode('T', 'F1', 1, 0x50100, 0x100);
this.profile.addCode('T', 'F2', 0x50200, 0x100); this.profile.addCode('T', 'F2', 2, 0x50200, 0x100);
this.profile.addCode('T', 'F3', 0x50400, 0x100); this.profile.addCode('T', 'F3', 3, 0x50400, 0x100);
}; };
......
...@@ -2,9 +2,9 @@ shared-library,"shell",0x08048000,0x081ee000,0 ...@@ -2,9 +2,9 @@ shared-library,"shell",0x08048000,0x081ee000,0
shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000,0 shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000,0
shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000,0 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000,0
profiler,"begin",1 profiler,"begin",1
code-creation,Stub,0,0x424260,348,"CompareStub_GE" code-creation,Stub,0,100,0x424260,348,"CompareStub_GE"
code-creation,LazyCompile,0,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac, code-creation,LazyCompile,0,101,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
code-creation,LazyCompile,0,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50, code-creation,LazyCompile,0,102,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
tick,0x424284,0,0,0x480600,0,0x2aaaa5 tick,0x424284,0,0,0x480600,0,0x2aaaa5
tick,0x42429f,0,0,0x480600,0,0x2aacb4 tick,0x42429f,0,0,0x480600,0,0x2aacb4
tick,0x48063d,0,0,0x2d0f7c,0,0x2aaec6 tick,0x48063d,0,0,0x2d0f7c,0,0x2aaec6
......
...@@ -2,13 +2,13 @@ shared-library,"shell",0x08048000,0x081ee000,0 ...@@ -2,13 +2,13 @@ shared-library,"shell",0x08048000,0x081ee000,0
shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000,0 shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000,0
shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000,0 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000,0
profiler,"begin",1 profiler,"begin",1
code-creation,Stub,0,0xf540a100,474,"CEntryStub" code-creation,Stub,0,100,0xf540a100,474,"CEntryStub"
code-creation,Script,0,0xf541cd80,736,"exp.js" code-creation,Script,0,101,0xf541cd80,736,"exp.js"
code-creation,Stub,0,0xf541d0e0,47,"RuntimeStub_Math_exp" code-creation,Stub,0,102,0xf541d0e0,47,"RuntimeStub_Math_exp"
code-creation,LazyCompile,0,0xf541d120,145,"exp native math.js:41" code-creation,LazyCompile,0,103,0xf541d120,145,"exp native math.js:41"
function-creation,0xf441d280,0xf541d120 function-creation,0xf441d280,0xf541d120
code-creation,LoadIC,0,0xf541d280,117,"j" code-creation,LoadIC,0,104,0xf541d280,117,"j"
code-creation,LoadIC,0,0xf541d360,63,"i" code-creation,LoadIC,0,105,0xf541d360,63,"i"
tick,0x80f82d1,0,0,0,0,0xf541ce5c tick,0x80f82d1,0,0,0,0,0xf541ce5c
tick,0x80f89a1,0,0,0,0,0xf541ce5c tick,0x80f89a1,0,0,0,0,0xf541ce5c
tick,0x8123b5c,0,0,0,0,0xf541d1a1,0xf541ceea tick,0x8123b5c,0,0,0,0,0xf541d1a1,0xf541ceea
......
...@@ -135,7 +135,7 @@ Profile.prototype.addStaticCode = function( ...@@ -135,7 +135,7 @@ Profile.prototype.addStaticCode = function(
* @param {number} size Code entry size. * @param {number} size Code entry size.
*/ */
Profile.prototype.addCode = function( Profile.prototype.addCode = function(
type, name, start, size) { type, name, timestamp, start, size) {
var entry = new Profile.DynamicCodeEntry(size, type, name); var entry = new Profile.DynamicCodeEntry(size, type, name);
this.codeMap_.addCode(start, entry); this.codeMap_.addCode(start, entry);
return entry; return entry;
...@@ -153,7 +153,7 @@ Profile.prototype.addCode = function( ...@@ -153,7 +153,7 @@ Profile.prototype.addCode = function(
* @param {Profile.CodeState} state Optimization state. * @param {Profile.CodeState} state Optimization state.
*/ */
Profile.prototype.addFuncCode = function( Profile.prototype.addFuncCode = function(
type, name, start, size, funcAddr, state) { type, name, timestamp, start, size, funcAddr, state) {
// As code and functions are in the same address space, // As code and functions are in the same address space,
// it is safe to put them in a single code map. // it is safe to put them in a single code map.
var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr); var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
...@@ -192,6 +192,10 @@ Profile.prototype.moveCode = function(from, to) { ...@@ -192,6 +192,10 @@ Profile.prototype.moveCode = function(from, to) {
} }
}; };
Profile.prototype.deoptCode = function(
timestamp, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
};
/** /**
* Reports about deletion of a dynamic code entry. * Reports about deletion of a dynamic code entry.
...@@ -864,18 +868,23 @@ JsonProfile.prototype.addStaticCode = function( ...@@ -864,18 +868,23 @@ JsonProfile.prototype.addStaticCode = function(
}; };
JsonProfile.prototype.addCode = function( JsonProfile.prototype.addCode = function(
kind, name, start, size) { kind, name, timestamp, start, size) {
var entry = new CodeMap.CodeEntry(size, name, 'CODE'); var entry = new CodeMap.CodeEntry(size, name, 'CODE');
this.codeMap_.addCode(start, entry); this.codeMap_.addCode(start, entry);
entry.codeId = this.codeEntries_.length; entry.codeId = this.codeEntries_.length;
this.codeEntries_.push({name : entry.name, type : entry.type, kind : kind}); this.codeEntries_.push({
name : entry.name,
timestamp: timestamp,
type : entry.type,
kind : kind
});
return entry; return entry;
}; };
JsonProfile.prototype.addFuncCode = function( JsonProfile.prototype.addFuncCode = function(
kind, name, start, size, funcAddr, state) { kind, name, timestamp, start, size, funcAddr, state) {
// As code and functions are in the same address space, // As code and functions are in the same address space,
// it is safe to put them in a single code map. // it is safe to put them in a single code map.
var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr); var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
...@@ -921,7 +930,8 @@ JsonProfile.prototype.addFuncCode = function( ...@@ -921,7 +930,8 @@ JsonProfile.prototype.addFuncCode = function(
name : entry.name, name : entry.name,
type : entry.type, type : entry.type,
kind : kind, kind : kind,
func : func.funcId func : func.funcId,
tm : timestamp
}); });
} }
return entry; return entry;
...@@ -935,6 +945,28 @@ JsonProfile.prototype.moveCode = function(from, to) { ...@@ -935,6 +945,28 @@ JsonProfile.prototype.moveCode = function(from, to) {
} }
}; };
JsonProfile.prototype.deoptCode = function(
timestamp, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
let entry = this.codeMap_.findDynamicEntryByStartAddress(code);
if (entry) {
let codeId = entry.codeId;
if (!this.codeEntries_[codeId].deopt) {
// Only add the deopt if there was no deopt before.
// The subsequent deoptimizations should be lazy deopts for
// other on-stack activations.
this.codeEntries_[codeId].deopt = {
tm : timestamp,
inliningId : inliningId,
scriptOffset : scriptOffset,
posText : sourcePositionText,
reason : deoptReasonText,
bailoutType : bailoutType
};
}
}
};
JsonProfile.prototype.deleteCode = function(start) { JsonProfile.prototype.deleteCode = function(start) {
try { try {
this.codeMap_.deleteCode(start); this.codeMap_.deleteCode(start);
......
...@@ -64,10 +64,10 @@ found in the LICENSE file. --> ...@@ -64,10 +64,10 @@ found in the LICENSE file. -->
<br> <br>
<div id="calltree" style="display : none"> <div id="mode-bar" style="display : none">
<div id="mode-bar"> </div>
</div>
<div id="calltree" style="display : none">
<br> <br>
Attribution: Attribution:
<select id="calltree-attribution"> <select id="calltree-attribution">
...@@ -98,6 +98,12 @@ found in the LICENSE file. --> ...@@ -98,6 +98,12 @@ found in the LICENSE file. -->
</table> </table>
</div> </div>
<div id="summary" style="display : none">
</div>
<div id="function-details" style="display : none">
</div>
<p style="font-style:italic;"> <p style="font-style:italic;">
<br> <br>
<br> <br>
......
...@@ -476,3 +476,93 @@ function generateTree( ...@@ -476,3 +476,93 @@ function generateTree(
return tickCount; return tickCount;
} }
function computeOptimizationStats(file,
timeStart = -Infinity, timeEnd = Infinity) {
function newCollection() {
return { count : 0, functions : [], functionTable : [] };
}
function addToCollection(collection, code) {
collection.count++;
let funcData = collection.functionTable[code.func];
if (!funcData) {
funcData = { f : file.functions[code.func], instances : [] };
collection.functionTable[code.func] = funcData;
collection.functions.push(funcData);
}
funcData.instances.push(code);
}
let functionCount = 0;
let optimizedFunctionCount = 0;
let deoptimizedFunctionCount = 0;
let optimizations = newCollection();
let eagerDeoptimizations = newCollection();
let softDeoptimizations = newCollection();
let lazyDeoptimizations = newCollection();
for (let i = 0; i < file.functions.length; i++) {
let f = file.functions[i];
// Skip special SFIs that do not correspond to JS functions.
if (f.codes.length === 0) continue;
if (file.code[f.codes[0]].type !== "JS") continue;
functionCount++;
let optimized = false;
let deoptimized = false;
for (let j = 0; j < f.codes.length; j++) {
let code = file.code[f.codes[j]];
console.assert(code.type === "JS");
if (code.kind === "Opt") {
optimized = true;
if (code.tm >= timeStart && code.tm <= timeEnd) {
addToCollection(optimizations, code);
}
}
if (code.deopt) {
deoptimized = true;
if (code.deopt.tm >= timeStart && code.deopt.tm <= timeEnd) {
switch (code.deopt.bailoutType) {
case "lazy":
addToCollection(lazyDeoptimizations, code);
break;
case "eager":
addToCollection(eagerDeoptimizations, code);
break;
case "soft":
addToCollection(softDeoptimizations, code);
break;
}
}
}
}
if (optimized) {
optimizedFunctionCount++;
}
if (deoptimized) {
deoptimizedFunctionCount++;
}
}
function sortCollection(collection) {
collection.functions.sort(
(a, b) => a.instances.length - b.instances.length);
}
sortCollection(eagerDeoptimizations);
sortCollection(lazyDeoptimizations);
sortCollection(softDeoptimizations);
sortCollection(optimizations);
return {
functionCount,
optimizedFunctionCount,
deoptimizedFunctionCount,
optimizations,
eagerDeoptimizations,
lazyDeoptimizations,
softDeoptimizations,
};
}
This diff is collapsed.
...@@ -88,9 +88,14 @@ function TickProcessor( ...@@ -88,9 +88,14 @@ function TickProcessor(
'shared-library': { parsers: [null, parseInt, parseInt, parseInt], 'shared-library': { parsers: [null, parseInt, parseInt, parseInt],
processor: this.processSharedLibrary }, processor: this.processSharedLibrary },
'code-creation': { 'code-creation': {
parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'], parsers: [null, parseInt, parseInt, parseInt, parseInt,
null, 'var-args'],
processor: this.processCodeCreation }, processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt], 'code-deopt': {
parsers: [parseInt, parseInt, parseInt, parseInt, parseInt,
null, null, null],
processor: this.processCodeDeopt },
'code-move': { parsers: [parseInt, parseInt, ],
processor: this.processCodeMove }, processor: this.processCodeMove },
'code-delete': { parsers: [parseInt], 'code-delete': { parsers: [parseInt],
processor: this.processCodeDelete }, processor: this.processCodeDelete },
...@@ -266,18 +271,26 @@ TickProcessor.prototype.processSharedLibrary = function( ...@@ -266,18 +271,26 @@ TickProcessor.prototype.processSharedLibrary = function(
TickProcessor.prototype.processCodeCreation = function( TickProcessor.prototype.processCodeCreation = function(
type, kind, start, size, name, maybe_func) { type, kind, timestamp, start, size, name, maybe_func) {
name = this.deserializedEntriesNames_[start] || name; name = this.deserializedEntriesNames_[start] || name;
if (maybe_func.length) { if (maybe_func.length) {
var funcAddr = parseInt(maybe_func[0]); var funcAddr = parseInt(maybe_func[0]);
var state = parseState(maybe_func[1]); var state = parseState(maybe_func[1]);
this.profile_.addFuncCode(type, name, start, size, funcAddr, state); this.profile_.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
} else { } else {
this.profile_.addCode(type, name, start, size); this.profile_.addCode(type, name, timestamp, start, size);
} }
}; };
TickProcessor.prototype.processCodeDeopt = function(
timestamp, size, code, inliningId, scriptOffset, bailoutType,
sourcePositionText, deoptReasonText) {
this.profile_.deoptCode(timestamp, code, inliningId, scriptOffset,
bailoutType, sourcePositionText, deoptReasonText);
};
TickProcessor.prototype.processCodeMove = function(from, to) { TickProcessor.prototype.processCodeMove = function(from, to) {
this.profile_.moveCode(from, to); this.profile_.moveCode(from, to);
}; };
......
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