Commit a0572f0b authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[cpu-profiler] Reduce the size of inlining information

Previously we stored the source position table, which stored a mapping
of pc offsets to line numbers, and the inline_locations, which stored a
mapping of pc offsets to stacks of {CodeEntry, line_number} pairs. This
was slightly wasteful because we had two different tables which were
both keyed on the pc offset and contained some overlapping information.

This CL combines the two tables in a way. The source position table now
maps a pc offset to a pair of {line_number, inlining_id}. If the
inlining_id is valid, then it can be used to look up the inlining stack
which is stored in inline_locations, but is now keyed by inlining_id
rather than pc offset. This also has the nice effect of de-duplicating
inline stacks which we previously duplicated.

The new structure is similar to how this data is stored by the compiler,
except that we convert 'source positions' (char offset in a file) into
line numbers as we go, because we only care about attributing ticks to
a given line.

Also remove the helper RecordInliningInfo() as this is only actually
used to add inline stacks by one caller (where it is now inlined). The
other callers would always bail out or are only called from
test-cpu-profiler.

Remove AddInlineStack and replace it with SetInlineStacks which adds all
of the stacks at once. We need to do it this way because the source pos
table is passed into the constructor of CodeEntry, so we need to create
it before the CodeEntry, but the inline stacks are not (they are part of
rare_data which is not always present), so we need to add them after
construction. Given that we calculate both the source pos table and the
inline stacks before construction, it's just easier to add them all at
once.

Also add a print() method to CodeEntry to make future debugging easier
as I'm constantly rewriting this locally.

Bug: v8:8575, v8:7719, v8:7203

Change-Id: I39324d6ea13d116d5da5d0a0d243cae76a749c79
Reviewed-on: https://chromium-review.googlesource.com/c/1392195
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58554}
parent 3346b8a3
......@@ -18,7 +18,8 @@
namespace v8 {
namespace internal {
void SourcePositionTable::SetPosition(int pc_offset, int line) {
void SourcePositionTable::SetPosition(int pc_offset, int line,
int inlining_id) {
DCHECK_GE(pc_offset, 0);
DCHECK_GT(line, 0); // The 1-based number of the source line.
// Check that we are inserting in ascending order, so that the vector remains
......@@ -26,8 +27,9 @@ void SourcePositionTable::SetPosition(int pc_offset, int line) {
DCHECK(pc_offsets_to_lines_.empty() ||
pc_offsets_to_lines_.back().pc_offset < pc_offset);
if (pc_offsets_to_lines_.empty() ||
pc_offsets_to_lines_.back().line_number != line) {
pc_offsets_to_lines_.push_back({pc_offset, line});
pc_offsets_to_lines_.back().line_number != line ||
pc_offsets_to_lines_.back().inlining_id != inlining_id) {
pc_offsets_to_lines_.push_back({pc_offset, line, inlining_id});
}
}
......@@ -35,13 +37,33 @@ int SourcePositionTable::GetSourceLineNumber(int pc_offset) const {
if (pc_offsets_to_lines_.empty()) {
return v8::CpuProfileNode::kNoLineNumberInfo;
}
auto it =
std::lower_bound(pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(),
PCOffsetAndLineNumber{pc_offset, 0});
auto it = std::lower_bound(
pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(),
SourcePositionTuple{pc_offset, 0, SourcePosition::kNotInlined});
if (it != pc_offsets_to_lines_.begin()) --it;
return it->line_number;
}
int SourcePositionTable::GetInliningId(int pc_offset) const {
if (pc_offsets_to_lines_.empty()) {
return SourcePosition::kNotInlined;
}
auto it = std::lower_bound(
pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(),
SourcePositionTuple{pc_offset, 0, SourcePosition::kNotInlined});
if (it != pc_offsets_to_lines_.begin()) --it;
return it->inlining_id;
}
void SourcePositionTable::print() const {
base::OS::Print(" - source position table at %p\n", this);
for (const SourcePositionTuple& pos_info : pc_offsets_to_lines_) {
base::OS::Print(" %d --> line_number: %d inlining_id: %d\n",
pos_info.pc_offset, pos_info.line_number,
pos_info.inlining_id);
}
}
const char* const CodeEntry::kWasmResourceNamePrefix = "wasm ";
const char* const CodeEntry::kEmptyResourceName = "";
const char* const CodeEntry::kEmptyBailoutReason = "";
......@@ -119,17 +141,20 @@ int CodeEntry::GetSourceLine(int pc_offset) const {
return v8::CpuProfileNode::kNoLineNumberInfo;
}
void CodeEntry::AddInlineStack(int pc_offset,
std::vector<InlineEntry> inline_stack) {
EnsureRareData()->inline_locations_.insert(
std::make_pair(pc_offset, std::move(inline_stack)));
void CodeEntry::SetInlineStacks(
std::unordered_map<int, std::vector<InlineEntry>> inline_stacks) {
EnsureRareData()->inline_locations_ = std::move(inline_stacks);
}
const std::vector<InlineEntry>* CodeEntry::GetInlineStack(int pc_offset) const {
if (!rare_data_ || rare_data_->inline_locations_.empty()) return nullptr;
auto it = rare_data_->inline_locations_.lower_bound(pc_offset);
if (it != rare_data_->inline_locations_.begin()) it--;
return it->second.empty() ? nullptr : &it->second;
if (!line_info_) return nullptr;
int inlining_id = line_info_->GetInliningId(pc_offset);
if (inlining_id == SourcePosition::kNotInlined) return nullptr;
DCHECK(rare_data_);
auto it = rare_data_->inline_locations_.find(inlining_id);
return it != rare_data_->inline_locations_.end() ? &it->second : nullptr;
}
void CodeEntry::set_deopt_info(
......@@ -174,6 +199,55 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() {
return rare_data_.get();
}
void CodeEntry::print() const {
base::OS::Print("CodeEntry: at %p\n", this);
base::OS::Print(" - name: %s\n", name_);
base::OS::Print(" - resource_name: %s\n", resource_name_);
base::OS::Print(" - line_number: %d\n", line_number_);
base::OS::Print(" - column_number: %d\n", column_number_);
base::OS::Print(" - script_id: %d\n", script_id_);
base::OS::Print(" - position: %d\n", position_);
base::OS::Print(" - instruction_start: %p\n",
reinterpret_cast<void*>(instruction_start_));
if (line_info_) {
line_info_->print();
}
if (rare_data_) {
base::OS::Print(" - deopt_reason: %s\n", rare_data_->deopt_reason_);
base::OS::Print(" - bailout_reason: %s\n", rare_data_->bailout_reason_);
base::OS::Print(" - deopt_id: %d\n", rare_data_->deopt_id_);
if (!rare_data_->inline_locations_.empty()) {
base::OS::Print(" - inline stacks:\n");
for (auto it = rare_data_->inline_locations_.begin();
it != rare_data_->inline_locations_.end(); it++) {
base::OS::Print(" inlining_id: [%d]\n", it->first);
for (const auto& e : it->second) {
base::OS::Print(" %s --> %d\n", e.code_entry->name(),
e.call_line_number);
}
}
} else {
base::OS::Print(" - inline stacks: (empty)\n");
}
if (!rare_data_->deopt_inlined_frames_.empty()) {
base::OS::Print(" - deopt inlined frames:\n");
for (const CpuProfileDeoptFrame& frame :
rare_data_->deopt_inlined_frames_) {
base::OS::Print("script_id: %d position: %zu\n", frame.script_id,
frame.position);
}
} else {
base::OS::Print(" - deopt inlined frames: (empty)\n");
}
}
base::OS::Print("\n");
}
void ProfileNode::CollectDeoptInfo(CodeEntry* entry) {
deopt_infos_.push_back(entry->GetDeoptInfo());
entry->clear_deopt_info();
......@@ -762,6 +836,7 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
const std::vector<InlineEntry>* inline_stack =
entry->GetInlineStack(pc_offset);
if (inline_stack) {
int most_inlined_frame_line_number = entry->GetSourceLine(pc_offset);
std::transform(inline_stack->begin(), inline_stack->end(),
std::back_inserter(stack_trace),
[](const InlineEntry& inline_entry) {
......@@ -769,6 +844,16 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
inline_entry.code_entry.get(),
inline_entry.call_line_number};
});
// This is a bit of a messy hack. The line number for the most-inlined
// frame (the function at the end of the chain of function calls) has
// the wrong line number in inline_stack. The actual line number in
// this function is stored in the SourcePositionTable in entry. We fix
// up the line number for the most-inlined frame here.
// TODO(petermarshall): Remove this and use a tree with a node per
// inlining_id.
DCHECK(!inline_stack->empty());
size_t index = stack_trace.size() - inline_stack->size();
stack_trace[index].line_number = most_inlined_frame_line_number;
}
// Skip unresolved frames (e.g. internal frame) and get source line of
// the first JS caller.
......
......@@ -26,26 +26,30 @@ namespace internal {
struct TickSample;
// Provides a mapping from the offsets within generated code or a bytecode array
// to the source line.
// to the source line and inlining id.
class SourcePositionTable : public Malloced {
public:
SourcePositionTable() = default;
void SetPosition(int pc_offset, int line);
void SetPosition(int pc_offset, int line, int inlining_id);
int GetSourceLineNumber(int pc_offset) const;
int GetInliningId(int pc_offset) const;
void print() const;
private:
struct PCOffsetAndLineNumber {
bool operator<(const PCOffsetAndLineNumber& other) const {
struct SourcePositionTuple {
bool operator<(const SourcePositionTuple& other) const {
return pc_offset < other.pc_offset;
}
int pc_offset;
int line_number;
int inlining_id;
};
// This is logically a map, but we store it as a vector of pairs, sorted by
// This is logically a map, but we store it as a vector of tuples, sorted by
// the pc offset, so that we can save space and look up items using binary
// search.
std::vector<PCOffsetAndLineNumber> pc_offsets_to_lines_;
std::vector<SourcePositionTuple> pc_offsets_to_lines_;
DISALLOW_COPY_AND_ASSIGN(SourcePositionTable);
};
......@@ -105,7 +109,8 @@ class CodeEntry {
int GetSourceLine(int pc_offset) const;
void AddInlineStack(int pc_offset, std::vector<InlineEntry> inline_stack);
void SetInlineStacks(
std::unordered_map<int, std::vector<InlineEntry>> inline_stacks);
const std::vector<InlineEntry>* GetInlineStack(int pc_offset) const;
void set_instruction_start(Address start) { instruction_start_ = start; }
......@@ -136,12 +141,14 @@ class CodeEntry {
return kUnresolvedEntry.Pointer();
}
void print() const;
private:
struct RareData {
const char* deopt_reason_ = kNoDeoptReason;
const char* bailout_reason_ = kEmptyBailoutReason;
int deopt_id_ = kNoDeoptimizationId;
std::map<int, std::vector<InlineEntry>> inline_locations_;
std::unordered_map<int, std::vector<InlineEntry>> inline_locations_;
std::vector<CpuProfileDeoptFrame> deopt_inlined_frames_;
};
......
......@@ -40,7 +40,6 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr,
code->InstructionStart());
RecordInliningInfo(rec->entry, code);
rec->instruction_size = code->InstructionSize();
DispatchCodeEvent(evt_rec);
}
......@@ -54,7 +53,6 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr,
code->InstructionStart());
RecordInliningInfo(rec->entry, code);
rec->instruction_size = code->InstructionSize();
DispatchCodeEvent(evt_rec);
}
......@@ -71,7 +69,7 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr,
code->InstructionStart());
RecordInliningInfo(rec->entry, code);
DCHECK(!code->IsCode());
rec->entry->FillFunctionInfo(shared);
rec->instruction_size = code->InstructionSize();
DispatchCodeEvent(evt_rec);
......@@ -85,25 +83,74 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = abstract_code->InstructionStart();
std::unique_ptr<SourcePositionTable> line_table;
std::unordered_map<int, std::vector<InlineEntry>> inline_stacks;
if (shared->script()->IsScript()) {
Script script = Script::cast(shared->script());
line_table.reset(new SourcePositionTable());
HandleScope scope(isolate_);
// Add each position to the source position table and store inlining stacks
// for inline positions. We store almost the same information in the
// profiler as is stored on the code object, except that we transform source
// positions to line numbers here, because we only care about attributing
// ticks to a given line.
for (SourcePositionTableIterator it(abstract_code->source_position_table());
!it.done(); it.Advance()) {
// TODO(alph,tebbi) Skipping inlined positions for now, because they might
// refer to a different script.
if (it.source_position().InliningId() != SourcePosition::kNotInlined)
continue;
int position = it.source_position().ScriptOffset();
int line_number = script->GetLineNumber(position) + 1;
line_table->SetPosition(it.code_offset(), line_number);
int inlining_id = it.source_position().InliningId();
line_table->SetPosition(it.code_offset(), line_number, inlining_id);
if (inlining_id != SourcePosition::kNotInlined) {
DCHECK(abstract_code->IsCode());
Code code = abstract_code->GetCode();
std::vector<SourcePositionInfo> stack =
it.source_position().InliningStack(handle(code, isolate_));
DCHECK(!stack.empty());
std::vector<InlineEntry> inline_stack;
for (SourcePositionInfo& pos_info : stack) {
if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue;
if (pos_info.script.is_null()) continue;
int line_number =
pos_info.script->GetLineNumber(pos_info.position.ScriptOffset()) +
1;
const char* resource_name =
(pos_info.script->name()->IsName())
? GetName(Name::cast(pos_info.script->name()))
: CodeEntry::kEmptyResourceName;
// We need the start line number and column number of the function for
// kLeafNodeLineNumbers mode. Creating a SourcePositionInfo is a handy
// way of getting both easily.
SourcePositionInfo start_pos_info(
SourcePosition(pos_info.shared->StartPosition()),
pos_info.shared);
std::unique_ptr<CodeEntry> inline_entry =
base::make_unique<CodeEntry>(
tag, GetName(pos_info.shared->DebugName()), resource_name,
start_pos_info.line + 1, start_pos_info.column + 1, nullptr,
code->InstructionStart());
inline_entry->FillFunctionInfo(*pos_info.shared);
inline_stack.push_back(
InlineEntry{std::move(inline_entry), line_number});
}
DCHECK(!inline_stack.empty());
inline_stacks.emplace(inlining_id, std::move(inline_stack));
}
}
}
rec->entry =
NewCodeEntry(tag, GetName(shared->DebugName()),
GetName(InferScriptName(script_name, shared)), line, column,
std::move(line_table), abstract_code->InstructionStart());
RecordInliningInfo(rec->entry, abstract_code);
if (!inline_stacks.empty()) {
rec->entry->SetInlineStacks(std::move(inline_stacks));
}
rec->entry->FillFunctionInfo(shared);
rec->instruction_size = abstract_code->InstructionSize();
DispatchCodeEvent(evt_rec);
......@@ -196,66 +243,6 @@ Name ProfilerListener::InferScriptName(Name name, SharedFunctionInfo info) {
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;
// Needed for InliningStack().
HandleScope scope(isolate_);
int last_inlining_id = -2;
for (SourcePositionTableIterator it(abstract_code->source_position_table());
!it.done(); it.Advance()) {
int code_offset = it.code_offset();
// Save space by not duplicating repeated entries that map to the same
// inlining ID. We might get multiple source positions per inlining ID, but
// they all map to the same line. This automatically collapses adjacent
// inlining stacks (or empty stacks) that are exactly the same.
if (it.source_position().InliningId() == last_inlining_id) continue;
last_inlining_id = it.source_position().InliningId();
// Only look at positions for inlined calls.
if (it.source_position().InliningId() == SourcePosition::kNotInlined) {
entry->AddInlineStack(code_offset, std::vector<InlineEntry>());
continue;
}
std::vector<SourcePositionInfo> stack =
it.source_position().InliningStack(handle(code, isolate_));
std::vector<InlineEntry> inline_stack;
for (SourcePositionInfo& pos_info : stack) {
if (pos_info.position.ScriptOffset() == kNoSourcePosition) continue;
if (pos_info.script.is_null()) continue;
int line_number =
pos_info.script->GetLineNumber(pos_info.position.ScriptOffset()) + 1;
const char* resource_name =
(pos_info.script->name()->IsName())
? GetName(Name::cast(pos_info.script->name()))
: CodeEntry::kEmptyResourceName;
// We need the start line number and column number of the function for
// kLeafNodeLineNumbers mode. Creating a SourcePositionInfo is a handy way
// of getting both easily.
SourcePositionInfo start_pos_info(
SourcePosition(pos_info.shared->StartPosition()), pos_info.shared);
std::unique_ptr<CodeEntry> inline_entry = base::make_unique<CodeEntry>(
entry->tag(), GetName(pos_info.shared->DebugName()), resource_name,
start_pos_info.line + 1, start_pos_info.column + 1, nullptr,
code->InstructionStart());
inline_entry->FillFunctionInfo(*pos_info.shared);
inline_stack.push_back(InlineEntry{std::move(inline_entry), line_number});
}
if (!inline_stack.empty()) {
entry->AddInlineStack(code_offset, std::move(inline_stack));
}
}
}
void ProfilerListener::AttachDeoptInlinedFrames(Code code,
CodeDeoptEventRecord* rec) {
int deopt_id = rec->deopt_id;
......
......@@ -76,7 +76,6 @@ class ProfilerListener : public CodeEventListener {
}
private:
void RecordInliningInfo(CodeEntry* entry, AbstractCode abstract_code);
void AttachDeoptInlinedFrames(Code code, CodeDeoptEventRecord* rec);
Name InferScriptName(Name name, SharedFunctionInfo info);
V8_INLINE void DispatchCodeEvent(const CodeEventsContainer& evt_rec) {
......
......@@ -1717,7 +1717,8 @@ static const char* inlining_test_source2 = R"(
return s;
}
function level4() {
return action(200);
action(100);
return action(100);
}
function level3() {
const a = level4();
......@@ -1748,23 +1749,27 @@ const double load_factor = 1.0;
// [Top down]:
// 0 (root):0 0 #1
// 1 start:33 6 #3
// bailed out due to 'Optimization disabled for test'
// 5 level1:35 6 #4
// 1 action:28 6 #12
// bailed out due to 'Optimization disabled for test'
// 3 action:30 6 #13
// bailed out due to 'Optimization disabled for test'
// 0 level2:31 6 #6
// 0 level3:25 6 #7
// 6 level4:20 6 #10
// 251 action:17 6 #11
// bailed out due to 'Optimization disabled for test'
// 2 level4:21 6 #8
// 238 action:17 6 #9
// bailed out due to 'Optimization disabled for test'
// 245 action:29 6 #5
// bailed out due to 'Optimization disabled for test'
// 13 start:34 6 #3
// bailed out due to 'Optimization is always disabled'
// 19 level1:36 6 #4
// 16 action:29 6 #14
// bailed out due to 'Optimization is always disabled'
// 2748 action:30 6 #10
// bailed out due to 'Optimization is always disabled'
// 18 action:31 6 #15
// bailed out due to 'Optimization is always disabled'
// 0 level2:32 6 #5
// 0 level3:26 6 #6
// 12 level4:22 6 #11
// 1315 action:17 6 #13
// bailed out due to 'Optimization is always disabled'
// 1324 action:18 6 #12
// bailed out due to 'Optimization is always disabled'
// 16 level4:21 6 #7
// 1268 action:17 6 #9
// bailed out due to 'Optimization is always disabled'
// 1322 action:18 6 #8
// bailed out due to 'Optimization is always disabled'
// 2 (program):0 0 #2
TEST(Inlining2) {
i::FLAG_allow_natives_syntax = true;
......@@ -1792,19 +1797,33 @@ TEST(Inlining2) {
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* start_node = GetChild(env, root, "start");
NameLinePair l4_18[] = {{"level1", 35},
{"level2", 31},
{"level3", 25},
{"level4", 20},
{"action", 17}};
CheckBranch(start_node, l4_18, arraysize(l4_18));
NameLinePair l4_19[] = {{"level1", 35},
{"level2", 31},
{"level3", 25},
{"level4", 21},
{"action", 17}};
CheckBranch(start_node, l4_19, arraysize(l4_19));
NameLinePair action_direct[] = {{"level1", 35}, {"action", 29}};
NameLinePair l421_a17[] = {{"level1", 36},
{"level2", 32},
{"level3", 26},
{"level4", 21},
{"action", 17}};
CheckBranch(start_node, l421_a17, arraysize(l421_a17));
NameLinePair l422_a17[] = {{"level1", 36},
{"level2", 32},
{"level3", 26},
{"level4", 22},
{"action", 17}};
CheckBranch(start_node, l422_a17, arraysize(l422_a17));
NameLinePair l421_a18[] = {{"level1", 36},
{"level2", 32},
{"level3", 26},
{"level4", 21},
{"action", 18}};
CheckBranch(start_node, l421_a18, arraysize(l421_a18));
NameLinePair l422_a18[] = {{"level1", 36},
{"level2", 32},
{"level3", 26},
{"level4", 22},
{"action", 18}};
CheckBranch(start_node, l422_a18, arraysize(l422_a18));
NameLinePair action_direct[] = {{"level1", 36}, {"action", 30}};
CheckBranch(start_node, action_direct, arraysize(action_direct));
profile->Delete();
......@@ -2617,6 +2636,7 @@ TEST(SourcePositionTable) {
int no_info = v8::CpuProfileNode::kNoLineNumberInfo;
CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits<int>::min()));
CHECK_EQ(no_info, info.GetSourceLineNumber(0));
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(0));
CHECK_EQ(no_info, info.GetSourceLineNumber(1));
CHECK_EQ(no_info, info.GetSourceLineNumber(9));
CHECK_EQ(no_info, info.GetSourceLineNumber(10));
......@@ -2625,12 +2645,14 @@ TEST(SourcePositionTable) {
CHECK_EQ(no_info, info.GetSourceLineNumber(20));
CHECK_EQ(no_info, info.GetSourceLineNumber(21));
CHECK_EQ(no_info, info.GetSourceLineNumber(100));
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(100));
CHECK_EQ(no_info, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
info.SetPosition(10, 1);
info.SetPosition(20, 2);
info.SetPosition(10, 1, SourcePosition::kNotInlined);
info.SetPosition(20, 2, SourcePosition::kNotInlined);
// The only valid return values are 1 or 2 - every pc maps to a line number.
// The only valid return values are 1 or 2 - every pc maps to a line
// number.
CHECK_EQ(1, info.GetSourceLineNumber(std::numeric_limits<int>::min()));
CHECK_EQ(1, info.GetSourceLineNumber(0));
CHECK_EQ(1, info.GetSourceLineNumber(1));
......@@ -2643,11 +2665,17 @@ TEST(SourcePositionTable) {
CHECK_EQ(2, info.GetSourceLineNumber(100));
CHECK_EQ(2, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(0));
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(100));
// Test SetPosition behavior.
info.SetPosition(25, 3);
info.SetPosition(25, 3, 0);
CHECK_EQ(2, info.GetSourceLineNumber(21));
CHECK_EQ(3, info.GetSourceLineNumber(100));
CHECK_EQ(3, info.GetSourceLineNumber(std::numeric_limits<int>::max()));
CHECK_EQ(SourcePosition::kNotInlined, info.GetInliningId(21));
CHECK_EQ(0, info.GetInliningId(100));
}
TEST(MultipleProfilers) {
......
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