Commit cb59fc1f authored by lpy's avatar lpy Committed by Commit bot

Refactor CpuProfiler.

Currently CpuProfiler is a subclass of CodeEventListener, it listens code events
from Logger, constructs and stores CodeEventsContainer. This patch is part of
the effort to split the logic of CodeEventListener as ProfilerListener out of
the profiling functionality logic in CpuProfiler. A ProfilerListener will listen
to code events, construct code event to CodeEventsContainer and pass it to code
event handler.

The reason we refactor CpuProfiler is that eventually we want to move
CpuProfiler as part of sampler library and code event listener should stay
inside V8.

Main changes:
1. Refactored CpuProfiler into two parts, the CpuProfiler with profling
functionality and the ProfilerListener listening to code events from Logger.
2. Created CodeEventObserver and made CpuProfiler inherit from it.
ProfilerListener will have a list of observers and call CodeEventHandler once a
code event is created.
3. Moved code entry list from CodeEntry to ProfilerListener.

Minor changes:
1. Moved static code entry as part of CodeEntry.
2. Added ProfilerListener to Logger.

BUG=v8:4789

Review-Url: https://codereview.chromium.org/2053523003
Cr-Commit-Position: refs/heads/master@{#37112}
parent cbc6adc8
...@@ -1322,6 +1322,8 @@ v8_source_set("v8_base") { ...@@ -1322,6 +1322,8 @@ v8_source_set("v8_base") {
"src/profiler/profile-generator-inl.h", "src/profiler/profile-generator-inl.h",
"src/profiler/profile-generator.cc", "src/profiler/profile-generator.cc",
"src/profiler/profile-generator.h", "src/profiler/profile-generator.h",
"src/profiler/profiler-listener.cc",
"src/profiler/profiler-listener.h",
"src/profiler/sampling-heap-profiler.cc", "src/profiler/sampling-heap-profiler.cc",
"src/profiler/sampling-heap-profiler.h", "src/profiler/sampling-heap-profiler.h",
"src/profiler/strings-storage.cc", "src/profiler/strings-storage.cc",
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/perf-jit.h" #include "src/perf-jit.h"
#include "src/profiler/cpu-profiler-inl.h" #include "src/profiler/cpu-profiler-inl.h"
#include "src/profiler/profiler-listener.h"
#include "src/runtime-profiler.h" #include "src/runtime-profiler.h"
#include "src/string-stream.h" #include "src/string-stream.h"
#include "src/vm-state-inl.h" #include "src/vm-state-inl.h"
...@@ -1789,6 +1790,8 @@ bool Logger::SetUp(Isolate* isolate) { ...@@ -1789,6 +1790,8 @@ bool Logger::SetUp(Isolate* isolate) {
profiler_->Engage(); profiler_->Engage();
} }
profiler_listener_.reset();
if (is_logging_) { if (is_logging_) {
addCodeEventListener(this); addCodeEventListener(this);
} }
...@@ -1816,6 +1819,18 @@ void Logger::SetCodeEventHandler(uint32_t options, ...@@ -1816,6 +1819,18 @@ void Logger::SetCodeEventHandler(uint32_t options,
} }
} }
void Logger::SetUpProfilerListener() {
if (!is_initialized_) return;
if (profiler_listener_.get() == nullptr) {
profiler_listener_.reset(new ProfilerListener(isolate_));
}
addCodeEventListener(profiler_listener_.get());
}
void Logger::TearDownProfilerListener() {
if (profiler_listener_->HasObservers()) return;
removeCodeEventListener(profiler_listener_.get());
}
sampler::Sampler* Logger::sampler() { sampler::Sampler* Logger::sampler() {
return ticker_; return ticker_;
...@@ -1860,6 +1875,10 @@ FILE* Logger::TearDown() { ...@@ -1860,6 +1875,10 @@ FILE* Logger::TearDown() {
jit_logger_ = NULL; jit_logger_ = NULL;
} }
if (profiler_listener_.get() != nullptr) {
removeCodeEventListener(profiler_listener_.get());
}
return log_->Close(); return log_->Close();
} }
......
...@@ -89,6 +89,7 @@ class JitLogger; ...@@ -89,6 +89,7 @@ class JitLogger;
class PerfBasicLogger; class PerfBasicLogger;
class LowLevelLogger; class LowLevelLogger;
class PerfJitLogger; class PerfJitLogger;
class ProfilerListener;
class Logger : public CodeEventListener { class Logger : public CodeEventListener {
public: public:
...@@ -101,8 +102,16 @@ class Logger : public CodeEventListener { ...@@ -101,8 +102,16 @@ class Logger : public CodeEventListener {
void SetCodeEventHandler(uint32_t options, void SetCodeEventHandler(uint32_t options,
JitCodeEventHandler event_handler); JitCodeEventHandler event_handler);
// Sets up ProfilerListener.
void SetUpProfilerListener();
// Tear down ProfilerListener if it has no observers.
void TearDownProfilerListener();
sampler::Sampler* sampler(); sampler::Sampler* sampler();
ProfilerListener* profiler_listener() { return profiler_listener_.get(); }
// Frees resources acquired in SetUp. // Frees resources acquired in SetUp.
// When a temporary file is used for the log, returns its stream descriptor, // When a temporary file is used for the log, returns its stream descriptor,
// leaving the file open. // leaving the file open.
...@@ -332,6 +341,7 @@ class Logger : public CodeEventListener { ...@@ -332,6 +341,7 @@ class Logger : public CodeEventListener {
PerfJitLogger* perf_jit_logger_; PerfJitLogger* perf_jit_logger_;
LowLevelLogger* ll_logger_; LowLevelLogger* ll_logger_;
JitLogger* jit_logger_; JitLogger* jit_logger_;
std::unique_ptr<ProfilerListener> profiler_listener_;
List<CodeEventListener*> listeners_; List<CodeEventListener*> listeners_;
// Guards against multiple calls to TearDown() that can happen in some tests. // Guards against multiple calls to TearDown() that can happen in some tests.
......
...@@ -199,294 +199,23 @@ void CpuProfiler::DeleteProfile(CpuProfile* profile) { ...@@ -199,294 +199,23 @@ void CpuProfiler::DeleteProfile(CpuProfile* profile) {
} }
} }
void CpuProfiler::CodeEventHandler(const CodeEventsContainer& evt_rec) {
void CpuProfiler::CallbackEvent(Name* name, Address entry_point) { switch (evt_rec.generic.type) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); case CodeEventRecord::CODE_CREATION:
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; case CodeEventRecord::CODE_MOVE:
rec->start = entry_point; case CodeEventRecord::CODE_DISABLE_OPT:
rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG, processor_->Enqueue(evt_rec);
profiles_->GetName(name)); break;
rec->size = 1; case CodeEventRecord::CODE_DEOPT: {
processor_->Enqueue(evt_rec); const CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
} Address pc = reinterpret_cast<Address>(rec->pc);
int fp_to_sp_delta = rec->fp_to_sp_delta;
void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, processor_->Enqueue(evt_rec);
AbstractCode* code, const char* name) { processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); break;
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, Name* name) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code,
SharedFunctionInfo* shared,
Name* script_name) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(shared->DebugName()),
CodeEntry::kEmptyNamePrefix,
profiles_->GetName(InferScriptName(script_name, shared)),
CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->entry->FillFunctionInfo(shared);
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* abstract_code,
SharedFunctionInfo* shared, Name* script_name,
int line, int column) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = abstract_code->address();
Script* script = Script::cast(shared->script());
JITLineInfoTable* line_table = NULL;
if (script) {
if (abstract_code->IsCode()) {
Code* code = abstract_code->GetCode();
int start_position = shared->start_position();
int end_position = shared->end_position();
line_table = new JITLineInfoTable();
for (RelocIterator it(code); !it.done(); it.next()) {
RelocInfo* reloc_info = it.rinfo();
if (!RelocInfo::IsPosition(reloc_info->rmode())) continue;
int position = static_cast<int>(reloc_info->data());
// TODO(alph): in case of inlining the position may correspond
// to an inlined function source code. Do not collect positions
// that fall beyond the function source code. There's however a
// chance the inlined function has similar positions but in another
// script. So the proper fix is to store script_id in some form
// along with the inlined function positions.
if (position < start_position || position >= end_position) continue;
int pc_offset = static_cast<int>(reloc_info->pc() - code->address());
int line_number = script->GetLineNumber(position) + 1;
line_table->SetPosition(pc_offset, line_number);
}
} else {
BytecodeArray* bytecode = abstract_code->GetBytecodeArray();
line_table = new JITLineInfoTable();
interpreter::SourcePositionTableIterator it(
bytecode->source_position_table());
for (; !it.done(); it.Advance()) {
int line_number = script->GetLineNumber(it.source_position()) + 1;
int pc_offset = it.bytecode_offset() + BytecodeArray::kHeaderSize;
line_table->SetPosition(pc_offset, line_number);
}
}
}
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(shared->DebugName()),
CodeEntry::kEmptyNamePrefix,
profiles_->GetName(InferScriptName(script_name, shared)), line, column,
line_table, abstract_code->instruction_start());
RecordInliningInfo(rec->entry, abstract_code);
RecordDeoptInlinedFrames(rec->entry, abstract_code);
rec->entry->FillFunctionInfo(shared);
rec->size = abstract_code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, int args_count) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetName(args_count), "args_count: ",
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeMoveEvent(AbstractCode* from, Address to) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
rec->from = from->address();
rec->to = to;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
rec->start = code->address();
rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
processor_->Enqueue(evt_rec);
}
void CpuProfiler::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
rec->start = code->address();
rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
rec->position = info.position;
rec->deopt_id = info.deopt_id;
processor_->Enqueue(evt_rec);
processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta);
}
void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG,
profiles_->GetName(name), "get ");
rec->size = 1;
processor_->Enqueue(evt_rec);
}
void CpuProfiler::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
CodeEventListener::REG_EXP_TAG, profiles_->GetName(source), "RegExp: ",
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG,
profiles_->GetName(name), "set ");
rec->size = 1;
processor_->Enqueue(evt_rec);
}
Name* CpuProfiler::InferScriptName(Name* name, SharedFunctionInfo* info) {
if (name->IsString() && String::cast(name)->length()) return name;
if (!info->script()->IsScript()) return name;
Object* source_url = Script::cast(info->script())->source_url();
return source_url->IsName() ? Name::cast(source_url) : name;
}
void CpuProfiler::RecordInliningInfo(CodeEntry* entry,
AbstractCode* abstract_code) {
if (!abstract_code->IsCode()) return;
Code* code = abstract_code->GetCode();
if (code->kind() != Code::OPTIMIZED_FUNCTION) return;
DeoptimizationInputData* deopt_input_data =
DeoptimizationInputData::cast(code->deoptimization_data());
int deopt_count = deopt_input_data->DeoptCount();
for (int i = 0; i < deopt_count; i++) {
int pc_offset = deopt_input_data->Pc(i)->value();
if (pc_offset == -1) continue;
int translation_index = deopt_input_data->TranslationIndex(i)->value();
TranslationIterator it(deopt_input_data->TranslationByteArray(),
translation_index);
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, opcode);
it.Skip(Translation::NumberOfOperandsFor(opcode));
int depth = 0;
std::vector<CodeEntry*> inline_stack;
while (it.HasNext() &&
Translation::BEGIN !=
(opcode = static_cast<Translation::Opcode>(it.Next()))) {
if (opcode != Translation::JS_FRAME &&
opcode != Translation::INTERPRETED_FRAME) {
it.Skip(Translation::NumberOfOperandsFor(opcode));
continue;
}
it.Next(); // Skip ast_id
int shared_info_id = it.Next();
it.Next(); // Skip height
SharedFunctionInfo* shared_info = SharedFunctionInfo::cast(
deopt_input_data->LiteralArray()->get(shared_info_id));
if (!depth++) continue; // Skip the current function itself.
CodeEntry* inline_entry = new CodeEntry(
entry->tag(), profiles_->GetFunctionName(shared_info->DebugName()),
CodeEntry::kEmptyNamePrefix, entry->resource_name(),
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
inline_entry->FillFunctionInfo(shared_info);
inline_stack.push_back(inline_entry);
}
if (!inline_stack.empty()) {
entry->AddInlineStack(pc_offset, inline_stack);
DCHECK(inline_stack.empty());
}
}
}
void CpuProfiler::RecordDeoptInlinedFrames(CodeEntry* entry,
AbstractCode* abstract_code) {
if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return;
Code* code = abstract_code->GetCode();
DeoptimizationInputData* deopt_input_data =
DeoptimizationInputData::cast(code->deoptimization_data());
int const mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID);
for (RelocIterator rit(code, mask); !rit.done(); rit.next()) {
RelocInfo* reloc_info = rit.rinfo();
DCHECK(RelocInfo::IsDeoptId(reloc_info->rmode()));
int deopt_id = static_cast<int>(reloc_info->data());
int translation_index =
deopt_input_data->TranslationIndex(deopt_id)->value();
TranslationIterator it(deopt_input_data->TranslationByteArray(),
translation_index);
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, opcode);
it.Skip(Translation::NumberOfOperandsFor(opcode));
std::vector<CodeEntry::DeoptInlinedFrame> inlined_frames;
while (it.HasNext() &&
Translation::BEGIN !=
(opcode = static_cast<Translation::Opcode>(it.Next()))) {
if (opcode != Translation::JS_FRAME &&
opcode != Translation::INTERPRETED_FRAME) {
it.Skip(Translation::NumberOfOperandsFor(opcode));
continue;
}
BailoutId ast_id = BailoutId(it.Next());
int shared_info_id = it.Next();
it.Next(); // Skip height
SharedFunctionInfo* shared = SharedFunctionInfo::cast(
deopt_input_data->LiteralArray()->get(shared_info_id));
int source_position = Deoptimizer::ComputeSourcePosition(shared, ast_id);
int script_id = v8::UnboundScript::kNoScriptId;
if (shared->script()->IsScript()) {
Script* script = Script::cast(shared->script());
script_id = script->id();
}
CodeEntry::DeoptInlinedFrame frame = {source_position, script_id};
inlined_frames.push_back(frame);
}
if (!inlined_frames.empty() && !entry->HasDeoptInlinedFramesFor(deopt_id)) {
entry->AddDeoptInlinedFrames(deopt_id, inlined_frames);
DCHECK(inlined_frames.empty());
} }
default:
UNREACHABLE();
} }
} }
...@@ -558,11 +287,13 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -558,11 +287,13 @@ void CpuProfiler::StartProcessorIfNotStarted() {
generator_.reset(new ProfileGenerator(profiles_.get())); generator_.reset(new ProfileGenerator(profiles_.get()));
processor_.reset(new ProfilerEventsProcessor(generator_.get(), sampler, processor_.reset(new ProfilerEventsProcessor(generator_.get(), sampler,
sampling_interval_)); sampling_interval_));
logger->SetUpProfilerListener();
ProfilerListener* profiler_listener = logger->profiler_listener();
profiler_listener->AddObserver(this);
is_profiling_ = true; is_profiling_ = true;
isolate_->set_is_profiling(true); isolate_->set_is_profiling(true);
// Enumerate stuff we already have in the heap. // Enumerate stuff we already have in the heap.
DCHECK(isolate_->heap()->HasBeenSetUp()); DCHECK(isolate_->heap()->HasBeenSetUp());
isolate_->code_event_dispatcher()->AddListener(this);
if (!FLAG_prof_browser_mode) { if (!FLAG_prof_browser_mode) {
logger->LogCodeObjects(); logger->LogCodeObjects();
} }
...@@ -609,8 +340,10 @@ void CpuProfiler::StopProcessor() { ...@@ -609,8 +340,10 @@ void CpuProfiler::StopProcessor() {
reinterpret_cast<sampler::Sampler*>(logger->ticker_); reinterpret_cast<sampler::Sampler*>(logger->ticker_);
is_profiling_ = false; is_profiling_ = false;
isolate_->set_is_profiling(false); isolate_->set_is_profiling(false);
isolate_->code_event_dispatcher()->RemoveListener(this); ProfilerListener* profiler_listener = logger->profiler_listener();
profiler_listener->RemoveObserver(this);
processor_->StopSynchronously(); processor_->StopSynchronously();
logger->TearDownProfilerListener();
processor_.reset(); processor_.reset();
generator_.reset(); generator_.reset();
sampler->SetHasProcessingThread(false); sampler->SetHasProcessingThread(false);
...@@ -632,6 +365,5 @@ void CpuProfiler::LogBuiltins() { ...@@ -632,6 +365,5 @@ void CpuProfiler::LogBuiltins() {
} }
} }
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "src/libsampler/v8-sampler.h" #include "src/libsampler/v8-sampler.h"
#include "src/locked-queue.h" #include "src/locked-queue.h"
#include "src/profiler/circular-queue.h" #include "src/profiler/circular-queue.h"
#include "src/profiler/profiler-listener.h"
#include "src/profiler/tick-sample.h" #include "src/profiler/tick-sample.h"
namespace v8 { namespace v8 {
...@@ -85,6 +86,8 @@ class CodeDeoptEventRecord : public CodeEventRecord { ...@@ -85,6 +86,8 @@ class CodeDeoptEventRecord : public CodeEventRecord {
const char* deopt_reason; const char* deopt_reason;
SourcePosition position; SourcePosition position;
int deopt_id; int deopt_id;
void* pc;
int fp_to_sp_delta;
INLINE(void UpdateCodeMap(CodeMap* code_map)); INLINE(void UpdateCodeMap(CodeMap* code_map));
}; };
...@@ -183,7 +186,7 @@ class ProfilerEventsProcessor : public base::Thread { ...@@ -183,7 +186,7 @@ class ProfilerEventsProcessor : public base::Thread {
unsigned last_processed_code_event_id_; unsigned last_processed_code_event_id_;
}; };
class CpuProfiler : public CodeEventListener { class CpuProfiler : public CodeEventObserver {
public: public:
explicit CpuProfiler(Isolate* isolate); explicit CpuProfiler(Isolate* isolate);
...@@ -204,34 +207,12 @@ class CpuProfiler : public CodeEventListener { ...@@ -204,34 +207,12 @@ class CpuProfiler : public CodeEventListener {
void DeleteAllProfiles(); void DeleteAllProfiles();
void DeleteProfile(CpuProfile* profile); void DeleteProfile(CpuProfile* profile);
void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
// Invoked from stack sampler (thread or signal handler.) // Invoked from stack sampler (thread or signal handler.)
inline TickSample* StartTickSample(); inline TickSample* StartTickSample();
inline void FinishTickSample(); inline void FinishTickSample();
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
void CallbackEvent(Name* name, Address entry_point) override;
void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
const char* comment) override;
void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
Name* name) override;
void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
SharedFunctionInfo* shared, Name* script_name) override;
void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
SharedFunctionInfo* shared, Name* script_name, int line,
int column) override;
void CodeCreateEvent(LogEventsAndTags tag, AbstractCode* code,
int args_count) override;
void CodeMovingGCEvent() override {}
void CodeMoveEvent(AbstractCode* from, Address to) override;
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override;
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override;
void GetterCallbackEvent(Name* name, Address entry_point) override;
void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
void SetterCallbackEvent(Name* name, Address entry_point) override;
void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
bool is_profiling() const { return is_profiling_; } bool is_profiling() const { return is_profiling_; }
ProfileGenerator* generator() const { return generator_.get(); } ProfileGenerator* generator() const { return generator_.get(); }
...@@ -244,9 +225,6 @@ class CpuProfiler : public CodeEventListener { ...@@ -244,9 +225,6 @@ class CpuProfiler : public CodeEventListener {
void StopProcessor(); void StopProcessor();
void ResetProfiles(); void ResetProfiles();
void LogBuiltins(); void LogBuiltins();
void RecordInliningInfo(CodeEntry* entry, AbstractCode* abstract_code);
void RecordDeoptInlinedFrames(CodeEntry* entry, AbstractCode* abstract_code);
Name* InferScriptName(Name* name, SharedFunctionInfo* info);
Isolate* const isolate_; Isolate* const isolate_;
base::TimeDelta sampling_interval_; base::TimeDelta sampling_interval_;
......
...@@ -48,6 +48,41 @@ const char* const CodeEntry::kEmptyResourceName = ""; ...@@ -48,6 +48,41 @@ const char* const CodeEntry::kEmptyResourceName = "";
const char* const CodeEntry::kEmptyBailoutReason = ""; const char* const CodeEntry::kEmptyBailoutReason = "";
const char* const CodeEntry::kNoDeoptReason = ""; const char* const CodeEntry::kNoDeoptReason = "";
const char* const CodeEntry::kProgramEntryName = "(program)";
const char* const CodeEntry::kIdleEntryName = "(idle)";
const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)";
const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)";
base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type
CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
base::LazyDynamicInstance<CodeEntry, CodeEntry::IdleEntryCreateTrait>::type
CodeEntry::kIdleEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
base::LazyDynamicInstance<CodeEntry, CodeEntry::GCEntryCreateTrait>::type
CodeEntry::kGCEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
base::LazyDynamicInstance<CodeEntry,
CodeEntry::UnresolvedEntryCreateTrait>::type
CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER;
CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() {
return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kProgramEntryName);
}
CodeEntry* CodeEntry::IdleEntryCreateTrait::Create() {
return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kIdleEntryName);
}
CodeEntry* CodeEntry::GCEntryCreateTrait::Create() {
return new CodeEntry(Logger::BUILTIN_TAG,
CodeEntry::kGarbageCollectorEntryName);
}
CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
return new CodeEntry(Logger::FUNCTION_TAG,
CodeEntry::kUnresolvedFunctionName);
}
CodeEntry::~CodeEntry() { CodeEntry::~CodeEntry() {
delete line_info_; delete line_info_;
...@@ -433,15 +468,10 @@ void CodeMap::Print() { ...@@ -433,15 +468,10 @@ void CodeMap::Print() {
} }
CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate) CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate)
: function_and_resource_names_(isolate->heap()), : resource_names_(isolate->heap()),
profiler_(nullptr), profiler_(nullptr),
current_profiles_semaphore_(1) {} current_profiles_semaphore_(1) {}
static void DeleteCodeEntry(CodeEntry** entry_ptr) {
delete *entry_ptr;
}
static void DeleteCpuProfile(CpuProfile** profile_ptr) { static void DeleteCpuProfile(CpuProfile** profile_ptr) {
delete *profile_ptr; delete *profile_ptr;
} }
...@@ -450,7 +480,6 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) { ...@@ -450,7 +480,6 @@ static void DeleteCpuProfile(CpuProfile** profile_ptr) {
CpuProfilesCollection::~CpuProfilesCollection() { CpuProfilesCollection::~CpuProfilesCollection() {
finished_profiles_.Iterate(DeleteCpuProfile); finished_profiles_.Iterate(DeleteCpuProfile);
current_profiles_.Iterate(DeleteCpuProfile); current_profiles_.Iterate(DeleteCpuProfile);
code_entries_.Iterate(DeleteCodeEntry);
} }
...@@ -527,37 +556,8 @@ void CpuProfilesCollection::AddPathToCurrentProfiles( ...@@ -527,37 +556,8 @@ void CpuProfilesCollection::AddPathToCurrentProfiles(
current_profiles_semaphore_.Signal(); current_profiles_semaphore_.Signal();
} }
CodeEntry* CpuProfilesCollection::NewCodeEntry(
CodeEventListener::LogEventsAndTags tag, const char* name,
const char* name_prefix, const char* resource_name, int line_number,
int column_number, JITLineInfoTable* line_info, Address instruction_start) {
CodeEntry* code_entry =
new CodeEntry(tag, name, name_prefix, resource_name, line_number,
column_number, line_info, instruction_start);
code_entries_.Add(code_entry);
return code_entry;
}
const char* const ProfileGenerator::kProgramEntryName =
"(program)";
const char* const ProfileGenerator::kIdleEntryName =
"(idle)";
const char* const ProfileGenerator::kGarbageCollectorEntryName =
"(garbage collector)";
const char* const ProfileGenerator::kUnresolvedFunctionName =
"(unresolved function)";
ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
: profiles_(profiles), : profiles_(profiles) {}
program_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG,
kProgramEntryName)),
idle_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG,
kIdleEntryName)),
gc_entry_(profiles->NewCodeEntry(CodeEventListener::BUILTIN_TAG,
kGarbageCollectorEntryName)),
unresolved_entry_(profiles->NewCodeEntry(CodeEventListener::FUNCTION_TAG,
kUnresolvedFunctionName)) {}
void ProfileGenerator::RecordTickSample(const TickSample& sample) { void ProfileGenerator::RecordTickSample(const TickSample& sample) {
std::vector<CodeEntry*> entries; std::vector<CodeEntry*> entries;
...@@ -610,7 +610,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { ...@@ -610,7 +610,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// former case we don't so we simply replace the frame with // former case we don't so we simply replace the frame with
// 'unresolved' entry. // 'unresolved' entry.
if (!sample.has_external_callback) { if (!sample.has_external_callback) {
entries.push_back(unresolved_entry_); entries.push_back(CodeEntry::unresolved_entry());
} }
} }
} }
...@@ -667,7 +667,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) { ...@@ -667,7 +667,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) { switch (tag) {
case GC: case GC:
return gc_entry_; return CodeEntry::gc_entry();
case JS: case JS:
case COMPILER: case COMPILER:
// DOM events handlers are reported as OTHER / EXTERNAL entries. // DOM events handlers are reported as OTHER / EXTERNAL entries.
...@@ -675,9 +675,9 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { ...@@ -675,9 +675,9 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
// one bucket. // one bucket.
case OTHER: case OTHER:
case EXTERNAL: case EXTERNAL:
return program_entry_; return CodeEntry::program_entry();
case IDLE: case IDLE:
return idle_entry_; return CodeEntry::idle_entry();
default: return NULL; default: return NULL;
} }
} }
......
...@@ -114,7 +114,45 @@ class CodeEntry { ...@@ -114,7 +114,45 @@ class CodeEntry {
static const char* const kEmptyBailoutReason; static const char* const kEmptyBailoutReason;
static const char* const kNoDeoptReason; static const char* const kNoDeoptReason;
static const char* const kProgramEntryName;
static const char* const kIdleEntryName;
static const char* const kGarbageCollectorEntryName;
// Used to represent frames for which we have no reliable way to
// detect function.
static const char* const kUnresolvedFunctionName;
V8_INLINE static CodeEntry* program_entry() {
return kProgramEntry.Pointer();
}
V8_INLINE static CodeEntry* idle_entry() { return kIdleEntry.Pointer(); }
V8_INLINE static CodeEntry* gc_entry() { return kGCEntry.Pointer(); }
V8_INLINE static CodeEntry* unresolved_entry() {
return kUnresolvedEntry.Pointer();
}
private: private:
struct ProgramEntryCreateTrait {
static CodeEntry* Create();
};
struct IdleEntryCreateTrait {
static CodeEntry* Create();
};
struct GCEntryCreateTrait {
static CodeEntry* Create();
};
struct UnresolvedEntryCreateTrait {
static CodeEntry* Create();
};
static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type
kProgramEntry;
static base::LazyDynamicInstance<CodeEntry, IdleEntryCreateTrait>::type
kIdleEntry;
static base::LazyDynamicInstance<CodeEntry, GCEntryCreateTrait>::type
kGCEntry;
static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type
kUnresolvedEntry;
class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {}; class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
class BuiltinIdField : public BitField<Builtins::Name, 8, 24> {}; class BuiltinIdField : public BitField<Builtins::Name, 8, 24> {};
...@@ -300,29 +338,10 @@ class CpuProfilesCollection { ...@@ -300,29 +338,10 @@ class CpuProfilesCollection {
bool StartProfiling(const char* title, bool record_samples); bool StartProfiling(const char* title, bool record_samples);
CpuProfile* StopProfiling(const char* title); CpuProfile* StopProfiling(const char* title);
List<CpuProfile*>* profiles() { return &finished_profiles_; } List<CpuProfile*>* profiles() { return &finished_profiles_; }
const char* GetName(Name* name) { const char* GetName(Name* name) { return resource_names_.GetName(name); }
return function_and_resource_names_.GetName(name);
}
const char* GetName(int args_count) {
return function_and_resource_names_.GetName(args_count);
}
const char* GetFunctionName(Name* name) {
return function_and_resource_names_.GetFunctionName(name);
}
const char* GetFunctionName(const char* name) {
return function_and_resource_names_.GetFunctionName(name);
}
bool IsLastProfile(const char* title); bool IsLastProfile(const char* title);
void RemoveProfile(CpuProfile* profile); void RemoveProfile(CpuProfile* profile);
CodeEntry* NewCodeEntry(
CodeEventListener::LogEventsAndTags tag, const char* name,
const char* name_prefix = CodeEntry::kEmptyNamePrefix,
const char* resource_name = CodeEntry::kEmptyResourceName,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
JITLineInfoTable* line_info = NULL, Address instruction_start = NULL);
// Called from profile generator thread. // Called from profile generator thread.
void AddPathToCurrentProfiles(base::TimeTicks timestamp, void AddPathToCurrentProfiles(base::TimeTicks timestamp,
const std::vector<CodeEntry*>& path, const std::vector<CodeEntry*>& path,
...@@ -332,8 +351,7 @@ class CpuProfilesCollection { ...@@ -332,8 +351,7 @@ class CpuProfilesCollection {
static const int kMaxSimultaneousProfiles = 100; static const int kMaxSimultaneousProfiles = 100;
private: private:
StringsStorage function_and_resource_names_; StringsStorage resource_names_;
List<CodeEntry*> code_entries_;
List<CpuProfile*> finished_profiles_; List<CpuProfile*> finished_profiles_;
CpuProfiler* profiler_; CpuProfiler* profiler_;
...@@ -353,22 +371,11 @@ class ProfileGenerator { ...@@ -353,22 +371,11 @@ class ProfileGenerator {
CodeMap* code_map() { return &code_map_; } CodeMap* code_map() { return &code_map_; }
static const char* const kProgramEntryName;
static const char* const kIdleEntryName;
static const char* const kGarbageCollectorEntryName;
// Used to represent frames for which we have no reliable way to
// detect function.
static const char* const kUnresolvedFunctionName;
private: private:
CodeEntry* EntryForVMState(StateTag tag); CodeEntry* EntryForVMState(StateTag tag);
CpuProfilesCollection* profiles_; CpuProfilesCollection* profiles_;
CodeMap code_map_; CodeMap code_map_;
CodeEntry* program_entry_;
CodeEntry* idle_entry_;
CodeEntry* gc_entry_;
CodeEntry* unresolved_entry_;
DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
}; };
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/profiler/profiler-listener.h"
#include "src/deoptimizer.h"
#include "src/interpreter/source-position-table.h"
#include "src/profiler/cpu-profiler.h"
#include "src/profiler/profile-generator-inl.h"
namespace v8 {
namespace internal {
ProfilerListener::ProfilerListener(Isolate* isolate)
: function_and_resource_names_(isolate->heap()) {}
ProfilerListener::~ProfilerListener() {
for (auto code_entry : code_entries_) {
delete code_entry;
}
}
void ProfilerListener::CallbackEvent(Name* name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry = NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name));
rec->size = 1;
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, const char* name) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = NewCodeEntry(
tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, Name* name) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = NewCodeEntry(
tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix,
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code,
SharedFunctionInfo* shared,
Name* script_name) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = NewCodeEntry(
tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix,
GetName(InferScriptName(script_name, shared)),
CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->entry->FillFunctionInfo(shared);
rec->size = code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* abstract_code,
SharedFunctionInfo* shared,
Name* script_name, int line,
int column) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = abstract_code->address();
Script* script = Script::cast(shared->script());
JITLineInfoTable* line_table = NULL;
if (script) {
if (abstract_code->IsCode()) {
Code* code = abstract_code->GetCode();
int start_position = shared->start_position();
int end_position = shared->end_position();
line_table = new JITLineInfoTable();
for (RelocIterator it(code); !it.done(); it.next()) {
RelocInfo* reloc_info = it.rinfo();
if (!RelocInfo::IsPosition(reloc_info->rmode())) continue;
int position = static_cast<int>(reloc_info->data());
// TODO(alph): in case of inlining the position may correspond
// to an inlined function source code. Do not collect positions
// that fall beyond the function source code. There's however a
// chance the inlined function has similar positions but in another
// script. So the proper fix is to store script_id in some form
// along with the inlined function positions.
if (position < start_position || position >= end_position) continue;
int pc_offset = static_cast<int>(reloc_info->pc() - code->address());
int line_number = script->GetLineNumber(position) + 1;
line_table->SetPosition(pc_offset, line_number);
}
} else {
BytecodeArray* bytecode = abstract_code->GetBytecodeArray();
line_table = new JITLineInfoTable();
interpreter::SourcePositionTableIterator it(
bytecode->source_position_table());
for (; !it.done(); it.Advance()) {
int line_number = script->GetLineNumber(it.source_position()) + 1;
int pc_offset = it.bytecode_offset() + BytecodeArray::kHeaderSize;
line_table->SetPosition(pc_offset, line_number);
}
}
}
rec->entry = NewCodeEntry(
tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix,
GetName(InferScriptName(script_name, shared)), line, column, line_table,
abstract_code->instruction_start());
RecordInliningInfo(rec->entry, abstract_code);
RecordDeoptInlinedFrames(rec->entry, abstract_code);
rec->entry->FillFunctionInfo(shared);
rec->size = abstract_code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, int args_count) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = NewCodeEntry(
tag, GetName(args_count), "args_count: ", CodeEntry::kEmptyResourceName,
CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
NULL, code->instruction_start());
RecordInliningInfo(rec->entry, code);
rec->size = code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeMoveEvent(AbstractCode* from, Address to) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE);
CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
rec->from = from->address();
rec->to = to;
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT);
CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_;
rec->start = code->address();
rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason());
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::CodeDeoptEvent(Code* code, Address pc,
int fp_to_sp_delta) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
rec->start = code->address();
rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
rec->position = info.position;
rec->deopt_id = info.deopt_id;
rec->pc = reinterpret_cast<void*>(pc);
rec->fp_to_sp_delta = fp_to_sp_delta;
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry =
NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "get ");
rec->size = 1;
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code,
String* source) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = NewCodeEntry(
CodeEventListener::REG_EXP_TAG, GetName(source), "RegExp: ",
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
rec->size = code->ExecutableSize();
DispatchCodeEvent(evt_rec);
}
void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = entry_point;
rec->entry =
NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "set ");
rec->size = 1;
DispatchCodeEvent(evt_rec);
}
Name* ProfilerListener::InferScriptName(Name* name, SharedFunctionInfo* info) {
if (name->IsString() && String::cast(name)->length()) return name;
if (!info->script()->IsScript()) return name;
Object* source_url = Script::cast(info->script())->source_url();
return source_url->IsName() ? Name::cast(source_url) : name;
}
void ProfilerListener::RecordInliningInfo(CodeEntry* entry,
AbstractCode* abstract_code) {
if (!abstract_code->IsCode()) return;
Code* code = abstract_code->GetCode();
if (code->kind() != Code::OPTIMIZED_FUNCTION) return;
DeoptimizationInputData* deopt_input_data =
DeoptimizationInputData::cast(code->deoptimization_data());
int deopt_count = deopt_input_data->DeoptCount();
for (int i = 0; i < deopt_count; i++) {
int pc_offset = deopt_input_data->Pc(i)->value();
if (pc_offset == -1) continue;
int translation_index = deopt_input_data->TranslationIndex(i)->value();
TranslationIterator it(deopt_input_data->TranslationByteArray(),
translation_index);
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, opcode);
it.Skip(Translation::NumberOfOperandsFor(opcode));
int depth = 0;
std::vector<CodeEntry*> inline_stack;
while (it.HasNext() &&
Translation::BEGIN !=
(opcode = static_cast<Translation::Opcode>(it.Next()))) {
if (opcode != Translation::JS_FRAME &&
opcode != Translation::INTERPRETED_FRAME) {
it.Skip(Translation::NumberOfOperandsFor(opcode));
continue;
}
it.Next(); // Skip ast_id
int shared_info_id = it.Next();
it.Next(); // Skip height
SharedFunctionInfo* shared_info = SharedFunctionInfo::cast(
deopt_input_data->LiteralArray()->get(shared_info_id));
if (!depth++) continue; // Skip the current function itself.
CodeEntry* inline_entry = new CodeEntry(
entry->tag(), GetFunctionName(shared_info->DebugName()),
CodeEntry::kEmptyNamePrefix, entry->resource_name(),
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
inline_entry->FillFunctionInfo(shared_info);
inline_stack.push_back(inline_entry);
}
if (!inline_stack.empty()) {
entry->AddInlineStack(pc_offset, inline_stack);
DCHECK(inline_stack.empty());
}
}
}
void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry,
AbstractCode* abstract_code) {
if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return;
Code* code = abstract_code->GetCode();
DeoptimizationInputData* deopt_input_data =
DeoptimizationInputData::cast(code->deoptimization_data());
int const mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID);
for (RelocIterator rit(code, mask); !rit.done(); rit.next()) {
RelocInfo* reloc_info = rit.rinfo();
DCHECK(RelocInfo::IsDeoptId(reloc_info->rmode()));
int deopt_id = static_cast<int>(reloc_info->data());
int translation_index =
deopt_input_data->TranslationIndex(deopt_id)->value();
TranslationIterator it(deopt_input_data->TranslationByteArray(),
translation_index);
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, opcode);
it.Skip(Translation::NumberOfOperandsFor(opcode));
std::vector<CodeEntry::DeoptInlinedFrame> inlined_frames;
while (it.HasNext() &&
Translation::BEGIN !=
(opcode = static_cast<Translation::Opcode>(it.Next()))) {
if (opcode != Translation::JS_FRAME &&
opcode != Translation::INTERPRETED_FRAME) {
it.Skip(Translation::NumberOfOperandsFor(opcode));
continue;
}
BailoutId ast_id = BailoutId(it.Next());
int shared_info_id = it.Next();
it.Next(); // Skip height
SharedFunctionInfo* shared = SharedFunctionInfo::cast(
deopt_input_data->LiteralArray()->get(shared_info_id));
int source_position = Deoptimizer::ComputeSourcePosition(shared, ast_id);
int script_id = v8::UnboundScript::kNoScriptId;
if (shared->script()->IsScript()) {
Script* script = Script::cast(shared->script());
script_id = script->id();
}
CodeEntry::DeoptInlinedFrame frame = {source_position, script_id};
inlined_frames.push_back(frame);
}
if (!inlined_frames.empty() && !entry->HasDeoptInlinedFramesFor(deopt_id)) {
entry->AddDeoptInlinedFrames(deopt_id, inlined_frames);
DCHECK(inlined_frames.empty());
}
}
}
CodeEntry* ProfilerListener::NewCodeEntry(
CodeEventListener::LogEventsAndTags tag, const char* name,
const char* name_prefix, const char* resource_name, int line_number,
int column_number, JITLineInfoTable* line_info, Address instruction_start) {
CodeEntry* code_entry =
new CodeEntry(tag, name, name_prefix, resource_name, line_number,
column_number, line_info, instruction_start);
code_entries_.push_back(code_entry);
return code_entry;
}
void ProfilerListener::AddObserver(CodeEventObserver* observer) {
if (std::find(observers_.begin(), observers_.end(), observer) !=
observers_.end())
return;
observers_.push_back(observer);
}
void ProfilerListener::RemoveObserver(CodeEventObserver* observer) {
auto it = std::find(observers_.begin(), observers_.end(), observer);
if (it == observers_.end()) return;
observers_.erase(it);
}
} // namespace internal
} // namespace v8
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_PROFILER_PROFILER_LISTENER_H_
#define V8_PROFILER_PROFILER_LISTENER_H_
#include <vector>
#include "src/code-events.h"
#include "src/profiler/profile-generator.h"
namespace v8 {
namespace internal {
class CodeEventsContainer;
class CodeEventObserver {
public:
virtual void CodeEventHandler(const CodeEventsContainer& evt_rec) = 0;
virtual ~CodeEventObserver() {}
};
class ProfilerListener : public CodeEventListener {
public:
explicit ProfilerListener(Isolate* isolate);
~ProfilerListener() override;
void CallbackEvent(Name* name, Address entry_point) override;
void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, const char* comment) override;
void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, Name* name) override;
void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, SharedFunctionInfo* shared,
Name* script_name) override;
void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, SharedFunctionInfo* shared,
Name* script_name, int line, int column) override;
void CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
AbstractCode* code, int args_count) override;
void CodeMovingGCEvent() override {}
void CodeMoveEvent(AbstractCode* from, Address to) override;
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override;
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) override;
void GetterCallbackEvent(Name* name, Address entry_point) override;
void RegExpCodeCreateEvent(AbstractCode* code, String* source) override;
void SetterCallbackEvent(Name* name, Address entry_point) override;
void SharedFunctionInfoMoveEvent(Address from, Address to) override {}
CodeEntry* NewCodeEntry(
CodeEventListener::LogEventsAndTags tag, const char* name,
const char* name_prefix = CodeEntry::kEmptyNamePrefix,
const char* resource_name = CodeEntry::kEmptyResourceName,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
JITLineInfoTable* line_info = NULL, Address instruction_start = NULL);
void AddObserver(CodeEventObserver* observer);
void RemoveObserver(CodeEventObserver* observer);
V8_INLINE bool HasObservers() { return !observers_.empty(); }
const char* GetName(Name* name) {
return function_and_resource_names_.GetName(name);
}
const char* GetName(int args_count) {
return function_and_resource_names_.GetName(args_count);
}
const char* GetFunctionName(Name* name) {
return function_and_resource_names_.GetFunctionName(name);
}
const char* GetFunctionName(const char* name) {
return function_and_resource_names_.GetFunctionName(name);
}
private:
void RecordInliningInfo(CodeEntry* entry, AbstractCode* abstract_code);
void RecordDeoptInlinedFrames(CodeEntry* entry, AbstractCode* abstract_code);
Name* InferScriptName(Name* name, SharedFunctionInfo* info);
V8_INLINE void DispatchCodeEvent(const CodeEventsContainer& evt_rec) {
for (auto observer : observers_) {
observer->CodeEventHandler(evt_rec);
}
}
StringsStorage function_and_resource_names_;
std::vector<CodeEntry*> code_entries_;
std::vector<CodeEventObserver*> observers_;
DISALLOW_COPY_AND_ASSIGN(ProfilerListener);
};
} // namespace internal
} // namespace v8
#endif // V8_PROFILER_PROFILER_LISTENER_H_
...@@ -1002,6 +1002,8 @@ ...@@ -1002,6 +1002,8 @@
'profiler/heap-snapshot-generator-inl.h', 'profiler/heap-snapshot-generator-inl.h',
'profiler/heap-snapshot-generator.cc', 'profiler/heap-snapshot-generator.cc',
'profiler/heap-snapshot-generator.h', 'profiler/heap-snapshot-generator.h',
'profiler/profiler-listener.cc',
'profiler/profiler-listener.h',
'profiler/profile-generator-inl.h', 'profiler/profile-generator-inl.h',
'profiler/profile-generator.cc', 'profiler/profile-generator.cc',
'profiler/profile-generator.h', 'profiler/profile-generator.h',
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "src/base/platform/platform.h" #include "src/base/platform/platform.h"
#include "src/deoptimizer.h" #include "src/deoptimizer.h"
#include "src/profiler/cpu-profiler-inl.h" #include "src/profiler/cpu-profiler-inl.h"
#include "src/profiler/profiler-listener.h"
#include "src/utils.h" #include "src/utils.h"
#include "test/cctest/cctest.h" #include "test/cctest/cctest.h"
#include "test/cctest/profiler-extension.h" #include "test/cctest/profiler-extension.h"
...@@ -45,6 +46,7 @@ using i::Heap; ...@@ -45,6 +46,7 @@ using i::Heap;
using i::ProfileGenerator; using i::ProfileGenerator;
using i::ProfileNode; using i::ProfileNode;
using i::ProfilerEventsProcessor; using i::ProfilerEventsProcessor;
using i::ProfilerListener;
using i::ScopedVector; using i::ScopedVector;
using i::Vector; using i::Vector;
...@@ -158,24 +160,29 @@ TEST(CodeEvents) { ...@@ -158,24 +160,29 @@ TEST(CodeEvents) {
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
ProfilerListener profiler_listener(isolate);
isolate->code_event_dispatcher()->AddListener(&profiler_listener);
profiler_listener.AddObserver(&profiler);
// Enqueue code creation events. // Enqueue code creation events.
const char* aaa_str = "aaa"; const char* aaa_str = "aaa";
i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str); i::Handle<i::String> aaa_name = factory->NewStringFromAsciiChecked(aaa_str);
profiler.CodeCreateEvent(i::CodeEventListener::FUNCTION_TAG, aaa_code, profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, aaa_code,
*aaa_name); *aaa_name);
profiler.CodeCreateEvent(i::CodeEventListener::BUILTIN_TAG, comment_code, profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment_code,
"comment"); "comment");
profiler.CodeCreateEvent(i::CodeEventListener::STUB_TAG, args5_code, 5); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args5_code, 5);
profiler.CodeCreateEvent(i::CodeEventListener::BUILTIN_TAG, comment2_code, profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, comment2_code,
"comment2"); "comment2");
profiler.CodeMoveEvent(comment2_code, moved_code->address()); profiler_listener.CodeMoveEvent(comment2_code, moved_code->address());
profiler.CodeCreateEvent(i::CodeEventListener::STUB_TAG, args3_code, 3); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args3_code, 3);
profiler.CodeCreateEvent(i::CodeEventListener::STUB_TAG, args4_code, 4); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, args4_code, 4);
// Enqueue a tick event to enable code events processing. // Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(processor, aaa_code->address()); EnqueueTickSampleEvent(processor, aaa_code->address());
profiler_listener.RemoveObserver(&profiler);
isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
processor->StopSynchronously(); processor->StopSynchronously();
// Check the state of profile generator. // Check the state of profile generator.
...@@ -221,12 +228,13 @@ TEST(TickEvents) { ...@@ -221,12 +228,13 @@ TEST(TickEvents) {
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
ProfilerListener profiler_listener(isolate);
isolate->code_event_dispatcher()->AddListener(&profiler_listener);
profiler_listener.AddObserver(&profiler);
profiler.CodeCreateEvent(i::CodeEventListener::BUILTIN_TAG, frame1_code, profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
"bbb"); profiler_listener.CodeCreateEvent(i::Logger::STUB_TAG, frame2_code, 5);
profiler.CodeCreateEvent(i::CodeEventListener::STUB_TAG, frame2_code, 5); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame3_code, "ddd");
profiler.CodeCreateEvent(i::CodeEventListener::BUILTIN_TAG, frame3_code,
"ddd");
EnqueueTickSampleEvent(processor, frame1_code->instruction_start()); EnqueueTickSampleEvent(processor, frame1_code->instruction_start());
EnqueueTickSampleEvent( EnqueueTickSampleEvent(
...@@ -237,6 +245,8 @@ TEST(TickEvents) { ...@@ -237,6 +245,8 @@ TEST(TickEvents) {
frame2_code->instruction_end() - 1, frame2_code->instruction_end() - 1,
frame1_code->instruction_end() - 1); frame1_code->instruction_end() - 1);
profiler_listener.RemoveObserver(&profiler);
isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
processor->StopSynchronously(); processor->StopSynchronously();
CpuProfile* profile = profiles->StopProfiling(""); CpuProfile* profile = profiles->StopProfiling("");
CHECK(profile); CHECK(profile);
...@@ -257,6 +267,8 @@ TEST(TickEvents) { ...@@ -257,6 +267,8 @@ TEST(TickEvents) {
const i::List<ProfileNode*>* top_down_ddd_children = const i::List<ProfileNode*>* top_down_ddd_children =
top_down_stub_children->last()->children(); top_down_stub_children->last()->children();
CHECK_EQ(0, top_down_ddd_children->length()); CHECK_EQ(0, top_down_ddd_children->length());
isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
} }
// http://crbug/51594 // http://crbug/51594
...@@ -288,8 +300,11 @@ TEST(Issue1398) { ...@@ -288,8 +300,11 @@ TEST(Issue1398) {
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
ProfilerListener profiler_listener(isolate);
isolate->code_event_dispatcher()->AddListener(&profiler_listener);
profiler_listener.AddObserver(&profiler);
profiler.CodeCreateEvent(i::CodeEventListener::BUILTIN_TAG, code, "bbb"); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
i::TickSample* sample = processor->StartTickSample(); i::TickSample* sample = processor->StartTickSample();
sample->pc = code->address(); sample->pc = code->address();
...@@ -300,6 +315,8 @@ TEST(Issue1398) { ...@@ -300,6 +315,8 @@ TEST(Issue1398) {
} }
processor->FinishTickSample(); processor->FinishTickSample();
profiler_listener.RemoveObserver(&profiler);
isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
processor->StopSynchronously(); processor->StopSynchronously();
CpuProfile* profile = profiles->StopProfiling(""); CpuProfile* profile = profiles->StopProfiling("");
CHECK(profile); CHECK(profile);
...@@ -1026,17 +1043,22 @@ static void TickLines(bool optimize) { ...@@ -1026,17 +1043,22 @@ static void TickLines(bool optimize) {
CpuProfiler profiler(isolate, profiles, generator, processor); CpuProfiler profiler(isolate, profiles, generator, processor);
profiles->StartProfiling("", false); profiles->StartProfiling("", false);
processor->Start(); processor->Start();
ProfilerListener profiler_listener(isolate);
isolate->code_event_dispatcher()->AddListener(&profiler_listener);
profiler_listener.AddObserver(&profiler);
// Enqueue code creation events. // Enqueue code creation events.
i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name); i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
int line = 1; int line = 1;
int column = 1; int column = 1;
profiler.CodeCreateEvent(i::CodeEventListener::FUNCTION_TAG, code, profiler_listener.CodeCreateEvent(i::Logger::FUNCTION_TAG, code,
func->shared(), *str, line, column); func->shared(), *str, line, column);
// Enqueue a tick event to enable code events processing. // Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(processor, code_address); EnqueueTickSampleEvent(processor, code_address);
profiler_listener.RemoveObserver(&profiler);
isolate->code_event_dispatcher()->RemoveListener(&profiler_listener);
processor->StopSynchronously(); processor->StopSynchronously();
CpuProfile* profile = profiles->StopProfiling(""); CpuProfile* profile = profiles->StopProfiling("");
...@@ -1129,8 +1151,8 @@ TEST(FunctionCallSample) { ...@@ -1129,8 +1151,8 @@ TEST(FunctionCallSample) {
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start"); const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "bar"); GetChild(env.local(), start_node, "bar");
const v8::CpuProfileNode* unresolved_node = FindChild( const v8::CpuProfileNode* unresolved_node =
env.local(), root, i::ProfileGenerator::kUnresolvedFunctionName); FindChild(env.local(), root, i::CodeEntry::kUnresolvedFunctionName);
CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call")); CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "call"));
profile->Delete(); profile->Delete();
...@@ -1185,8 +1207,8 @@ TEST(FunctionApplySample) { ...@@ -1185,8 +1207,8 @@ TEST(FunctionApplySample) {
GetChild(env.local(), start_node, "test"); GetChild(env.local(), start_node, "test");
GetChild(env.local(), test_node, "bar"); GetChild(env.local(), test_node, "bar");
const v8::CpuProfileNode* unresolved_node = FindChild( const v8::CpuProfileNode* unresolved_node =
env.local(), start_node, ProfileGenerator::kUnresolvedFunctionName); FindChild(env.local(), start_node, CodeEntry::kUnresolvedFunctionName);
CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply")); CHECK(!unresolved_node || GetChild(env.local(), unresolved_node, "apply"));
profile->Delete(); profile->Delete();
...@@ -1593,12 +1615,12 @@ TEST(IdleTime) { ...@@ -1593,12 +1615,12 @@ TEST(IdleTime) {
const v8::CpuProfileNode* root = profile->GetTopDownRoot(); const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* program_node = const v8::CpuProfileNode* program_node =
GetChild(env.local(), root, ProfileGenerator::kProgramEntryName); GetChild(env.local(), root, CodeEntry::kProgramEntryName);
CHECK_EQ(0, program_node->GetChildrenCount()); CHECK_EQ(0, program_node->GetChildrenCount());
CHECK_GE(program_node->GetHitCount(), 2u); CHECK_GE(program_node->GetHitCount(), 2u);
const v8::CpuProfileNode* idle_node = const v8::CpuProfileNode* idle_node =
GetChild(env.local(), root, ProfileGenerator::kIdleEntryName); GetChild(env.local(), root, CodeEntry::kIdleEntryName);
CHECK_EQ(0, idle_node->GetChildrenCount()); CHECK_EQ(0, idle_node->GetChildrenCount());
CHECK_GE(idle_node->GetHitCount(), 3u); CHECK_GE(idle_node->GetHitCount(), 3u);
......
...@@ -348,12 +348,9 @@ TEST(RecordTickSample) { ...@@ -348,12 +348,9 @@ TEST(RecordTickSample) {
profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler()); profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler());
profiles.StartProfiling("", false); profiles.StartProfiling("", false);
ProfileGenerator generator(&profiles); ProfileGenerator generator(&profiles);
CodeEntry* entry1 = CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry2 = CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* entry3 =
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100); generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50); generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
...@@ -401,6 +398,10 @@ TEST(RecordTickSample) { ...@@ -401,6 +398,10 @@ TEST(RecordTickSample) {
ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1); ProfileNode* node4 = top_down_test_helper.Walk(entry1, entry3, entry1);
CHECK(node4); CHECK(node4);
CHECK_EQ(entry1, node4->entry()); CHECK_EQ(entry1, node4->entry());
delete entry1;
delete entry2;
delete entry3;
} }
...@@ -418,12 +419,9 @@ TEST(SampleIds) { ...@@ -418,12 +419,9 @@ TEST(SampleIds) {
profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler()); profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler());
profiles.StartProfiling("", true); profiles.StartProfiling("", true);
ProfileGenerator generator(&profiles); ProfileGenerator generator(&profiles);
CodeEntry* entry1 = CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry2 = CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* entry3 =
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100); generator.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50); generator.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
...@@ -464,6 +462,10 @@ TEST(SampleIds) { ...@@ -464,6 +462,10 @@ TEST(SampleIds) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
CHECK_EQ(expected_id[i], profile->sample(i)->id()); CHECK_EQ(expected_id[i], profile->sample(i)->id());
} }
delete entry1;
delete entry2;
delete entry3;
} }
...@@ -473,8 +475,7 @@ TEST(NoSamples) { ...@@ -473,8 +475,7 @@ TEST(NoSamples) {
profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler()); profiles.set_cpu_profiler(CcTest::i_isolate()->cpu_profiler());
profiles.StartProfiling("", false); profiles.StartProfiling("", false);
ProfileGenerator generator(&profiles); ProfileGenerator generator(&profiles);
CodeEntry* entry1 = CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
profiles.NewCodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); generator.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
// We are building the following calls tree: // We are building the following calls tree:
...@@ -491,6 +492,8 @@ TEST(NoSamples) { ...@@ -491,6 +492,8 @@ TEST(NoSamples) {
CHECK_EQ(3u, nodeId - 1); CHECK_EQ(3u, nodeId - 1);
CHECK_EQ(0, profile->samples_count()); CHECK_EQ(0, profile->samples_count());
delete entry1;
} }
......
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