[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}
This commit is contained in:
parent
2ff2a0c65d
commit
12d815b36e
@ -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 {
|
|||||||
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) {
|
|||||||
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,
|
|||||||
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 =
|
||||||
|
67
src/log.cc
67
src/log.cc
@ -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,
|
|||||||
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) {
|
|||||||
CallbackEventInternal("set ", name, entry_point);
|
CallbackEventInternal("set ", name, entry_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AppendCodeCreateHeader(Log::MessageBuilder* msg,
|
namespace {
|
||||||
CodeEventListener::LogEventsAndTags tag,
|
|
||||||
AbstractCode* code) {
|
void AppendCodeCreateHeader(Log::MessageBuilder* msg,
|
||||||
|
CodeEventListener::LogEventsAndTags tag,
|
||||||
|
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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) {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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,
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
#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) {
|
|||||||
#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) {
|
|||||||
#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() {
|
|||||||
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
|
|||||||
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
|
|||||||
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(
|
|||||||
* @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(
|
|||||||
* @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) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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(
|
|||||||
};
|
};
|
||||||
|
|
||||||
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(
|
|||||||
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) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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. -->
|
|||||||
|
|
||||||
<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. -->
|
|||||||
</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(
|
|||||||
|
|
||||||
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -14,34 +14,17 @@ function createViews() {
|
|||||||
components.push(new CallTreeView());
|
components.push(new CallTreeView());
|
||||||
components.push(new TimelineView());
|
components.push(new TimelineView());
|
||||||
components.push(new HelpView());
|
components.push(new HelpView());
|
||||||
|
components.push(new SummaryView());
|
||||||
|
components.push(new ModeBarView());
|
||||||
|
|
||||||
let modeBar = $("mode-bar");
|
main.setMode("summary");
|
||||||
|
|
||||||
function addMode(id, text, active) {
|
|
||||||
let div = document.createElement("div");
|
|
||||||
div.classList = "mode-button" + (active ? " active-mode-button" : "");
|
|
||||||
div.id = "mode-" + id;
|
|
||||||
div.textContent = text;
|
|
||||||
div.onclick = () => {
|
|
||||||
if (main.currentState.callTree.mode === id) return;
|
|
||||||
let old = $("mode-" + main.currentState.callTree.mode);
|
|
||||||
old.classList = "mode-button";
|
|
||||||
div.classList = "mode-button active-mode-button";
|
|
||||||
main.setMode(id);
|
|
||||||
};
|
|
||||||
modeBar.appendChild(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
addMode("bottom-up", "Bottom up", true);
|
|
||||||
addMode("top-down", "Top down");
|
|
||||||
addMode("function-list", "Functions");
|
|
||||||
|
|
||||||
main.setMode("bottom-up");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function emptyState() {
|
function emptyState() {
|
||||||
return {
|
return {
|
||||||
file : null,
|
file : null,
|
||||||
|
mode : "none",
|
||||||
|
currentCodeId : null,
|
||||||
start : 0,
|
start : 0,
|
||||||
end : Infinity,
|
end : Infinity,
|
||||||
timeLine : {
|
timeLine : {
|
||||||
@ -49,7 +32,6 @@ function emptyState() {
|
|||||||
height : 100
|
height : 100
|
||||||
},
|
},
|
||||||
callTree : {
|
callTree : {
|
||||||
mode : "none",
|
|
||||||
attribution : "js-exclude-bc",
|
attribution : "js-exclude-bc",
|
||||||
categories : "code-type",
|
categories : "code-type",
|
||||||
sort : "time"
|
sort : "time"
|
||||||
@ -68,28 +50,35 @@ let main = {
|
|||||||
|
|
||||||
setMode(mode) {
|
setMode(mode) {
|
||||||
if (mode != main.currentState.mode) {
|
if (mode != main.currentState.mode) {
|
||||||
let callTreeState = Object.assign({}, main.currentState.callTree);
|
|
||||||
callTreeState.mode = mode;
|
function setCallTreeModifiers(attribution, categories, sort) {
|
||||||
|
let callTreeState = Object.assign({}, main.currentState.callTree);
|
||||||
|
callTreeState.attribution = attribution;
|
||||||
|
callTreeState.categories = categories;
|
||||||
|
callTreeState.sort = sort;
|
||||||
|
return callTreeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = Object.assign({}, main.currentState);
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case "bottom-up":
|
case "bottom-up":
|
||||||
callTreeState.attribution = "js-exclude-bc";
|
state.callTree =
|
||||||
callTreeState.categories = "code-type";
|
setCallTreeModifiers("js-exclude-bc", "code-type", "time");
|
||||||
callTreeState.sort = "time";
|
|
||||||
break;
|
break;
|
||||||
case "top-down":
|
case "top-down":
|
||||||
callTreeState.attribution = "js-exclude-bc";
|
state.callTree =
|
||||||
callTreeState.categories = "none";
|
setCallTreeModifiers("js-exclude-bc", "none", "time");
|
||||||
callTreeState.sort = "time";
|
|
||||||
break;
|
break;
|
||||||
case "function-list":
|
case "function-list":
|
||||||
callTreeState.attribution = "js-exclude-bc";
|
state.callTree =
|
||||||
callTreeState.categories = "code-type";
|
setCallTreeModifiers("js-exclude-bc", "code-type", "own-time");
|
||||||
callTreeState.sort = "own-time";
|
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
console.error("Invalid mode");
|
|
||||||
}
|
}
|
||||||
main.currentState = setCallTreeState(main.currentState, callTreeState);
|
|
||||||
|
state.mode = mode;
|
||||||
|
|
||||||
|
main.currentState = state;
|
||||||
main.delayRender();
|
main.delayRender();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -201,12 +190,12 @@ let main = {
|
|||||||
|
|
||||||
let bucketDescriptors =
|
let bucketDescriptors =
|
||||||
[ { kinds : [ "JSOPT" ],
|
[ { kinds : [ "JSOPT" ],
|
||||||
color : "#ffb000",
|
|
||||||
backgroundColor : "#ffe0c0",
|
|
||||||
text : "JS Optimized" },
|
|
||||||
{ kinds : [ "JSUNOPT", "BC" ],
|
|
||||||
color : "#00ff00",
|
color : "#00ff00",
|
||||||
backgroundColor : "#c0ffc0",
|
backgroundColor : "#c0ffc0",
|
||||||
|
text : "JS Optimized" },
|
||||||
|
{ kinds : [ "JSUNOPT", "BC" ],
|
||||||
|
color : "#ffb000",
|
||||||
|
backgroundColor : "#ffe0c0",
|
||||||
text : "JS Unoptimized" },
|
text : "JS Unoptimized" },
|
||||||
{ kinds : [ "IC" ],
|
{ kinds : [ "IC" ],
|
||||||
color : "#ffff00",
|
color : "#ffff00",
|
||||||
@ -325,6 +314,27 @@ function filterFromFilterId(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createTableExpander(indent) {
|
||||||
|
let div = document.createElement("div");
|
||||||
|
div.style.width = (indent + 0.5) + "em";
|
||||||
|
div.style.display = "inline-block";
|
||||||
|
div.style.textAlign = "right";
|
||||||
|
return div;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFunctionNode(name, codeId) {
|
||||||
|
if (codeId == -1) {
|
||||||
|
return document.createTextNode(name);
|
||||||
|
}
|
||||||
|
let nameElement = document.createElement("span");
|
||||||
|
nameElement.classList.add("codeid-link")
|
||||||
|
nameElement.onclick = function() {
|
||||||
|
main.setCurrentCode(codeId);
|
||||||
|
};
|
||||||
|
nameElement.appendChild(document.createTextNode(name));
|
||||||
|
return nameElement;
|
||||||
|
}
|
||||||
|
|
||||||
class CallTreeView {
|
class CallTreeView {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.element = $("calltree");
|
this.element = $("calltree");
|
||||||
@ -377,27 +387,6 @@ class CallTreeView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createExpander(indent) {
|
|
||||||
let div = document.createElement("div");
|
|
||||||
div.style.width = (1 + indent) + "em";
|
|
||||||
div.style.display = "inline-block";
|
|
||||||
div.style.textAlign = "right";
|
|
||||||
return div;
|
|
||||||
}
|
|
||||||
|
|
||||||
createFunctionNode(name, codeId) {
|
|
||||||
if (codeId == -1) {
|
|
||||||
return document.createTextNode(name);
|
|
||||||
}
|
|
||||||
let nameElement = document.createElement("span");
|
|
||||||
nameElement.classList.add("codeid-link")
|
|
||||||
nameElement.onclick = function() {
|
|
||||||
main.setCurrentCode(codeId);
|
|
||||||
};
|
|
||||||
nameElement.appendChild(document.createTextNode(name));
|
|
||||||
return nameElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
expandTree(tree, indent) {
|
expandTree(tree, indent) {
|
||||||
let that = this;
|
let that = this;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
@ -406,7 +395,6 @@ class CallTreeView {
|
|||||||
let expander = tree.expander;
|
let expander = tree.expander;
|
||||||
|
|
||||||
if (row) {
|
if (row) {
|
||||||
console.assert("expander");
|
|
||||||
index = row.rowIndex;
|
index = row.rowIndex;
|
||||||
id = row.id;
|
id = row.id;
|
||||||
|
|
||||||
@ -452,7 +440,7 @@ class CallTreeView {
|
|||||||
c.textContent = (node.ticks * 100 / tree.ticks).toFixed(2) + "%";
|
c.textContent = (node.ticks * 100 / tree.ticks).toFixed(2) + "%";
|
||||||
c.style.textAlign = "right";
|
c.style.textAlign = "right";
|
||||||
// Exclusive time % cell.
|
// Exclusive time % cell.
|
||||||
if (this.currentState.callTree.mode !== "bottom-up") {
|
if (this.currentState.mode !== "bottom-up") {
|
||||||
c = row.insertCell(-1);
|
c = row.insertCell(-1);
|
||||||
c.textContent = (node.ownTicks * 100 / this.tickCount).toFixed(2) + "%";
|
c.textContent = (node.ownTicks * 100 / this.tickCount).toFixed(2) + "%";
|
||||||
c.style.textAlign = "right";
|
c.style.textAlign = "right";
|
||||||
@ -460,16 +448,16 @@ class CallTreeView {
|
|||||||
|
|
||||||
// Create the name cell.
|
// Create the name cell.
|
||||||
let nameCell = row.insertCell();
|
let nameCell = row.insertCell();
|
||||||
let expander = this.createExpander(indent);
|
let expander = createTableExpander(indent + 1);
|
||||||
nameCell.appendChild(expander);
|
nameCell.appendChild(expander);
|
||||||
nameCell.appendChild(createTypeDiv(node.type));
|
nameCell.appendChild(createTypeDiv(node.type));
|
||||||
nameCell.appendChild(this.createFunctionNode(node.name, node.codeId));
|
nameCell.appendChild(createFunctionNode(node.name, node.codeId));
|
||||||
|
|
||||||
// Inclusive ticks cell.
|
// Inclusive ticks cell.
|
||||||
c = row.insertCell();
|
c = row.insertCell();
|
||||||
c.textContent = node.ticks;
|
c.textContent = node.ticks;
|
||||||
c.style.textAlign = "right";
|
c.style.textAlign = "right";
|
||||||
if (this.currentState.callTree.mode !== "bottom-up") {
|
if (this.currentState.mode !== "bottom-up") {
|
||||||
// Exclusive ticks cell.
|
// Exclusive ticks cell.
|
||||||
c = row.insertCell(-1);
|
c = row.insertCell(-1);
|
||||||
c.textContent = node.ownTicks;
|
c.textContent = node.ownTicks;
|
||||||
@ -500,7 +488,7 @@ class CallTreeView {
|
|||||||
expander.onclick = expandHandler;
|
expander.onclick = expandHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
fillSelects(calltree) {
|
fillSelects(mode, calltree) {
|
||||||
function addOptions(e, values, current) {
|
function addOptions(e, values, current) {
|
||||||
while (e.options.length > 0) {
|
while (e.options.length > 0) {
|
||||||
e.remove(0);
|
e.remove(0);
|
||||||
@ -523,7 +511,7 @@ class CallTreeView {
|
|||||||
text : "Attribute non-functions to JS functions" }
|
text : "Attribute non-functions to JS functions" }
|
||||||
];
|
];
|
||||||
|
|
||||||
switch (calltree.mode) {
|
switch (mode) {
|
||||||
case "bottom-up":
|
case "bottom-up":
|
||||||
addOptions(this.selectAttribution, attributions, calltree.attribution);
|
addOptions(this.selectAttribution, attributions, calltree.attribution);
|
||||||
addOptions(this.selectCategories, [
|
addOptions(this.selectCategories, [
|
||||||
@ -564,10 +552,22 @@ class CallTreeView {
|
|||||||
console.error("Unexpected mode");
|
console.error("Unexpected mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isCallTreeMode(mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case "bottom-up":
|
||||||
|
case "top-down":
|
||||||
|
case "function-list":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render(newState) {
|
render(newState) {
|
||||||
let oldState = this.currentState;
|
let oldState = this.currentState;
|
||||||
if (!newState.file) {
|
if (!newState.file || !CallTreeView.isCallTreeMode(newState.mode)) {
|
||||||
this.element.style.display = "none";
|
this.element.style.display = "none";
|
||||||
|
this.currentState = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,7 +576,7 @@ class CallTreeView {
|
|||||||
if (newState.file === oldState.file &&
|
if (newState.file === oldState.file &&
|
||||||
newState.start === oldState.start &&
|
newState.start === oldState.start &&
|
||||||
newState.end === oldState.end &&
|
newState.end === oldState.end &&
|
||||||
newState.callTree.mode === oldState.callTree.mode &&
|
newState.mode === oldState.mode &&
|
||||||
newState.callTree.attribution === oldState.callTree.attribution &&
|
newState.callTree.attribution === oldState.callTree.attribution &&
|
||||||
newState.callTree.categories === oldState.callTree.categories &&
|
newState.callTree.categories === oldState.callTree.categories &&
|
||||||
newState.callTree.sort === oldState.callTree.sort) {
|
newState.callTree.sort === oldState.callTree.sort) {
|
||||||
@ -587,12 +587,12 @@ class CallTreeView {
|
|||||||
|
|
||||||
this.element.style.display = "inherit";
|
this.element.style.display = "inherit";
|
||||||
|
|
||||||
let mode = this.currentState.callTree.mode;
|
let mode = this.currentState.mode;
|
||||||
if (!oldState || mode !== oldState.callTree.mode) {
|
if (!oldState || mode !== oldState.mode) {
|
||||||
// Technically, we should also call this if attribution, categories or
|
// Technically, we should also call this if attribution, categories or
|
||||||
// sort change, but the selection is already highlighted by the combobox
|
// sort change, but the selection is already highlighted by the combobox
|
||||||
// itself, so we do need to do anything here.
|
// itself, so we do need to do anything here.
|
||||||
this.fillSelects(newState.callTree);
|
this.fillSelects(newState.mode, newState.callTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ownTimeClass = (mode === "bottom-up") ? "numeric-hidden" : "numeric";
|
let ownTimeClass = (mode === "bottom-up") ? "numeric-hidden" : "numeric";
|
||||||
@ -661,7 +661,8 @@ class TimelineView {
|
|||||||
|
|
||||||
this.fontSize = 12;
|
this.fontSize = 12;
|
||||||
this.imageOffset = Math.round(this.fontSize * 1.2);
|
this.imageOffset = Math.round(this.fontSize * 1.2);
|
||||||
this.functionTimelineHeight = 16;
|
this.functionTimelineHeight = 24;
|
||||||
|
this.functionTimelineTickHeight = 16;
|
||||||
|
|
||||||
this.currentState = null;
|
this.currentState = null;
|
||||||
}
|
}
|
||||||
@ -864,8 +865,8 @@ class TimelineView {
|
|||||||
bucketsGraph.push(bucketData);
|
bucketsGraph.push(bucketData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the graph into the buffer.
|
// Draw the category graph into the buffer.
|
||||||
let bucketWidth = width / (bucketsGraph.length - 1);
|
let bucketWidth = width / bucketsGraph.length;
|
||||||
let ctx = buffer.getContext('2d');
|
let ctx = buffer.getContext('2d');
|
||||||
for (let i = 0; i < bucketsGraph.length - 1; i++) {
|
for (let i = 0; i < bucketsGraph.length - 1; i++) {
|
||||||
let bucketData = bucketsGraph[i];
|
let bucketData = bucketsGraph[i];
|
||||||
@ -883,25 +884,30 @@ class TimelineView {
|
|||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw the function ticks.
|
||||||
let functionTimelineYOffset = graphHeight;
|
let functionTimelineYOffset = graphHeight;
|
||||||
let functionTimelineHeight = this.functionTimelineHeight;
|
let functionTimelineTickHeight = this.functionTimelineTickHeight;
|
||||||
let functionTimelineHalfHeight = Math.round(functionTimelineHeight / 2);
|
let functionTimelineHalfHeight =
|
||||||
|
Math.round(functionTimelineTickHeight / 2);
|
||||||
let timestampScaler = width / (lastTime - firstTime);
|
let timestampScaler = width / (lastTime - firstTime);
|
||||||
|
let timestampToX = (t) => Math.round((t - firstTime) * timestampScaler);
|
||||||
ctx.fillStyle = "white";
|
ctx.fillStyle = "white";
|
||||||
ctx.fillRect(
|
ctx.fillRect(
|
||||||
0,
|
0,
|
||||||
functionTimelineYOffset,
|
functionTimelineYOffset,
|
||||||
buffer.width,
|
buffer.width,
|
||||||
functionTimelineHeight);
|
this.functionTimelineHeight);
|
||||||
for (let i = 0; i < codeIdProcessor.blocks.length; i++) {
|
for (let i = 0; i < codeIdProcessor.blocks.length; i++) {
|
||||||
let block = codeIdProcessor.blocks[i];
|
let block = codeIdProcessor.blocks[i];
|
||||||
let bucket = kindToBucketDescriptor[block.kind];
|
let bucket = kindToBucketDescriptor[block.kind];
|
||||||
ctx.fillStyle = bucket.color;
|
ctx.fillStyle = bucket.color;
|
||||||
ctx.fillRect(
|
ctx.fillRect(
|
||||||
Math.round((block.start - firstTime) * timestampScaler),
|
timestampToX(block.start),
|
||||||
functionTimelineYOffset,
|
functionTimelineYOffset,
|
||||||
Math.max(1, Math.round((block.end - block.start) * timestampScaler)),
|
Math.max(1, Math.round((block.end - block.start) * timestampScaler)),
|
||||||
block.topOfStack ? functionTimelineHeight : functionTimelineHalfHeight);
|
block.topOfStack ?
|
||||||
|
functionTimelineTickHeight : functionTimelineHalfHeight);
|
||||||
}
|
}
|
||||||
ctx.strokeStyle = "black";
|
ctx.strokeStyle = "black";
|
||||||
ctx.lineWidth = "1";
|
ctx.lineWidth = "1";
|
||||||
@ -917,6 +923,53 @@ class TimelineView {
|
|||||||
functionTimelineYOffset + functionTimelineHalfHeight - 0.5);
|
functionTimelineYOffset + functionTimelineHalfHeight - 0.5);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
|
// Draw marks for optimizations and deoptimizations in the function
|
||||||
|
// timeline.
|
||||||
|
if (currentCodeId && currentCodeId >= 0 &&
|
||||||
|
file.code[currentCodeId].func) {
|
||||||
|
let y = Math.round(functionTimelineYOffset + functionTimelineTickHeight +
|
||||||
|
(this.functionTimelineHeight - functionTimelineTickHeight) / 2);
|
||||||
|
let func = file.functions[file.code[currentCodeId].func];
|
||||||
|
for (let i = 0; i < func.codes.length; i++) {
|
||||||
|
let code = file.code[func.codes[i]];
|
||||||
|
if (code.kind === "Opt") {
|
||||||
|
if (code.deopt) {
|
||||||
|
// Draw deoptimization mark.
|
||||||
|
let x = timestampToX(code.deopt.tm);
|
||||||
|
ctx.lineWidth = 0.7;
|
||||||
|
ctx.strokeStyle = "red";
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x - 3, y - 3);
|
||||||
|
ctx.lineTo(x + 3, y + 3);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x - 3, y + 3);
|
||||||
|
ctx.lineTo(x + 3, y - 3);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
// Draw optimization mark.
|
||||||
|
let x = timestampToX(code.tm);
|
||||||
|
ctx.lineWidth = 0.7;
|
||||||
|
ctx.strokeStyle = "blue";
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x - 3, y - 3);
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x - 3, y + 3);
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
ctx.stroke();
|
||||||
|
} else {
|
||||||
|
// Draw code creation mark.
|
||||||
|
let x = Math.round(timestampToX(code.tm));
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = "black";
|
||||||
|
ctx.arc(x, y, 3, 0, 2 * Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remember stuff for later.
|
// Remember stuff for later.
|
||||||
this.buffer = buffer;
|
this.buffer = buffer;
|
||||||
|
|
||||||
@ -958,6 +1011,218 @@ class TimelineView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ModeBarView {
|
||||||
|
constructor() {
|
||||||
|
let modeBar = this.element = $("mode-bar");
|
||||||
|
|
||||||
|
function addMode(id, text, active) {
|
||||||
|
let div = document.createElement("div");
|
||||||
|
div.classList = "mode-button" + (active ? " active-mode-button" : "");
|
||||||
|
div.id = "mode-" + id;
|
||||||
|
div.textContent = text;
|
||||||
|
div.onclick = () => {
|
||||||
|
if (main.currentState.mode === id) return;
|
||||||
|
let old = $("mode-" + main.currentState.mode);
|
||||||
|
old.classList = "mode-button";
|
||||||
|
div.classList = "mode-button active-mode-button";
|
||||||
|
main.setMode(id);
|
||||||
|
};
|
||||||
|
modeBar.appendChild(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
addMode("summary", "Summary", true);
|
||||||
|
addMode("bottom-up", "Bottom up");
|
||||||
|
addMode("top-down", "Top down");
|
||||||
|
addMode("function-list", "Functions");
|
||||||
|
}
|
||||||
|
|
||||||
|
render(newState) {
|
||||||
|
if (!newState.file) {
|
||||||
|
this.element.style.display = "none";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.style.display = "inherit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SummaryView {
|
||||||
|
constructor() {
|
||||||
|
this.element = $("summary");
|
||||||
|
this.currentState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(newState) {
|
||||||
|
let oldState = this.currentState;
|
||||||
|
|
||||||
|
if (!newState.file || newState.mode !== "summary") {
|
||||||
|
this.element.style.display = "none";
|
||||||
|
this.currentState = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentState = newState;
|
||||||
|
if (oldState) {
|
||||||
|
if (newState.file === oldState.file &&
|
||||||
|
newState.start === oldState.start &&
|
||||||
|
newState.end === oldState.end) {
|
||||||
|
// No change, nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.style.display = "inherit";
|
||||||
|
|
||||||
|
while (this.element.firstChild) {
|
||||||
|
this.element.removeChild(this.element.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
let stats = computeOptimizationStats(
|
||||||
|
this.currentState.file, newState.start, newState.end);
|
||||||
|
|
||||||
|
let table = document.createElement("table");
|
||||||
|
let rows = document.createElement("tbody");
|
||||||
|
|
||||||
|
function addRow(text, number, indent) {
|
||||||
|
let row = rows.insertRow(-1);
|
||||||
|
let textCell = row.insertCell(-1);
|
||||||
|
textCell.textContent = text;
|
||||||
|
let numberCell = row.insertCell(-1);
|
||||||
|
numberCell.textContent = number;
|
||||||
|
if (indent) {
|
||||||
|
textCell.style.textIndent = indent + "em";
|
||||||
|
numberCell.style.textIndent = indent + "em";
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeCollapsible(row, expander) {
|
||||||
|
expander.textContent = "\u25BE";
|
||||||
|
let expandHandler = expander.onclick;
|
||||||
|
expander.onclick = () => {
|
||||||
|
let id = row.id;
|
||||||
|
let index = row.rowIndex + 1;
|
||||||
|
while (index < rows.rows.length &&
|
||||||
|
rows.rows[index].id.startsWith(id)) {
|
||||||
|
rows.deleteRow(index);
|
||||||
|
}
|
||||||
|
expander.textContent = "\u25B8";
|
||||||
|
expander.onclick = expandHandler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandDeoptInstances(row, expander, instances, indent, kind) {
|
||||||
|
let index = row.rowIndex;
|
||||||
|
for (let i = 0; i < instances.length; i++) {
|
||||||
|
let childRow = rows.insertRow(index + 1);
|
||||||
|
childRow.id = row.id + i + "/";
|
||||||
|
|
||||||
|
let deopt = instances[i].deopt;
|
||||||
|
|
||||||
|
let textCell = childRow.insertCell(-1);
|
||||||
|
textCell.appendChild(document.createTextNode(deopt.posText));
|
||||||
|
textCell.style.textIndent = indent + "em";
|
||||||
|
let reasonCell = childRow.insertCell(-1);
|
||||||
|
reasonCell.appendChild(
|
||||||
|
document.createTextNode("Reason: " + deopt.reason));
|
||||||
|
reasonCell.style.textIndent = indent + "em";
|
||||||
|
}
|
||||||
|
makeCollapsible(row, expander);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandDeoptFunctionList(row, expander, list, indent, kind) {
|
||||||
|
let index = row.rowIndex;
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let childRow = rows.insertRow(index + 1);
|
||||||
|
childRow.id = row.id + i + "/";
|
||||||
|
|
||||||
|
let textCell = childRow.insertCell(-1);
|
||||||
|
let expander = createTableExpander(indent);
|
||||||
|
textCell.appendChild(expander);
|
||||||
|
textCell.appendChild(
|
||||||
|
createFunctionNode(list[i].f.name, list[i].f.codes[0]));
|
||||||
|
|
||||||
|
let numberCell = childRow.insertCell(-1);
|
||||||
|
numberCell.textContent = list[i].instances.length;
|
||||||
|
numberCell.style.textIndent = indent + "em";
|
||||||
|
|
||||||
|
expander.textContent = "\u25B8";
|
||||||
|
expander.onclick = () => {
|
||||||
|
expandDeoptInstances(
|
||||||
|
childRow, expander, list[i].instances, indent + 1);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
makeCollapsible(row, expander);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandOptimizedFunctionList(row, expander, list, indent, kind) {
|
||||||
|
let index = row.rowIndex;
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let childRow = rows.insertRow(index + 1);
|
||||||
|
childRow.id = row.id + i + "/";
|
||||||
|
|
||||||
|
let textCell = childRow.insertCell(-1);
|
||||||
|
textCell.appendChild(
|
||||||
|
createFunctionNode(list[i].f.name, list[i].f.codes[0]));
|
||||||
|
textCell.style.textIndent = indent + "em";
|
||||||
|
|
||||||
|
let numberCell = childRow.insertCell(-1);
|
||||||
|
numberCell.textContent = list[i].instances.length;
|
||||||
|
numberCell.style.textIndent = indent + "em";
|
||||||
|
}
|
||||||
|
makeCollapsible(row, expander);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addExpandableRow(text, list, indent, kind) {
|
||||||
|
let row = rows.insertRow(-1);
|
||||||
|
|
||||||
|
row.id = "opt-table/" + kind + "/";
|
||||||
|
|
||||||
|
let textCell = row.insertCell(-1);
|
||||||
|
let expander = createTableExpander(indent);
|
||||||
|
textCell.appendChild(expander);
|
||||||
|
textCell.appendChild(document.createTextNode(text));
|
||||||
|
|
||||||
|
let numberCell = row.insertCell(-1);
|
||||||
|
numberCell.textContent = list.count;
|
||||||
|
if (indent) {
|
||||||
|
numberCell.style.textIndent = indent + "em";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list.count > 0) {
|
||||||
|
expander.textContent = "\u25B8";
|
||||||
|
if (kind === "opt") {
|
||||||
|
expander.onclick = () => {
|
||||||
|
expandOptimizedFunctionList(
|
||||||
|
row, expander, list.functions, indent + 1, kind);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
expander.onclick = () => {
|
||||||
|
expandDeoptFunctionList(
|
||||||
|
row, expander, list.functions, indent + 1, kind);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
addRow("Total function count:", stats.functionCount);
|
||||||
|
addRow("Optimized function count:", stats.optimizedFunctionCount, 1);
|
||||||
|
addRow("Deoptimized function count:", stats.deoptimizedFunctionCount, 2);
|
||||||
|
|
||||||
|
addExpandableRow("Optimization count:", stats.optimizations, 0, "opt");
|
||||||
|
let deoptCount = stats.eagerDeoptimizations.count +
|
||||||
|
stats.softDeoptimizations.count + stats.lazyDeoptimizations.count;
|
||||||
|
addRow("Deoptimization count:", deoptCount);
|
||||||
|
addExpandableRow("Eager:", stats.eagerDeoptimizations, 1, "eager");
|
||||||
|
addExpandableRow("Lazy:", stats.lazyDeoptimizations, 1, "lazy");
|
||||||
|
addExpandableRow("Soft:", stats.softDeoptimizations, 1, "soft");
|
||||||
|
|
||||||
|
table.appendChild(rows);
|
||||||
|
this.element.appendChild(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class HelpView {
|
class HelpView {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.element = $("help");
|
this.element = $("help");
|
||||||
|
@ -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(
|
|||||||
|
|
||||||
|
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user