[turbofan] basic block profiler
R=titzer@chromium.org, mstarzinger@chromium.org BUG= Review URL: https://codereview.chromium.org/593563005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24263 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
667f15a104
commit
5d0e9a2496
4
BUILD.gn
4
BUILD.gn
@ -440,6 +440,8 @@ source_set("v8_base") {
|
||||
"src/background-parsing-task.h",
|
||||
"src/bailout-reason.cc",
|
||||
"src/bailout-reason.h",
|
||||
"src/basic-block-profiler.cc",
|
||||
"src/basic-block-profiler.h",
|
||||
"src/bignum-dtoa.cc",
|
||||
"src/bignum-dtoa.h",
|
||||
"src/bignum.cc",
|
||||
@ -471,6 +473,8 @@ source_set("v8_base") {
|
||||
"src/compiler/access-builder.h",
|
||||
"src/compiler/ast-graph-builder.cc",
|
||||
"src/compiler/ast-graph-builder.h",
|
||||
"src/compiler/basic-block-instrumentor.cc",
|
||||
"src/compiler/basic-block-instrumentor.h",
|
||||
"src/compiler/change-lowering.cc",
|
||||
"src/compiler/change-lowering.h",
|
||||
"src/compiler/code-generator-impl.h",
|
||||
|
112
src/basic-block-profiler.cc
Normal file
112
src/basic-block-profiler.cc
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2014 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/basic-block-profiler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
BasicBlockProfiler::Data::Data(size_t n_blocks)
|
||||
: n_blocks_(n_blocks), block_ids_(n_blocks_, -1), counts_(n_blocks_, 0) {}
|
||||
|
||||
|
||||
BasicBlockProfiler::Data::~Data() {}
|
||||
|
||||
|
||||
static void InsertIntoString(OStringStream* os, std::string* string) {
|
||||
string->insert(string->begin(), os->c_str(), &os->c_str()[os->size()]);
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::Data::SetCode(OStringStream* os) {
|
||||
InsertIntoString(os, &code_);
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::Data::SetFunctionName(OStringStream* os) {
|
||||
InsertIntoString(os, &function_name_);
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::Data::SetSchedule(OStringStream* os) {
|
||||
InsertIntoString(os, &schedule_);
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::Data::SetBlockId(size_t offset, int block_id) {
|
||||
DCHECK(offset < n_blocks_);
|
||||
block_ids_[offset] = block_id;
|
||||
}
|
||||
|
||||
|
||||
uint32_t* BasicBlockProfiler::Data::GetCounterAddress(size_t offset) {
|
||||
DCHECK(offset < n_blocks_);
|
||||
return &counts_[offset];
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::Data::ResetCounts() {
|
||||
for (size_t i = 0; i < n_blocks_; ++i) {
|
||||
counts_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BasicBlockProfiler::BasicBlockProfiler() {}
|
||||
|
||||
|
||||
BasicBlockProfiler::Data* BasicBlockProfiler::NewData(size_t n_blocks) {
|
||||
Data* data = new Data(n_blocks);
|
||||
data_list_.push_back(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
BasicBlockProfiler::~BasicBlockProfiler() {
|
||||
for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
|
||||
delete (*i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BasicBlockProfiler::ResetCounts() {
|
||||
for (DataList::iterator i = data_list_.begin(); i != data_list_.end(); ++i) {
|
||||
(*i)->ResetCounts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OStream& operator<<(OStream& os, const BasicBlockProfiler& p) {
|
||||
os << "---- Start Profiling Data ----" << endl;
|
||||
typedef BasicBlockProfiler::DataList::const_iterator iterator;
|
||||
for (iterator i = p.data_list_.begin(); i != p.data_list_.end(); ++i) {
|
||||
os << **i;
|
||||
}
|
||||
os << "---- End Profiling Data ----" << endl;
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
OStream& operator<<(OStream& os, const BasicBlockProfiler::Data& d) {
|
||||
const char* name = "unknown function";
|
||||
if (!d.function_name_.empty()) {
|
||||
name = d.function_name_.c_str();
|
||||
}
|
||||
if (!d.schedule_.empty()) {
|
||||
os << "schedule for " << name << endl;
|
||||
os << d.schedule_.c_str() << endl;
|
||||
}
|
||||
os << "block counts for " << name << ":" << endl;
|
||||
for (size_t i = 0; i < d.n_blocks_; ++i) {
|
||||
os << "block " << d.block_ids_[i] << " : " << d.counts_[i] << endl;
|
||||
}
|
||||
os << endl;
|
||||
if (!d.code_.empty()) {
|
||||
os << d.code_.c_str() << endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
73
src/basic-block-profiler.h
Normal file
73
src/basic-block-profiler.h
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2014 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_BASIC_BLOCK_PROFILER_H_
|
||||
#define V8_BASIC_BLOCK_PROFILER_H_
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Schedule;
|
||||
class Graph;
|
||||
|
||||
class BasicBlockProfiler {
|
||||
public:
|
||||
class Data {
|
||||
public:
|
||||
size_t n_blocks() const { return n_blocks_; }
|
||||
const uint32_t* counts() const { return &counts_[0]; }
|
||||
|
||||
void SetCode(OStringStream* os);
|
||||
void SetFunctionName(OStringStream* os);
|
||||
void SetSchedule(OStringStream* os);
|
||||
void SetBlockId(size_t offset, int block_id);
|
||||
uint32_t* GetCounterAddress(size_t offset);
|
||||
|
||||
private:
|
||||
friend class BasicBlockProfiler;
|
||||
friend OStream& operator<<(OStream& os, const BasicBlockProfiler::Data& s);
|
||||
|
||||
explicit Data(size_t n_blocks);
|
||||
~Data();
|
||||
|
||||
void ResetCounts();
|
||||
|
||||
const size_t n_blocks_;
|
||||
std::vector<int> block_ids_;
|
||||
std::vector<uint32_t> counts_;
|
||||
std::string function_name_;
|
||||
std::string schedule_;
|
||||
std::string code_;
|
||||
DISALLOW_COPY_AND_ASSIGN(Data);
|
||||
};
|
||||
|
||||
typedef std::list<Data*> DataList;
|
||||
|
||||
BasicBlockProfiler();
|
||||
~BasicBlockProfiler();
|
||||
|
||||
Data* NewData(size_t n_blocks);
|
||||
void ResetCounts();
|
||||
|
||||
const DataList* data_list() { return &data_list_; }
|
||||
|
||||
private:
|
||||
friend OStream& operator<<(OStream& os, const BasicBlockProfiler& s);
|
||||
|
||||
DataList data_list_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BasicBlockProfiler);
|
||||
};
|
||||
|
||||
OStream& operator<<(OStream& os, const BasicBlockProfiler& s);
|
||||
OStream& operator<<(OStream& os, const BasicBlockProfiler::Data& s);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BASIC_BLOCK_PROFILER_H_
|
103
src/compiler/basic-block-instrumentor.cc
Normal file
103
src/compiler/basic-block-instrumentor.cc
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2014 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/compiler/basic-block-instrumentor.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "src/compiler/operator-properties-inl.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
// Find the first place to insert new nodes in a block that's already been
|
||||
// scheduled that won't upset the register allocator.
|
||||
static NodeVector::iterator FindInsertionPoint(NodeVector* nodes) {
|
||||
NodeVector::iterator i = nodes->begin();
|
||||
for (; i != nodes->end(); ++i) {
|
||||
const Operator* op = (*i)->op();
|
||||
if (OperatorProperties::IsBasicBlockBegin(op)) continue;
|
||||
switch (op->opcode()) {
|
||||
case IrOpcode::kParameter:
|
||||
case IrOpcode::kPhi:
|
||||
case IrOpcode::kEffectPhi:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// TODO(dcarney): need to mark code as non-serializable.
|
||||
static const Operator* PointerConstant(CommonOperatorBuilder* common,
|
||||
void* ptr) {
|
||||
return kPointerSize == 8
|
||||
? common->Int64Constant(reinterpret_cast<intptr_t>(ptr))
|
||||
: common->Int32Constant(
|
||||
static_cast<int32_t>(reinterpret_cast<intptr_t>(ptr)));
|
||||
}
|
||||
|
||||
|
||||
BasicBlockProfiler::Data* BasicBlockInstrumentor::Instrument(
|
||||
CompilationInfo* info, Graph* graph, Schedule* schedule) {
|
||||
// Skip the exit block in profiles, since the register allocator can't handle
|
||||
// it and entry into it means falling off the end of the function anyway.
|
||||
size_t n_blocks = static_cast<size_t>(schedule->RpoBlockCount()) - 1;
|
||||
BasicBlockProfiler::Data* data =
|
||||
info->isolate()->GetOrCreateBasicBlockProfiler()->NewData(n_blocks);
|
||||
// Set the function name.
|
||||
if (!info->shared_info().is_null() &&
|
||||
info->shared_info()->name()->IsString()) {
|
||||
OStringStream os;
|
||||
String::cast(info->shared_info()->name())->PrintUC16(os);
|
||||
data->SetFunctionName(&os);
|
||||
}
|
||||
// Capture the schedule string before instrumentation.
|
||||
{
|
||||
OStringStream os;
|
||||
os << *schedule;
|
||||
data->SetSchedule(&os);
|
||||
}
|
||||
// Add the increment instructions to the start of every block.
|
||||
CommonOperatorBuilder common(graph->zone());
|
||||
Node* zero = graph->NewNode(common.Int32Constant(0));
|
||||
Node* one = graph->NewNode(common.Int32Constant(1));
|
||||
MachineOperatorBuilder machine;
|
||||
BasicBlockVector* blocks = schedule->rpo_order();
|
||||
size_t block_number = 0;
|
||||
for (BasicBlockVector::iterator it = blocks->begin(); block_number < n_blocks;
|
||||
++it, ++block_number) {
|
||||
BasicBlock* block = (*it);
|
||||
data->SetBlockId(block_number, block->id());
|
||||
// TODO(dcarney): wire effect and control deps for load and store.
|
||||
// Construct increment operation.
|
||||
Node* base = graph->NewNode(
|
||||
PointerConstant(&common, data->GetCounterAddress(block_number)));
|
||||
Node* load = graph->NewNode(machine.Load(kMachUint32), base, zero);
|
||||
Node* inc = graph->NewNode(machine.Int32Add(), load, one);
|
||||
Node* store = graph->NewNode(
|
||||
machine.Store(StoreRepresentation(kMachUint32, kNoWriteBarrier)), base,
|
||||
zero, inc);
|
||||
// Insert the new nodes.
|
||||
static const int kArraySize = 6;
|
||||
Node* to_insert[kArraySize] = {zero, one, base, load, inc, store};
|
||||
int insertion_start = block_number == 0 ? 0 : 2;
|
||||
NodeVector* nodes = &block->nodes_;
|
||||
NodeVector::iterator insertion_point = FindInsertionPoint(nodes);
|
||||
nodes->insert(insertion_point, &to_insert[insertion_start],
|
||||
&to_insert[kArraySize]);
|
||||
// Tell the scheduler about the new nodes.
|
||||
for (int i = insertion_start; i < kArraySize; ++i) {
|
||||
schedule->SetBlockForNode(block, to_insert[i]);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
32
src/compiler/basic-block-instrumentor.h
Normal file
32
src/compiler/basic-block-instrumentor.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2014 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_COMPILER_BASIC_BLOCK_INSTRUMENTOR_H_
|
||||
#define V8_COMPILER_BASIC_BLOCK_INSTRUMENTOR_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/basic-block-profiler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CompilationInfo;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class Graph;
|
||||
class Schedule;
|
||||
|
||||
class BasicBlockInstrumentor : public AllStatic {
|
||||
public:
|
||||
static BasicBlockProfiler::Data* Instrument(CompilationInfo* info,
|
||||
Graph* graph, Schedule* schedule);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "src/base/platform/elapsed-timer.h"
|
||||
#include "src/compiler/ast-graph-builder.h"
|
||||
#include "src/compiler/basic-block-instrumentor.h"
|
||||
#include "src/compiler/change-lowering.h"
|
||||
#include "src/compiler/code-generator.h"
|
||||
#include "src/compiler/graph-replay.h"
|
||||
@ -315,6 +316,8 @@ Handle<Code> Pipeline::GenerateCode() {
|
||||
VerifyAndPrintGraph(&graph, "Lowered generic");
|
||||
}
|
||||
|
||||
source_positions.RemoveDecorator();
|
||||
|
||||
Handle<Code> code = Handle<Code>::null();
|
||||
{
|
||||
// Compute a schedule.
|
||||
@ -381,6 +384,11 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph,
|
||||
DCHECK_NOT_NULL(schedule);
|
||||
CHECK(SupportedBackend());
|
||||
|
||||
BasicBlockProfiler::Data* profiler_data = NULL;
|
||||
if (FLAG_turbo_profiling) {
|
||||
profiler_data = BasicBlockInstrumentor::Instrument(info_, graph, schedule);
|
||||
}
|
||||
|
||||
InstructionSequence sequence(linkage, graph, schedule);
|
||||
|
||||
// Select and schedule instructions covering the scheduled graph.
|
||||
@ -417,7 +425,15 @@ Handle<Code> Pipeline::GenerateCode(Linkage* linkage, Graph* graph,
|
||||
|
||||
// Generate native sequence.
|
||||
CodeGenerator generator(&sequence);
|
||||
return generator.GenerateCode();
|
||||
Handle<Code> code = generator.GenerateCode();
|
||||
if (profiler_data != NULL) {
|
||||
#if ENABLE_DISASSEMBLER
|
||||
OStringStream os;
|
||||
code->Disassemble(NULL, os);
|
||||
profiler_data->SetCode(&os);
|
||||
#endif
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,6 +22,7 @@ namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class BasicBlock;
|
||||
class BasicBlockInstrumentor;
|
||||
class Graph;
|
||||
class ConstructScheduleData;
|
||||
class CodeGenerator; // Because of a namespace bug in clang.
|
||||
@ -279,6 +280,7 @@ class Schedule : public GenericGraph<BasicBlock> {
|
||||
|
||||
private:
|
||||
friend class ScheduleVisualizer;
|
||||
friend class BasicBlockInstrumentor;
|
||||
|
||||
void SetControlInput(BasicBlock* block, Node* node) {
|
||||
block->control_input_ = node;
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/base/sys-info.h"
|
||||
#include "src/basic-block-profiler.h"
|
||||
#include "src/d8-debug.h"
|
||||
#include "src/debug.h"
|
||||
#include "src/natives.h"
|
||||
@ -1700,6 +1701,14 @@ int Shell::Main(int argc, char* argv[]) {
|
||||
RunShell(isolate);
|
||||
}
|
||||
}
|
||||
#ifndef V8_SHARED
|
||||
// Dump basic block profiling data.
|
||||
if (i::BasicBlockProfiler* profiler =
|
||||
reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
|
||||
i::OFStream os(stdout);
|
||||
os << *profiler;
|
||||
}
|
||||
#endif // !V8_SHARED
|
||||
isolate->Dispose();
|
||||
V8::Dispose();
|
||||
V8::ShutdownPlatform();
|
||||
|
@ -345,6 +345,7 @@ DEFINE_BOOL(turbo_deoptimization, false, "enable deoptimization in TurboFan")
|
||||
DEFINE_BOOL(turbo_inlining, false, "enable inlining in TurboFan")
|
||||
DEFINE_BOOL(trace_turbo_inlining, false, "trace TurboFan inlining")
|
||||
DEFINE_IMPLICATION(turbo_inlining, turbo_types)
|
||||
DEFINE_BOOL(turbo_profiling, false, "enable profiling in TurboFan")
|
||||
|
||||
DEFINE_INT(typed_array_max_size_in_heap, 64,
|
||||
"threshold for in-heap typed array")
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/base/sys-info.h"
|
||||
#include "src/base/utils/random-number-generator.h"
|
||||
#include "src/basic-block-profiler.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/compilation-cache.h"
|
||||
@ -1516,7 +1517,8 @@ Isolate::Isolate()
|
||||
num_sweeper_threads_(0),
|
||||
stress_deopt_count_(0),
|
||||
next_optimization_id_(0),
|
||||
use_counter_callback_(NULL) {
|
||||
use_counter_callback_(NULL),
|
||||
basic_block_profiler_(NULL) {
|
||||
{
|
||||
base::LockGuard<base::Mutex> lock_guard(thread_data_table_mutex_.Pointer());
|
||||
CHECK(thread_data_table_);
|
||||
@ -1640,6 +1642,10 @@ void Isolate::Deinit() {
|
||||
delete runtime_profiler_;
|
||||
runtime_profiler_ = NULL;
|
||||
}
|
||||
|
||||
delete basic_block_profiler_;
|
||||
basic_block_profiler_ = NULL;
|
||||
|
||||
heap_.TearDown();
|
||||
logger_->TearDown();
|
||||
|
||||
@ -2363,6 +2369,14 @@ void Isolate::CountUsage(v8::Isolate::UseCounterFeature feature) {
|
||||
}
|
||||
|
||||
|
||||
BasicBlockProfiler* Isolate::GetOrCreateBasicBlockProfiler() {
|
||||
if (basic_block_profiler_ == NULL) {
|
||||
basic_block_profiler_ = new BasicBlockProfiler();
|
||||
}
|
||||
return basic_block_profiler_;
|
||||
}
|
||||
|
||||
|
||||
bool StackLimitCheck::JsHasOverflowed() const {
|
||||
StackGuard* stack_guard = isolate_->stack_guard();
|
||||
#ifdef USE_SIMULATOR
|
||||
|
@ -32,6 +32,7 @@ class RandomNumberGenerator;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class BasicBlockProfiler;
|
||||
class Bootstrapper;
|
||||
class CallInterfaceDescriptorData;
|
||||
class CodeGenerator;
|
||||
@ -1107,6 +1108,9 @@ class Isolate {
|
||||
void SetUseCounterCallback(v8::Isolate::UseCounterCallback callback);
|
||||
void CountUsage(v8::Isolate::UseCounterFeature feature);
|
||||
|
||||
BasicBlockProfiler* GetOrCreateBasicBlockProfiler();
|
||||
BasicBlockProfiler* basic_block_profiler() { return basic_block_profiler_; }
|
||||
|
||||
static Isolate* NewForTesting() { return new Isolate(); }
|
||||
|
||||
private:
|
||||
@ -1327,6 +1331,7 @@ class Isolate {
|
||||
List<CallCompletedCallback> call_completed_callbacks_;
|
||||
|
||||
v8::Isolate::UseCounterCallback use_counter_callback_;
|
||||
BasicBlockProfiler* basic_block_profiler_;
|
||||
|
||||
friend class ExecutionAccess;
|
||||
friend class HandleScopeImplementer;
|
||||
|
@ -53,6 +53,7 @@
|
||||
'compiler/graph-tester.h',
|
||||
'compiler/simplified-graph-builder.cc',
|
||||
'compiler/simplified-graph-builder.h',
|
||||
'compiler/test-basic-block-profiler.cc',
|
||||
'compiler/test-branch-combine.cc',
|
||||
'compiler/test-changes-lowering.cc',
|
||||
'compiler/test-codegen-deopt.cc',
|
||||
|
114
test/cctest/compiler/test-basic-block-profiler.cc
Normal file
114
test/cctest/compiler/test-basic-block-profiler.cc
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2014 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/v8.h"
|
||||
|
||||
#include "src/basic-block-profiler.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
#include "test/cctest/compiler/codegen-tester.h"
|
||||
|
||||
#if V8_TURBOFAN_TARGET
|
||||
|
||||
using namespace v8::internal;
|
||||
using namespace v8::internal::compiler;
|
||||
|
||||
typedef RawMachineAssembler::Label MLabel;
|
||||
|
||||
class BasicBlockProfilerTest : public RawMachineAssemblerTester<int32_t> {
|
||||
public:
|
||||
BasicBlockProfilerTest() : RawMachineAssemblerTester<int32_t>(kMachInt32) {
|
||||
FLAG_turbo_profiling = true;
|
||||
}
|
||||
|
||||
void ResetCounts() { isolate()->basic_block_profiler()->ResetCounts(); }
|
||||
|
||||
void Expect(size_t size, uint32_t* expected) {
|
||||
CHECK_NE(NULL, isolate()->basic_block_profiler());
|
||||
const BasicBlockProfiler::DataList* l =
|
||||
isolate()->basic_block_profiler()->data_list();
|
||||
CHECK_NE(0, static_cast<int>(l->size()));
|
||||
const BasicBlockProfiler::Data* data = l->back();
|
||||
CHECK_EQ(static_cast<int>(size), static_cast<int>(data->n_blocks()));
|
||||
const uint32_t* counts = data->counts();
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
CHECK_EQ(static_cast<int>(expected[i]), static_cast<int>(counts[i]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST(ProfileDiamond) {
|
||||
BasicBlockProfilerTest m;
|
||||
|
||||
MLabel blocka, blockb, end;
|
||||
m.Branch(m.Parameter(0), &blocka, &blockb);
|
||||
m.Bind(&blocka);
|
||||
m.Goto(&end);
|
||||
m.Bind(&blockb);
|
||||
m.Goto(&end);
|
||||
m.Bind(&end);
|
||||
m.Return(m.Int32Constant(0));
|
||||
|
||||
m.GenerateCode();
|
||||
{
|
||||
uint32_t expected[] = {0, 0, 0, 0};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
|
||||
m.Call(0);
|
||||
{
|
||||
uint32_t expected[] = {1, 1, 0, 1};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
|
||||
m.ResetCounts();
|
||||
|
||||
m.Call(1);
|
||||
{
|
||||
uint32_t expected[] = {1, 0, 1, 1};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
|
||||
m.Call(0);
|
||||
{
|
||||
uint32_t expected[] = {2, 1, 1, 2};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(ProfileLoop) {
|
||||
BasicBlockProfilerTest m;
|
||||
|
||||
MLabel header, body, end;
|
||||
Node* one = m.Int32Constant(1);
|
||||
m.Goto(&header);
|
||||
|
||||
m.Bind(&header);
|
||||
Node* count = m.Phi(kMachInt32, m.Parameter(0), one);
|
||||
m.Branch(count, &body, &end);
|
||||
|
||||
m.Bind(&body);
|
||||
count->ReplaceInput(1, m.Int32Sub(count, one));
|
||||
m.Goto(&header);
|
||||
|
||||
m.Bind(&end);
|
||||
m.Return(one);
|
||||
|
||||
m.GenerateCode();
|
||||
{
|
||||
uint32_t expected[] = {0, 0, 0, 0};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
|
||||
uint32_t runs[] = {0, 1, 500, 10000};
|
||||
for (size_t i = 0; i < arraysize(runs); i++) {
|
||||
m.ResetCounts();
|
||||
CHECK_EQ(1, m.Call(static_cast<int>(runs[i])));
|
||||
uint32_t expected[] = {1, runs[i] + 1, runs[i], 1};
|
||||
m.Expect(arraysize(expected), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // V8_TURBOFAN_TARGET
|
@ -351,6 +351,8 @@
|
||||
'../../src/background-parsing-task.h',
|
||||
'../../src/bailout-reason.cc',
|
||||
'../../src/bailout-reason.h',
|
||||
'../../src/basic-block-profiler.cc',
|
||||
'../../src/basic-block-profiler.h',
|
||||
'../../src/bignum-dtoa.cc',
|
||||
'../../src/bignum-dtoa.h',
|
||||
'../../src/bignum.cc',
|
||||
@ -382,6 +384,8 @@
|
||||
'../../src/compiler/access-builder.h',
|
||||
'../../src/compiler/ast-graph-builder.cc',
|
||||
'../../src/compiler/ast-graph-builder.h',
|
||||
'../../src/compiler/basic-block-instrumentor.cc',
|
||||
'../../src/compiler/basic-block-instrumentor.h',
|
||||
'../../src/compiler/change-lowering.cc',
|
||||
'../../src/compiler/change-lowering.h',
|
||||
'../../src/compiler/code-generator-impl.h',
|
||||
|
Loading…
Reference in New Issue
Block a user