"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",
"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",
--- /dev/null
+// 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
--- /dev/null
+// 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_
--- /dev/null
+// 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
--- /dev/null
+// 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
#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"
VerifyAndPrintGraph(&graph, "Lowered generic");
}
+ source_positions.RemoveDecorator();
+
Handle<Code> code = Handle<Code>::null();
{
// Compute a schedule.
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.
// 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;
}
namespace compiler {
class BasicBlock;
+class BasicBlockInstrumentor;
class Graph;
class ConstructScheduleData;
class CodeGenerator; // Because of a namespace bug in clang.
private:
friend class ScheduleVisualizer;
+ friend class BasicBlockInstrumentor;
void SetControlInput(BasicBlock* block, Node* node) {
block->control_input_ = node;
#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"
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();
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")
#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"
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_);
delete runtime_profiler_;
runtime_profiler_ = NULL;
}
+
+ delete basic_block_profiler_;
+ basic_block_profiler_ = NULL;
+
heap_.TearDown();
logger_->TearDown();
}
+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
namespace internal {
+class BasicBlockProfiler;
class Bootstrapper;
class CallInterfaceDescriptorData;
class CodeGenerator;
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:
List<CallCompletedCallback> call_completed_callbacks_;
v8::Isolate::UseCounterCallback use_counter_callback_;
+ BasicBlockProfiler* basic_block_profiler_;
friend class ExecutionAccess;
friend class HandleScopeImplementer;
'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',
--- /dev/null
+// 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
'../../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',
'../../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',