Commit 08c40baa authored by yurys@chromium.org's avatar yurys@chromium.org

Revert of Extend CPU profiler with mapping ticks to source lines (patchset #3...

Revert of Extend CPU profiler with mapping ticks to source lines (patchset #3 id:40001 of https://codereview.chromium.org/616963005/)

Reason for revert:
It broke layout test fast/events/window-onerror-02.html, error column reported by window.onerror is now wrong (I believe it is because of the change in full-codegen):

http://build.chromium.org/p/client.v8/builders/V8-Blink%20Linux%2064%20%28dbg%29/builds/652

Original issue's description:
> Extend CPU profiler with mapping ticks to source lines
>
> The idea behind of this solution is to use the existing "relocation info" instead of consumption the CodeLinePosition events emitted by the V8 compilers.
> During generation code and relocation info are generated simultaneously.
> When code generation is done you each code object has associated "relocation info".
> Relocation information lets V8 to mark interesting places in the generated code: the pointers that might need to be relocated (after garbage collection),
> correspondences between the machine program counter and source locations for stack walking.
>
> This patch:
> 1. Add more source positions info in reloc info to make it suitable for source level mapping.
> The amount of data should not be increased dramatically because (1) V8 already marks interesting places in the generated code and
> (2) V8 does not write redundant information (it writes a pair (pc_offset, pos) only if pos is changed and skips other).
> I measured it on Octane benchmark - for unoptimized code the number of source positions may achieve 2x ('lin_solve' from NavierStokes benchmark).
>
> 2. When a sample happens, CPU profiler finds a code object by pc, then use its reloc info to match the sample to a source line.
> If a source line is found that hit counter is increased by one for this line.
>
> 3. Add a new public V8 API to get the hit source lines by CDT CPU profiler.
> Note that it's expected a minor patch in Blink to pack the source level info in JSON to be shown.
>
> 4.Add a test that checks how the samples are distributed through source lines.
> It tests two cases: (1) relocation info created during code generation and (2) relocation info associated with precompiled function's version.
>
> Patch from Denis Pravdin <denis.pravdin@intel.com>
> BUG=None
> LOG=Y
> R=svenpanne@chromium.org
>
> Committed: https://code.google.com/p/v8/source/detail?r=24389

TBR=svenpanne@chromium.org,danno@chromium.org,alph@chromium.org,denis.pravdin@intel.com,weiliang.lin@intel.com
BUG=None
LOG=N

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24394 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 53454d95
......@@ -22,14 +22,6 @@ typedef uint32_t SnapshotObjectId;
*/
class V8_EXPORT CpuProfileNode {
public:
struct LineTick {
/** The 1-based number of the source line where the function originates. */
int line;
/** The count of samples associated with the source line. */
unsigned int hit_count;
};
/** Returns function name (empty string for anonymous functions.) */
Handle<String> GetFunctionName() const;
......@@ -51,18 +43,6 @@ class V8_EXPORT CpuProfileNode {
*/
int GetColumnNumber() const;
/**
* Returns the number of the function's source lines that collect the samples.
*/
unsigned int GetHitLineCount() const;
/** Returns the set of source lines that collect the samples.
* The caller allocates buffer and responsible for releasing it.
* True if all available entries are copied, otherwise false.
* The function copies nothing if buffer is not large enough.
*/
bool GetLineTicks(LineTick* entries, unsigned int length) const;
/** Returns bailout reason for the function
* if the optimization was disabled for it.
*/
......
......@@ -7114,19 +7114,6 @@ int CpuProfileNode::GetColumnNumber() const {
}
unsigned int CpuProfileNode::GetHitLineCount() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
return node->GetHitLineCount();
}
bool CpuProfileNode::GetLineTicks(LineTick* entries,
unsigned int length) const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
return node->GetLineTicks(entries, length);
}
const char* CpuProfileNode::GetBailoutReason() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
return node->entry()->bailout_reason();
......
......@@ -201,10 +201,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
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());
rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
......@@ -218,10 +215,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
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());
rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name));
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
......@@ -237,9 +231,7 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(shared->DebugName()),
CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name),
CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo,
NULL, code->instruction_start());
CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name));
if (info) {
rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
}
......@@ -264,29 +256,15 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, Code* code,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
Script* script = Script::cast(shared->script());
JITLineInfoTable* line_table = NULL;
if (script) {
line_table = new JITLineInfoTable();
for (RelocIterator it(code); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (RelocInfo::IsPosition(mode)) {
int position = static_cast<int>(it.rinfo()->data());
if (position >= 0) {
int pc_offset = static_cast<int>(it.rinfo()->pc() - code->address());
int line_number = script->GetLineNumber(position) + 1;
line_table->SetPosition(pc_offset, line_number);
}
}
}
}
rec->entry = profiles_->NewCodeEntry(
tag, profiles_->GetFunctionName(shared->DebugName()),
CodeEntry::kEmptyNamePrefix, profiles_->GetName(script_name), line,
column, line_table, code->instruction_start());
column);
if (info) {
rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges());
}
DCHECK(Script::cast(shared->script()));
Script* script = Script::cast(shared->script());
rec->entry->set_script_id(script->id()->value());
rec->size = code->ExecutableSize();
rec->shared = shared->address();
......@@ -304,9 +282,9 @@ void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
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());
tag,
profiles_->GetName(args_count),
"args_count: ");
rec->size = code->ExecutableSize();
rec->shared = NULL;
processor_->Enqueue(evt_rec);
......@@ -366,9 +344,9 @@ void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->start = code->address();
rec->entry = profiles_->NewCodeEntry(
Logger::REG_EXP_TAG, profiles_->GetName(source), "RegExp: ",
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start());
Logger::REG_EXP_TAG,
profiles_->GetName(source),
"RegExp: ");
rec->size = code->ExecutableSize();
processor_->Enqueue(evt_rec);
}
......
......@@ -866,7 +866,6 @@ void FullCodeGenerator::SetExpressionPosition(Expression* expr) {
void FullCodeGenerator::SetSourcePosition(int pos) {
if (pos != RelocInfo::kNoPosition) {
masm_->positions_recorder()->RecordPosition(pos);
masm_->positions_recorder()->WriteRecordedPositions();
}
}
......
......@@ -10,10 +10,12 @@
namespace v8 {
namespace internal {
CodeEntry::CodeEntry(Logger::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::CodeEntry(Logger::LogEventsAndTags tag,
const char* name,
const char* name_prefix,
const char* resource_name,
int line_number,
int column_number)
: tag_(tag),
builtin_id_(Builtins::builtin_count),
name_prefix_(name_prefix),
......@@ -24,9 +26,7 @@ CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, const char* name,
shared_id_(0),
script_id_(v8::UnboundScript::kNoScriptId),
no_frame_ranges_(NULL),
bailout_reason_(kEmptyBailoutReason),
line_info_(line_info),
instruction_start_(instruction_start) {}
bailout_reason_(kEmptyBailoutReason) { }
bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) {
......@@ -39,16 +39,13 @@ bool CodeEntry::is_js_function_tag(Logger::LogEventsAndTags tag) {
}
static bool LineTickMatch(void* a, void* b) { return a == b; }
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry)
: tree_(tree),
entry_(entry),
self_ticks_(0),
children_(CodeEntriesMatch),
id_(tree->next_node_id()),
line_ticks_(LineTickMatch) {}
id_(tree->next_node_id()) { }
} } // namespace v8::internal
#endif // V8_PROFILE_GENERATOR_INL_H_
......@@ -132,30 +132,6 @@ HashMap::Entry* StringsStorage::GetEntry(const char* str, int len) {
}
JITLineInfoTable::JITLineInfoTable() {}
JITLineInfoTable::~JITLineInfoTable() {}
void JITLineInfoTable::SetPosition(int pc_offset, int line) {
DCHECK(pc_offset >= 0);
DCHECK(line > 0); // The 1-based number of the source line.
if (GetSourceLineNumber(pc_offset) != line) {
pc_offset_map_.insert(std::make_pair(pc_offset, line));
}
}
int JITLineInfoTable::GetSourceLineNumber(int pc_offset) const {
PcOffsetMap::const_iterator it = pc_offset_map_.lower_bound(pc_offset);
if (it == pc_offset_map_.end()) {
if (pc_offset_map_.empty()) return v8::CpuProfileNode::kNoLineNumberInfo;
return (--pc_offset_map_.end())->second;
}
return it->second;
}
const char* const CodeEntry::kEmptyNamePrefix = "";
const char* const CodeEntry::kEmptyResourceName = "";
const char* const CodeEntry::kEmptyBailoutReason = "";
......@@ -163,7 +139,6 @@ const char* const CodeEntry::kEmptyBailoutReason = "";
CodeEntry::~CodeEntry() {
delete no_frame_ranges_;
delete line_info_;
}
......@@ -206,14 +181,6 @@ void CodeEntry::SetBuiltinId(Builtins::Name id) {
}
int CodeEntry::GetSourceLine(int pc_offset) const {
if (line_info_ && !line_info_->empty()) {
return line_info_->GetSourceLineNumber(pc_offset);
}
return v8::CpuProfileNode::kNoLineNumberInfo;
}
ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
HashMap::Entry* map_entry =
children_.Lookup(entry, CodeEntryHash(entry), false);
......@@ -235,40 +202,6 @@ ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
}
void ProfileNode::IncrementLineTicks(int src_line) {
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return;
// Increment a hit counter of a certain source line.
// Add a new source line if not found.
HashMap::Entry* e =
line_ticks_.Lookup(reinterpret_cast<void*>(src_line), src_line, true);
DCHECK(e);
e->value = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(e->value) + 1);
}
bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
unsigned int length) const {
if (entries == NULL || length == 0) return false;
unsigned line_count = line_ticks_.occupancy();
if (line_count == 0) return true;
if (length < line_count) return false;
v8::CpuProfileNode::LineTick* entry = entries;
for (HashMap::Entry* p = line_ticks_.Start(); p != NULL;
p = line_ticks_.Next(p), entry++) {
entry->line =
static_cast<unsigned int>(reinterpret_cast<uintptr_t>(p->key));
entry->hit_count =
static_cast<unsigned int>(reinterpret_cast<uintptr_t>(p->value));
}
return true;
}
void ProfileNode::Print(int indent) {
base::OS::Print("%5u %*s %s%s %d #%d %s", self_ticks_, indent, "",
entry_->name_prefix(), entry_->name(), entry_->script_id(),
......@@ -309,8 +242,7 @@ ProfileTree::~ProfileTree() {
}
ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path,
int src_line) {
ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
ProfileNode* node = root_;
for (CodeEntry** entry = path.start() + path.length() - 1;
entry != path.start() - 1;
......@@ -320,15 +252,11 @@ ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path,
}
}
node->IncrementSelfTicks();
if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) {
node->IncrementLineTicks(src_line);
}
return node;
}
void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path,
int src_line) {
void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
ProfileNode* node = root_;
for (CodeEntry** entry = path.start();
entry != path.start() + path.length();
......@@ -338,9 +266,6 @@ void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path,
}
}
node->IncrementSelfTicks();
if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) {
node->IncrementLineTicks(src_line);
}
}
......@@ -402,8 +327,8 @@ CpuProfile::CpuProfile(const char* title, bool record_samples)
void CpuProfile::AddPath(base::TimeTicks timestamp,
const Vector<CodeEntry*>& path, int src_line) {
ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path, src_line);
const Vector<CodeEntry*>& path) {
ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path);
if (record_samples_) {
timestamps_.Add(timestamp);
samples_.Add(top_frame_node);
......@@ -592,25 +517,31 @@ void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
void CpuProfilesCollection::AddPathToCurrentProfiles(
base::TimeTicks timestamp, const Vector<CodeEntry*>& path, int src_line) {
base::TimeTicks timestamp, const Vector<CodeEntry*>& path) {
// As starting / stopping profiles is rare relatively to this
// method, we don't bother minimizing the duration of lock holding,
// e.g. copying contents of the list to a local vector.
current_profiles_semaphore_.Wait();
for (int i = 0; i < current_profiles_.length(); ++i) {
current_profiles_[i]->AddPath(timestamp, path, src_line);
current_profiles_[i]->AddPath(timestamp, path);
}
current_profiles_semaphore_.Signal();
}
CodeEntry* CpuProfilesCollection::NewCodeEntry(
Logger::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);
Logger::LogEventsAndTags tag,
const char* name,
const char* name_prefix,
const char* resource_name,
int line_number,
int column_number) {
CodeEntry* code_entry = new CodeEntry(tag,
name,
name_prefix,
resource_name,
line_number,
column_number);
code_entries_.Add(code_entry);
return code_entry;
}
......@@ -648,15 +579,6 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// entries vector with NULL values.
CodeEntry** entry = entries.start();
memset(entry, 0, entries.length() * sizeof(*entry));
// The ProfileNode knows nothing about all versions of generated code for
// the same JS function. The line number information associated with
// the latest version of generated code is used to find a source line number
// for a JS function. Then, the detected source line is passed to
// ProfileNode to increase the tick count for this source line.
int src_line = v8::CpuProfileNode::kNoLineNumberInfo;
bool src_line_not_found = true;
if (sample.pc != NULL) {
if (sample.has_external_callback && sample.state == EXTERNAL &&
sample.top_frame_type == StackFrame::EXIT) {
......@@ -673,9 +595,10 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// frame. Check for this case and just skip such samples.
if (pc_entry) {
List<OffsetRange>* ranges = pc_entry->no_frame_ranges();
int pc_offset =
static_cast<int>(sample.pc - pc_entry->instruction_start());
if (ranges) {
Code* code = Code::cast(HeapObject::FromAddress(start));
int pc_offset = static_cast<int>(
sample.pc - code->instruction_start());
for (int i = 0; i < ranges->length(); i++) {
OffsetRange& range = ranges->at(i);
if (range.from <= pc_offset && pc_offset < range.to) {
......@@ -683,11 +606,6 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
}
}
src_line = pc_entry->GetSourceLine(pc_offset);
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) {
src_line = pc_entry->line_number();
}
src_line_not_found = false;
*entry++ = pc_entry;
if (pc_entry->builtin_id() == Builtins::kFunctionCall ||
......@@ -708,22 +626,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
*stack_end = stack_pos + sample.frames_count;
stack_pos != stack_end;
++stack_pos) {
Address start = NULL;
*entry = code_map_.FindEntry(*stack_pos, &start);
// Skip unresolved frames (e.g. internal frame) and get source line of
// the first JS caller.
if (src_line_not_found && *entry) {
int pc_offset =
static_cast<int>(*stack_pos - (*entry)->instruction_start());
src_line = (*entry)->GetSourceLine(pc_offset);
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) {
src_line = (*entry)->line_number();
}
src_line_not_found = false;
}
entry++;
*entry++ = code_map_.FindEntry(*stack_pos);
}
}
......@@ -741,7 +644,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
}
profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line);
profiles_->AddPathToCurrentProfiles(sample.timestamp, entries);
}
......
......@@ -5,7 +5,6 @@
#ifndef V8_PROFILE_GENERATOR_H_
#define V8_PROFILE_GENERATOR_H_
#include <map>
#include "include/v8-profiler.h"
#include "src/allocation.h"
#include "src/hashmap.h"
......@@ -45,35 +44,15 @@ class StringsStorage {
};
// Provides a mapping from the offsets within generated code to
// the source line.
class JITLineInfoTable : public Malloced {
public:
JITLineInfoTable();
~JITLineInfoTable();
void SetPosition(int pc_offset, int line);
int GetSourceLineNumber(int pc_offset) const;
bool empty() const { return pc_offset_map_.empty(); }
private:
// pc_offset -> source line
typedef std::map<int, int> PcOffsetMap;
PcOffsetMap pc_offset_map_;
DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
};
class CodeEntry {
public:
// CodeEntry doesn't own name strings, just references them.
inline CodeEntry(Logger::LogEventsAndTags tag, const char* name,
inline CodeEntry(Logger::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);
int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);
~CodeEntry();
bool is_js_function() const { return is_js_function_tag(tag_); }
......@@ -83,7 +62,6 @@ class CodeEntry {
const char* resource_name() const { return resource_name_; }
int line_number() const { return line_number_; }
int column_number() const { return column_number_; }
const JITLineInfoTable* line_info() const { return line_info_; }
void set_shared_id(int shared_id) { shared_id_ = shared_id; }
int script_id() const { return script_id_; }
void set_script_id(int script_id) { script_id_ = script_id; }
......@@ -105,10 +83,6 @@ class CodeEntry {
uint32_t GetCallUid() const;
bool IsSameAs(CodeEntry* entry) const;
int GetSourceLine(int pc_offset) const;
Address instruction_start() const { return instruction_start_; }
static const char* const kEmptyNamePrefix;
static const char* const kEmptyResourceName;
static const char* const kEmptyBailoutReason;
......@@ -125,8 +99,6 @@ class CodeEntry {
int script_id_;
List<OffsetRange>* no_frame_ranges_;
const char* bailout_reason_;
JITLineInfoTable* line_info_;
Address instruction_start_;
DISALLOW_COPY_AND_ASSIGN(CodeEntry);
};
......@@ -142,15 +114,11 @@ class ProfileNode {
ProfileNode* FindOrAddChild(CodeEntry* entry);
void IncrementSelfTicks() { ++self_ticks_; }
void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
void IncrementLineTicks(int src_line);
CodeEntry* entry() const { return entry_; }
unsigned self_ticks() const { return self_ticks_; }
const List<ProfileNode*>* children() const { return &children_list_; }
unsigned id() const { return id_; }
unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
unsigned int length) const;
void Print(int indent);
......@@ -171,7 +139,6 @@ class ProfileNode {
HashMap children_;
List<ProfileNode*> children_list_;
unsigned id_;
HashMap line_ticks_;
DISALLOW_COPY_AND_ASSIGN(ProfileNode);
};
......@@ -182,11 +149,8 @@ class ProfileTree {
ProfileTree();
~ProfileTree();
ProfileNode* AddPathFromEnd(
const Vector<CodeEntry*>& path,
int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
void AddPathFromStart(const Vector<CodeEntry*>& path,
int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path);
void AddPathFromStart(const Vector<CodeEntry*>& path);
ProfileNode* root() const { return root_; }
unsigned next_node_id() { return next_node_id_++; }
......@@ -211,8 +175,7 @@ class CpuProfile {
CpuProfile(const char* title, bool record_samples);
// Add pc -> ... -> main() call path to the profile.
void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path,
int src_line);
void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path);
void CalculateTotalTicksAndSamplingRate();
const char* title() const { return title_; }
......@@ -314,16 +277,16 @@ class CpuProfilesCollection {
void RemoveProfile(CpuProfile* profile);
CodeEntry* NewCodeEntry(
Logger::LogEventsAndTags tag, const char* name,
Logger::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);
int column_number = v8::CpuProfileNode::kNoColumnNumberInfo);
// Called from profile generator thread.
void AddPathToCurrentProfiles(base::TimeTicks timestamp,
const Vector<CodeEntry*>& path, int src_line);
void AddPathToCurrentProfiles(
base::TimeTicks timestamp, const Vector<CodeEntry*>& path);
// Limits the number of profiles that can be simultaneously collected.
static const int kMaxSimultaneousProfiles = 100;
......
......@@ -1064,104 +1064,6 @@ TEST(BoundFunctionCall) {
}
// This tests checks distribution of the samples through the source lines.
TEST(TickLines) {
CcTest::InitializeVM();
LocalContext env;
i::FLAG_turbo_source_positions = true;
i::Isolate* isolate = CcTest::i_isolate();
i::Factory* factory = isolate->factory();
i::HandleScope scope(isolate);
i::EmbeddedVector<char, 512> script;
const char* func_name = "func";
i::SNPrintF(script,
"function %s() {\n"
" var n = 0;\n"
" var m = 100*100;\n"
" while (m > 1) {\n"
" m--;\n"
" n += m * m * m;\n"
" }\n"
"}\n"
"%s();\n",
func_name, func_name);
CompileRun(script.start());
i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast((*env)->Global()->Get(v8_str(func_name))));
CHECK_NE(NULL, func->shared());
CHECK_NE(NULL, func->shared()->code());
i::Code* code = NULL;
if (func->code()->is_optimized_code()) {
code = func->code();
} else {
CHECK(func->shared()->code() == func->code() || !i::FLAG_crankshaft);
code = func->shared()->code();
}
CHECK_NE(NULL, code);
i::Address code_address = code->instruction_start();
CHECK_NE(NULL, code_address);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
profiles->StartProfiling("", false);
ProfileGenerator generator(profiles);
SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor(
&generator, NULL, v8::base::TimeDelta::FromMicroseconds(100)));
processor->Start();
CpuProfiler profiler(isolate, profiles, &generator, processor.get());
// Enqueue code creation events.
i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
int line = 1;
int column = 1;
profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, code, func->shared(), NULL,
*str, line, column);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(processor.get(), code_address);
processor->StopSynchronously();
CpuProfile* profile = profiles->StopProfiling("");
CHECK_NE(NULL, profile);
// Check the state of profile generator.
CodeEntry* func_entry = generator.code_map()->FindEntry(code_address);
CHECK_NE(NULL, func_entry);
CHECK_EQ(func_name, func_entry->name());
const i::JITLineInfoTable* line_info = func_entry->line_info();
CHECK_NE(NULL, line_info);
CHECK(!line_info->empty());
// Check the hit source lines using V8 Public APIs.
const i::ProfileTree* tree = profile->top_down();
ProfileNode* root = tree->root();
CHECK_NE(NULL, root);
ProfileNode* func_node = root->FindChild(func_entry);
CHECK_NE(NULL, func_node);
// Add 10 faked ticks to source line #5.
int hit_line = 5;
int hit_count = 10;
for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
unsigned int line_count = func_node->GetHitLineCount();
CHECK_EQ(2, line_count); // Expect two hit source lines - #1 and #5.
ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
CHECK(func_node->GetLineTicks(&entries[0], line_count));
int value = 0;
for (int i = 0; i < entries.length(); i++)
if (entries[i].line == hit_line) {
value = entries[i].hit_count;
break;
}
CHECK_EQ(hit_count, value);
}
static const char* call_function_test_source = "function bar(iterations) {\n"
"}\n"
"function start(duration) {\n"
......
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