"src/codegen.h",
"src/compilation-cache.cc",
"src/compilation-cache.h",
+ "src/compilation-statistics.cc",
+ "src/compilation-statistics.h",
"src/compiler/access-builder.cc",
"src/compiler/access-builder.h",
"src/compiler/ast-graph-builder.cc",
"src/compiler/phi-reducer.h",
"src/compiler/pipeline.cc",
"src/compiler/pipeline.h",
+ "src/compiler/pipeline-statistics.cc",
+ "src/compiler/pipeline-statistics.h",
"src/compiler/raw-machine-assembler.cc",
"src/compiler/raw-machine-assembler.h",
"src/compiler/register-allocator.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 <iostream> // NOLINT(readability/streams)
+#include <vector>
+
+#include "src/base/platform/platform.h"
+#include "src/compilation-statistics.h"
+
+namespace v8 {
+namespace internal {
+
+void CompilationStatistics::RecordPhaseStats(const char* phase_kind_name,
+ const char* phase_name,
+ const BasicStats& stats) {
+ std::string phase_name_str(phase_name);
+ auto it = phase_map_.find(phase_name_str);
+ if (it == phase_map_.end()) {
+ PhaseStats phase_stats(phase_map_.size(), phase_kind_name);
+ it = phase_map_.insert(std::make_pair(phase_name_str, phase_stats)).first;
+ }
+ it->second.Accumulate(stats);
+}
+
+
+void CompilationStatistics::RecordPhaseKindStats(const char* phase_kind_name,
+ const BasicStats& stats) {
+ std::string phase_kind_name_str(phase_kind_name);
+ auto it = phase_kind_map_.find(phase_kind_name_str);
+ if (it == phase_kind_map_.end()) {
+ PhaseKindStats phase_kind_stats(phase_kind_map_.size());
+ it = phase_kind_map_.insert(std::make_pair(phase_kind_name_str,
+ phase_kind_stats)).first;
+ }
+ it->second.Accumulate(stats);
+}
+
+
+void CompilationStatistics::RecordTotalStats(size_t source_size,
+ const BasicStats& stats) {
+ source_size += source_size;
+ total_stats_.Accumulate(stats);
+}
+
+
+void CompilationStatistics::BasicStats::Accumulate(const BasicStats& stats) {
+ delta_ += stats.delta_;
+ total_allocated_bytes_ += stats.total_allocated_bytes_;
+ if (stats.max_allocated_bytes_ > max_allocated_bytes_) {
+ max_allocated_bytes_ = stats.max_allocated_bytes_;
+ function_name_ = stats.function_name_;
+ }
+}
+
+
+static void WriteLine(std::ostream& os, const char* name,
+ const CompilationStatistics::BasicStats& stats,
+ const CompilationStatistics::BasicStats& total_stats) {
+ const size_t kBufferSize = 128;
+ char buffer[kBufferSize];
+
+ double ms = stats.delta_.InMillisecondsF();
+ double percent = stats.delta_.PercentOf(total_stats.delta_);
+ double size_percent =
+ static_cast<double>(stats.total_allocated_bytes_ * 100) /
+ static_cast<double>(total_stats.total_allocated_bytes_);
+ base::OS::SNPrintF(buffer, kBufferSize,
+ "%28s %10.3f ms / %5.1f %% %10u total / %5.1f %% %10u max",
+ name, ms, percent, stats.total_allocated_bytes_,
+ size_percent, stats.max_allocated_bytes_);
+
+ os << buffer;
+ if (stats.function_name_.size() > 0) {
+ os << " : " << stats.function_name_.c_str();
+ }
+ os << std::endl;
+}
+
+
+static void WriteFullLine(std::ostream& os) {
+ os << "-----------------------------------------------"
+ "-----------------------------------------------\n";
+}
+
+
+static void WriteHeader(std::ostream& os) {
+ WriteFullLine(os);
+ os << " Turbofan timing results:\n";
+ WriteFullLine(os);
+}
+
+
+static void WritePhaseKindBreak(std::ostream& os) {
+ os << " ------------------"
+ "-----------------------------------------------\n";
+}
+
+
+std::ostream& operator<<(std::ostream& os, const CompilationStatistics& s) {
+ // phase_kind_map_ and phase_map_ don't get mutated, so store a bunch of
+ // pointers into them.
+
+ typedef std::vector<CompilationStatistics::PhaseKindMap::const_iterator>
+ SortedPhaseKinds;
+ SortedPhaseKinds sorted_phase_kinds(s.phase_kind_map_.size());
+ for (auto it = s.phase_kind_map_.begin(); it != s.phase_kind_map_.end();
+ ++it) {
+ sorted_phase_kinds[it->second.insert_order_] = it;
+ }
+
+ typedef std::vector<CompilationStatistics::PhaseMap::const_iterator>
+ SortedPhases;
+ SortedPhases sorted_phases(s.phase_map_.size());
+ for (auto it = s.phase_map_.begin(); it != s.phase_map_.end(); ++it) {
+ sorted_phases[it->second.insert_order_] = it;
+ }
+
+ WriteHeader(os);
+ for (auto phase_kind_it : sorted_phase_kinds) {
+ const auto& phase_kind_name = phase_kind_it->first;
+ for (auto phase_it : sorted_phases) {
+ const auto& phase_stats = phase_it->second;
+ if (phase_stats.phase_kind_name_ != phase_kind_name) continue;
+ const auto& phase_name = phase_it->first;
+ WriteLine(os, phase_name.c_str(), phase_stats, s.total_stats_);
+ }
+ WritePhaseKindBreak(os);
+ const auto& phase_kind_stats = phase_kind_it->second;
+ WriteLine(os, phase_kind_name.c_str(), phase_kind_stats, s.total_stats_);
+ os << std::endl;
+ }
+ WriteFullLine(os);
+ WriteLine(os, "totals", s.total_stats_, s.total_stats_);
+
+ 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_COMPILATION_STATISTICS_H_
+#define V8_COMPILATION_STATISTICS_H_
+
+#include <map>
+#include <string>
+
+#include "src/allocation.h"
+#include "src/base/platform/time.h"
+
+namespace v8 {
+namespace internal {
+
+class CompilationInfo;
+
+class CompilationStatistics FINAL : public Malloced {
+ public:
+ CompilationStatistics() {}
+
+ class BasicStats {
+ public:
+ BasicStats() : total_allocated_bytes_(0), max_allocated_bytes_(0) {}
+
+ void Accumulate(const BasicStats& stats);
+
+ base::TimeDelta delta_;
+ size_t total_allocated_bytes_;
+ size_t max_allocated_bytes_;
+ std::string function_name_;
+ };
+
+ void RecordPhaseStats(const char* phase_kind_name, const char* phase_name,
+ const BasicStats& stats);
+
+ void RecordPhaseKindStats(const char* phase_kind_name,
+ const BasicStats& stats);
+
+ void RecordTotalStats(size_t source_size, const BasicStats& stats);
+
+ private:
+ class TotalStats : public BasicStats {
+ public:
+ TotalStats() : source_size_(0) {}
+ uint64_t source_size_;
+ };
+
+ class OrderedStats : public BasicStats {
+ public:
+ explicit OrderedStats(size_t insert_order) : insert_order_(insert_order) {}
+ size_t insert_order_;
+ };
+
+ class PhaseStats : public OrderedStats {
+ public:
+ PhaseStats(size_t insert_order, const char* phase_kind_name)
+ : OrderedStats(insert_order), phase_kind_name_(phase_kind_name) {}
+ std::string phase_kind_name_;
+ };
+
+ friend std::ostream& operator<<(std::ostream& os,
+ const CompilationStatistics& s);
+
+ typedef OrderedStats PhaseKindStats;
+ typedef std::map<std::string, PhaseKindStats> PhaseKindMap;
+ typedef std::map<std::string, PhaseStats> PhaseMap;
+
+ TotalStats total_stats_;
+ PhaseKindMap phase_kind_map_;
+ PhaseMap phase_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompilationStatistics);
+};
+
+std::ostream& operator<<(std::ostream& os, const CompilationStatistics& s);
+
+} // namespace internal
+} // namespace v8
+
+#endif
--- /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.h"
+#include "src/compiler/pipeline-statistics.h"
+#include "src/compiler/zone-pool.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+void PipelineStatistics::CommonStats::Begin(
+ PipelineStatistics* pipeline_stats) {
+ DCHECK(scope_.is_empty());
+ scope_.Reset(new ZonePool::StatsScope(pipeline_stats->zone_pool_));
+ timer_.Start();
+ outer_zone_initial_size_ = pipeline_stats->OuterZoneSize();
+}
+
+
+void PipelineStatistics::CommonStats::End(
+ PipelineStatistics* pipeline_stats,
+ CompilationStatistics::BasicStats* diff) {
+ DCHECK(!scope_.is_empty());
+ diff->function_name_ = pipeline_stats->function_name_;
+ diff->delta_ = timer_.Elapsed();
+ size_t outer_zone_diff =
+ pipeline_stats->OuterZoneSize() - outer_zone_initial_size_;
+ diff->max_allocated_bytes_ = outer_zone_diff + scope_->GetMaxAllocatedBytes();
+ diff->total_allocated_bytes_ =
+ outer_zone_diff + scope_->GetTotalAllocatedBytes();
+ scope_.Reset(NULL);
+ timer_.Stop();
+}
+
+
+PipelineStatistics::PipelineStatistics(CompilationInfo* info,
+ ZonePool* zone_pool)
+ : isolate_(info->zone()->isolate()),
+ outer_zone_(info->zone()),
+ zone_pool_(zone_pool),
+ compilation_stats_(isolate_->GetTurboStatistics()),
+ source_size_(0),
+ phase_kind_name_(NULL),
+ phase_name_(NULL) {
+ if (!info->shared_info().is_null()) {
+ source_size_ = static_cast<size_t>(info->shared_info()->SourceSize());
+ SmartArrayPointer<char> name =
+ info->shared_info()->DebugName()->ToCString();
+ function_name_ = name.get();
+ }
+ total_stats_.Begin(this);
+}
+
+
+PipelineStatistics::~PipelineStatistics() {
+ if (InPhaseKind()) EndPhaseKind();
+ CompilationStatistics::BasicStats diff;
+ total_stats_.End(this, &diff);
+ compilation_stats_->RecordTotalStats(source_size_, diff);
+}
+
+
+void PipelineStatistics::BeginPhaseKind(const char* phase_kind_name) {
+ DCHECK(!InPhase());
+ if (InPhaseKind()) EndPhaseKind();
+ phase_kind_name_ = phase_kind_name;
+ phase_kind_stats_.Begin(this);
+}
+
+
+void PipelineStatistics::EndPhaseKind() {
+ DCHECK(!InPhase());
+ CompilationStatistics::BasicStats diff;
+ phase_kind_stats_.End(this, &diff);
+ compilation_stats_->RecordPhaseKindStats(phase_kind_name_, diff);
+}
+
+
+void PipelineStatistics::BeginPhase(const char* name) {
+ DCHECK(InPhaseKind());
+ phase_name_ = name;
+ phase_stats_.Begin(this);
+}
+
+
+void PipelineStatistics::EndPhase() {
+ DCHECK(InPhaseKind());
+ CompilationStatistics::BasicStats diff;
+ phase_stats_.End(this, &diff);
+ compilation_stats_->RecordPhaseStats(phase_kind_name_, phase_name_, diff);
+}
+
+} // 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_PIPELINE_STATISTICS_H_
+#define V8_COMPILER_PIPELINE_STATISTICS_H_
+
+#include <string>
+
+#include "src/compilation-statistics.h"
+#include "src/compiler/zone-pool.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class PhaseScope;
+
+class PipelineStatistics : public Malloced {
+ public:
+ PipelineStatistics(CompilationInfo* info, ZonePool* zone_pool);
+ ~PipelineStatistics();
+
+ void BeginPhaseKind(const char* phase_kind_name);
+
+ private:
+ size_t OuterZoneSize() {
+ return static_cast<size_t>(outer_zone_->allocation_size());
+ }
+
+ class CommonStats {
+ public:
+ CommonStats() : outer_zone_initial_size_(0) {}
+
+ void Begin(PipelineStatistics* pipeline_stats);
+ void End(PipelineStatistics* pipeline_stats,
+ CompilationStatistics::BasicStats* diff);
+
+ SmartPointer<ZonePool::StatsScope> scope_;
+ base::ElapsedTimer timer_;
+ size_t outer_zone_initial_size_;
+ };
+
+ bool InPhaseKind() { return !phase_kind_stats_.scope_.is_empty(); }
+ void EndPhaseKind();
+
+ friend class PhaseScope;
+ bool InPhase() { return !phase_stats_.scope_.is_empty(); }
+ void BeginPhase(const char* name);
+ void EndPhase();
+
+ Isolate* isolate_;
+ Zone* outer_zone_;
+ ZonePool* zone_pool_;
+ CompilationStatistics* compilation_stats_;
+ std::string function_name_;
+
+ // Stats for the entire compilation.
+ CommonStats total_stats_;
+ size_t source_size_;
+
+ // Stats for phase kind.
+ const char* phase_kind_name_;
+ CommonStats phase_kind_stats_;
+
+ // Stats for phase.
+ const char* phase_name_;
+ CommonStats phase_stats_;
+
+ DISALLOW_COPY_AND_ASSIGN(PipelineStatistics);
+};
+
+
+class PhaseScope {
+ public:
+ PhaseScope(PipelineStatistics* pipeline_stats, const char* name)
+ : pipeline_stats_(pipeline_stats) {
+ if (pipeline_stats_ != NULL) pipeline_stats_->BeginPhase(name);
+ }
+ ~PhaseScope() {
+ if (pipeline_stats_ != NULL) pipeline_stats_->EndPhase();
+ }
+
+ private:
+ PipelineStatistics* const pipeline_stats_;
+
+ DISALLOW_COPY_AND_ASSIGN(PhaseScope);
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/compiler/pipeline.h"
-
#include <sstream>
#include "src/base/platform/elapsed-timer.h"
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/machine-operator-reducer.h"
#include "src/compiler/phi-reducer.h"
+#include "src/compiler/pipeline.h"
+#include "src/compiler/pipeline-statistics.h"
#include "src/compiler/register-allocator.h"
#include "src/compiler/schedule.h"
#include "src/compiler/scheduler.h"
#include "src/compiler/value-numbering-reducer.h"
#include "src/compiler/verifier.h"
#include "src/compiler/zone-pool.h"
-#include "src/hydrogen.h"
#include "src/ostreams.h"
#include "src/utils.h"
namespace internal {
namespace compiler {
-class PhaseStats {
- public:
- enum PhaseKind { CREATE_GRAPH, OPTIMIZATION, CODEGEN };
-
- PhaseStats(CompilationInfo* info, ZonePool* zone_pool, PhaseKind kind,
- const char* name)
- : info_(info),
- stats_scope_(zone_pool),
- kind_(kind),
- name_(name),
- size_(0) {
- if (FLAG_turbo_stats) {
- timer_.Start();
- size_ = info_->zone()->allocation_size();
- }
- }
-
- ~PhaseStats() {
- if (FLAG_turbo_stats) {
- base::TimeDelta delta = timer_.Elapsed();
- size_t bytes = info_->zone()->allocation_size() +
- stats_scope_.GetMaxAllocatedBytes() - size_;
- HStatistics* stats = info_->isolate()->GetTStatistics();
- stats->SaveTiming(name_, delta, static_cast<int>(bytes));
-
- switch (kind_) {
- case CREATE_GRAPH:
- stats->IncrementCreateGraph(delta);
- break;
- case OPTIMIZATION:
- stats->IncrementOptimizeGraph(delta);
- break;
- case CODEGEN:
- stats->IncrementGenerateCode(delta);
- break;
- }
- }
- }
-
- private:
- CompilationInfo* info_;
- ZonePool::StatsScope stats_scope_;
- PhaseKind kind_;
- const char* name_;
- size_t size_;
- base::ElapsedTimer timer_;
-};
-
-
static inline bool VerifyGraphs() {
#ifdef DEBUG
return true;
return Handle<Code>::null();
}
- if (FLAG_turbo_stats) isolate()->GetTStatistics()->Initialize(info_);
+ ZonePool zone_pool(isolate());
+
+ SmartPointer<PipelineStatistics> pipeline_statistics;
+ if (FLAG_turbo_stats) {
+ pipeline_statistics.Reset(new PipelineStatistics(info(), &zone_pool));
+ pipeline_statistics->BeginPhaseKind("create graph");
+ }
if (FLAG_trace_turbo) {
OFStream os(stdout);
PrintCompilationStart();
}
- ZonePool zone_pool(isolate());
-
// Build the graph.
Graph graph(zone());
SourcePositionTable source_positions(&graph);
JSGraph jsgraph(&graph, &common, &javascript, &machine);
Node* context_node;
{
- PhaseStats graph_builder_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "graph builder");
+ PhaseScope phase_scope(pipeline_statistics.get(), "graph builder");
ZonePool::Scope zone_scope(&zone_pool);
AstGraphBuilderWithPositions graph_builder(zone_scope.zone(), info(),
&jsgraph, &source_positions);
context_node = graph_builder.GetFunctionContext();
}
{
- PhaseStats phi_reducer_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "phi reduction");
+ PhaseScope phase_scope(pipeline_statistics.get(), "phi reduction");
PhiReducer phi_reducer;
GraphReducer graph_reducer(&graph);
graph_reducer.AddReducer(&phi_reducer);
}
if (info()->is_inlining_enabled()) {
+ PhaseScope phase_scope(pipeline_statistics.get(), "inlining");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
ZonePool::Scope zone_scope(&zone_pool);
if (info()->is_typing_enabled()) {
{
// Type the graph.
- PhaseStats typer_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "typer");
+ PhaseScope phase_scope(pipeline_statistics.get(), "typer");
typer.Run();
VerifyAndPrintGraph(&graph, "Typed");
}
+ }
+
+ if (!pipeline_statistics.is_empty()) {
+ pipeline_statistics->BeginPhaseKind("lowering");
+ }
+
+ if (info()->is_typing_enabled()) {
{
// Lower JSOperators where we can determine types.
- PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "typed lowering");
+ PhaseScope phase_scope(pipeline_statistics.get(), "typed lowering");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
ValueNumberingReducer vn_reducer(zone());
}
{
// Lower simplified operators and insert changes.
- PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "simplified lowering");
+ PhaseScope phase_scope(pipeline_statistics.get(), "simplified lowering");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
SimplifiedLowering lowering(&jsgraph);
}
{
// Lower changes that have been inserted before.
- PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::OPTIMIZATION,
- "change lowering");
+ PhaseScope phase_scope(pipeline_statistics.get(), "change lowering");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
Linkage linkage(info());
}
{
+ PhaseScope phase_scope(pipeline_statistics.get(), "control reduction");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
- PhaseStats control_reducer_stats(
- info(), &zone_pool, PhaseStats::CREATE_GRAPH, "control reduction");
ZonePool::Scope zone_scope(&zone_pool);
ControlReducer::ReduceGraph(zone_scope.zone(), &jsgraph, &common);
{
// Lower any remaining generic JSOperators.
- PhaseStats lowering_stats(info(), &zone_pool, PhaseStats::CREATE_GRAPH,
- "generic lowering");
+ PhaseScope phase_scope(pipeline_statistics.get(), "generic lowering");
SourcePositionTable::Scope pos(&source_positions,
SourcePosition::Unknown());
JSGenericLowering lowering(info(), &jsgraph);
VerifyAndPrintGraph(&graph, "Lowered generic", true);
}
+ if (!pipeline_statistics.is_empty()) {
+ pipeline_statistics->BeginPhaseKind("code generation");
+ }
+
source_positions.RemoveDecorator();
- Handle<Code> code = Handle<Code>::null();
+ Schedule* schedule;
{
+ PhaseScope phase_scope(pipeline_statistics.get(), "scheduling");
// Compute a schedule.
- Schedule* schedule = ComputeSchedule(&zone_pool, &graph);
+ schedule = ComputeSchedule(&zone_pool, &graph);
+ }
+
+ Handle<Code> code = Handle<Code>::null();
+ {
// Generate optimized code.
- PhaseStats codegen_stats(info(), &zone_pool, PhaseStats::CODEGEN,
- "codegen");
Linkage linkage(info());
- code =
- GenerateCode(&zone_pool, &linkage, &graph, schedule, &source_positions);
+ code = GenerateCode(pipeline_statistics.get(), &zone_pool, &linkage, &graph,
+ schedule, &source_positions);
info()->SetCode(code);
}
Schedule* Pipeline::ComputeSchedule(ZonePool* zone_pool, Graph* graph) {
- PhaseStats schedule_stats(info(), zone_pool, PhaseStats::CODEGEN,
- "scheduling");
Schedule* schedule = Scheduler::ComputeSchedule(zone_pool, graph);
TraceSchedule(schedule);
if (VerifyGraphs()) ScheduleVerifier::Run(schedule);
TraceSchedule(schedule);
SourcePositionTable source_positions(graph);
- Handle<Code> code =
- GenerateCode(&zone_pool, linkage, graph, schedule, &source_positions);
+ Handle<Code> code = GenerateCode(NULL, &zone_pool, linkage, graph, schedule,
+ &source_positions);
#if ENABLE_DISASSEMBLER
if (!code.is_null() && FLAG_print_opt_code) {
CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
}
-Handle<Code> Pipeline::GenerateCode(ZonePool* zone_pool, Linkage* linkage,
+Handle<Code> Pipeline::GenerateCode(PipelineStatistics* pipeline_statistics,
+ ZonePool* zone_pool, Linkage* linkage,
Graph* graph, Schedule* schedule,
SourcePositionTable* source_positions) {
DCHECK_NOT_NULL(graph);
// Select and schedule instructions covering the scheduled graph.
{
+ PhaseScope phase_scope(pipeline_statistics, "select instructions");
ZonePool::Scope zone_scope(zone_pool);
InstructionSelector selector(zone_scope.zone(), linkage, &sequence,
schedule, source_positions);
ZonePool::Scope zone_scope(zone_pool);
RegisterAllocator allocator(zone_scope.zone(), &frame, linkage->info(),
&sequence);
- if (!allocator.Allocate(zone_pool)) {
+ if (!allocator.Allocate(pipeline_statistics)) {
linkage->info()->AbortOptimization(kNotEnoughVirtualRegistersRegalloc);
return Handle<Code>::null();
}
}
// Generate native sequence.
- CodeGenerator generator(&frame, linkage, &sequence);
- Handle<Code> code = generator.GenerateCode();
+ Handle<Code> code;
+ {
+ PhaseScope phase_scope(pipeline_statistics, "generate code");
+ CodeGenerator generator(&frame, linkage, &sequence);
+ code = generator.GenerateCode();
+ }
if (profiler_data != NULL) {
#if ENABLE_DISASSEMBLER
std::ostringstream os;
class Graph;
class InstructionSequence;
class Linkage;
+class PipelineStatistics;
class RegisterAllocator;
class Schedule;
class SourcePositionTable;
void PrintAllocator(const char* phase, const RegisterAllocator* allocator);
void VerifyAndPrintGraph(Graph* graph, const char* phase,
bool untyped = false);
- Handle<Code> GenerateCode(ZonePool* zone_pool, Linkage* linkage, Graph* graph,
+ Handle<Code> GenerateCode(PipelineStatistics* pipeline_statistics,
+ ZonePool* zone_pool, Linkage* linkage, Graph* graph,
Schedule* schedule,
SourcePositionTable* source_positions);
};
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/compiler/register-allocator.h"
-
#include "src/compiler/linkage.h"
-#include "src/hydrogen.h"
+#include "src/compiler/pipeline-statistics.h"
+#include "src/compiler/register-allocator.h"
#include "src/string-stream.h"
namespace v8 {
CompilationInfo* info,
InstructionSequence* code)
: zone_(local_zone),
- zone_pool_(NULL),
frame_(frame),
info_(info),
code_(code),
}
-bool RegisterAllocator::Allocate(ZonePool* zone_pool) {
- DCHECK_EQ(NULL, zone_pool_);
- zone_pool_ = zone_pool;
+bool RegisterAllocator::Allocate(PipelineStatistics* stats) {
assigned_registers_ = new (code_zone())
BitVector(Register::NumAllocatableRegisters(), code_zone());
assigned_double_registers_ = new (code_zone())
BitVector(DoubleRegister::NumAllocatableAliasedRegisters(), code_zone());
- MeetRegisterConstraints();
+ {
+ PhaseScope phase_scope(stats, "meet register constraints");
+ MeetRegisterConstraints();
+ }
if (!AllocationOk()) return false;
- ResolvePhis();
- BuildLiveRanges();
- AllocateGeneralRegisters();
+ {
+ PhaseScope phase_scope(stats, "resolve phis");
+ ResolvePhis();
+ }
+ {
+ PhaseScope phase_scope(stats, "build live ranges");
+ BuildLiveRanges();
+ }
+ {
+ PhaseScope phase_scope(stats, "allocate general registers");
+ AllocateGeneralRegisters();
+ }
if (!AllocationOk()) return false;
- AllocateDoubleRegisters();
+ {
+ PhaseScope phase_scope(stats, "allocate double registers");
+ AllocateDoubleRegisters();
+ }
if (!AllocationOk()) return false;
- PopulatePointerMaps();
- ConnectRanges();
- ResolveControlFlow();
+ {
+ PhaseScope phase_scope(stats, "populate pointer maps");
+ PopulatePointerMaps();
+ }
+ {
+ PhaseScope phase_scope(stats, "connect ranges");
+ ConnectRanges();
+ }
+ {
+ PhaseScope phase_scope(stats, "resolve control flow");
+ ResolveControlFlow();
+ }
frame()->SetAllocatedRegisters(assigned_registers_);
frame()->SetAllocatedDoubleRegisters(assigned_double_registers_);
return true;
}
-class RegisterAllocatorPhase : public CompilationPhase {
- public:
- RegisterAllocatorPhase(const char* name, RegisterAllocator* allocator)
- : CompilationPhase(name, allocator->info()),
- allocator_(allocator),
- allocator_zone_start_allocation_size_(0),
- stats_(NULL) {
- if (FLAG_turbo_stats) {
- allocator_zone_start_allocation_size_ =
- allocator->info()->zone()->allocation_size();
- if (allocator->zone_pool() != NULL) {
- stats_ = new ZonePool::StatsScope(allocator->zone_pool());
- }
- }
- }
-
- ~RegisterAllocatorPhase() {
- if (FLAG_turbo_stats) {
- unsigned size = allocator_->info()->zone()->allocation_size() -
- allocator_zone_start_allocation_size_;
- if (stats_ != NULL) {
- size += static_cast<unsigned>(stats_->GetMaxAllocatedBytes());
- }
- isolate()->GetTStatistics()->SaveTiming(name(), base::TimeDelta(), size);
- }
- delete stats_;
-#ifdef DEBUG
- if (allocator_ != NULL) allocator_->Verify();
-#endif
- }
-
- private:
- RegisterAllocator* allocator_;
- unsigned allocator_zone_start_allocation_size_;
- ZonePool::StatsScope* stats_;
-
- DISALLOW_COPY_AND_ASSIGN(RegisterAllocatorPhase);
-};
-
-
void RegisterAllocator::MeetRegisterConstraints() {
- RegisterAllocatorPhase phase("L_Register constraints", this);
for (int i = 0; i < code()->InstructionBlockCount(); ++i) {
MeetRegisterConstraints(
code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
void RegisterAllocator::ResolvePhis() {
- RegisterAllocatorPhase phase("L_Resolve phis", this);
-
// Process the blocks in reverse order.
for (int i = code()->InstructionBlockCount() - 1; i >= 0; --i) {
ResolvePhis(code()->InstructionBlockAt(BasicBlock::RpoNumber::FromInt(i)));
void RegisterAllocator::ConnectRanges() {
- RegisterAllocatorPhase phase("L_Connect ranges", this);
for (int i = 0; i < live_ranges()->length(); ++i) {
LiveRange* first_range = live_ranges()->at(i);
if (first_range == NULL || first_range->parent() != NULL) continue;
void RegisterAllocator::ResolveControlFlow() {
- RegisterAllocatorPhase phase("L_Resolve control flow", this);
for (int block_id = 1; block_id < code()->InstructionBlockCount();
++block_id) {
const InstructionBlock* block =
void RegisterAllocator::BuildLiveRanges() {
- RegisterAllocatorPhase phase("L_Build live ranges", this);
InitializeLivenessAnalysis();
// Process the blocks in reverse order.
for (int block_id = code()->InstructionBlockCount() - 1; block_id >= 0;
void RegisterAllocator::PopulatePointerMaps() {
- RegisterAllocatorPhase phase("L_Populate pointer maps", this);
-
DCHECK(SafePointsAreInOrder());
// Iterate over all safe point positions and record a pointer
void RegisterAllocator::AllocateGeneralRegisters() {
- RegisterAllocatorPhase phase("L_Allocate general registers", this);
num_registers_ = Register::NumAllocatableRegisters();
mode_ = GENERAL_REGISTERS;
AllocateRegisters();
void RegisterAllocator::AllocateDoubleRegisters() {
- RegisterAllocatorPhase phase("L_Allocate double registers", this);
num_registers_ = DoubleRegister::NumAllocatableAliasedRegisters();
mode_ = DOUBLE_REGISTERS;
AllocateRegisters();
namespace compiler {
+class PipelineStatistics;
+
enum RegisterKind {
UNALLOCATED_REGISTERS,
GENERAL_REGISTERS,
// Returns the register kind required by the given virtual register.
RegisterKind RequiredRegisterKind(int virtual_register) const;
- // TODO(dcarney): fix compilation phase stats to not require this.
- bool Allocate(ZonePool* zone_pool = NULL);
+ bool Allocate(PipelineStatistics* stats = NULL);
const ZoneList<LiveRange*>* live_ranges() const { return &live_ranges_; }
const Vector<LiveRange*>* fixed_live_ranges() const {
CompilationInfo* info() const { return info_; }
inline InstructionSequence* code() const { return code_; }
- ZonePool* zone_pool() const { return zone_pool_; }
// This zone is for datastructures only needed during register allocation.
inline Zone* zone() const { return zone_; }
Frame* frame() const { return frame_; }
Zone* const zone_;
- // TODO(dcarney): remove this.
- ZonePool* zone_pool_;
Frame* const frame_;
CompilationInfo* const info_;
InstructionSequence* const code_;
namespace compiler {
ZonePool::StatsScope::StatsScope(ZonePool* zone_pool)
- : zone_pool_(zone_pool), max_allocated_bytes_(0) {
+ : zone_pool_(zone_pool),
+ total_allocated_bytes_at_start_(zone_pool->GetTotalAllocatedBytes()),
+ max_allocated_bytes_(0) {
zone_pool_->stats_.push_back(this);
for (auto zone : zone_pool_->used_) {
size_t size = static_cast<size_t>(zone->allocation_size());
}
+size_t ZonePool::StatsScope::GetTotalAllocatedBytes() {
+ return zone_pool_->GetTotalAllocatedBytes() - total_allocated_bytes_at_start_;
+}
+
+
void ZonePool::StatsScope::ZoneReturned(Zone* zone) {
size_t current_total = GetCurrentAllocatedBytes();
// Update max.
size_t GetMaxAllocatedBytes();
size_t GetCurrentAllocatedBytes();
+ size_t GetTotalAllocatedBytes();
private:
friend class ZonePool;
ZonePool* const zone_pool_;
InitialValues initial_values_;
+ size_t total_allocated_bytes_at_start_;
size_t max_allocated_bytes_;
DISALLOW_COPY_AND_ASSIGN(StatsScope);
}
-void HStatistics::Print(const char* stats_name) {
+void HStatistics::Print() {
PrintF(
"\n"
"----------------------------------------"
"----------------------------------------\n"
- "--- %s timing results:\n"
+ "--- Hydrogen timing results:\n"
"----------------------------------------"
- "----------------------------------------\n",
- stats_name);
+ "----------------------------------------\n");
base::TimeDelta sum;
for (int i = 0; i < times_.length(); ++i) {
sum += times_[i];
source_size_(0) { }
void Initialize(CompilationInfo* info);
- void Print(const char* stats_name);
+ void Print();
void SaveTiming(const char* name, base::TimeDelta time, unsigned size);
void IncrementFullCodeGen(base::TimeDelta full_code_gen) {
#include <stdlib.h>
#include <fstream> // NOLINT(readability/streams)
+#include <iostream> // NOLINT(readability/streams)
#include "src/v8.h"
#include "src/bootstrapper.h"
#include "src/codegen.h"
#include "src/compilation-cache.h"
+#include "src/compilation-statistics.h"
#include "src/cpu-profiler.h"
#include "src/debug.h"
#include "src/deoptimizer.h"
heap_.mark_compact_collector()->EnsureSweepingCompleted();
}
- if (FLAG_turbo_stats) GetTStatistics()->Print("TurboFan");
- if (FLAG_hydrogen_stats) GetHStatistics()->Print("Hydrogen");
+ if (turbo_statistics() != NULL) {
+ std::cout << *turbo_statistics() << std::endl;
+ }
+ if (FLAG_hydrogen_stats) GetHStatistics()->Print();
if (FLAG_print_deopt_stress) {
PrintF(stdout, "=== Stress deopt counter: %u\n", stress_deopt_count_);
}
-HStatistics* Isolate::GetTStatistics() {
- if (tstatistics() == NULL) set_tstatistics(new HStatistics());
- return tstatistics();
+CompilationStatistics* Isolate::GetTurboStatistics() {
+ if (turbo_statistics() == NULL)
+ set_turbo_statistics(new CompilationStatistics());
+ return turbo_statistics();
}
class CodeStubDescriptor;
class CodeTracer;
class CompilationCache;
+class CompilationStatistics;
class ContextSlotCache;
class Counters;
class CpuFeatures;
V(int, pending_microtask_count, 0) \
V(bool, autorun_microtasks, true) \
V(HStatistics*, hstatistics, NULL) \
- V(HStatistics*, tstatistics, NULL) \
+ V(CompilationStatistics*, turbo_statistics, NULL) \
V(HTracer*, htracer, NULL) \
V(CodeTracer*, code_tracer, NULL) \
V(bool, fp_stubs_generated, false) \
int id() const { return static_cast<int>(id_); }
HStatistics* GetHStatistics();
- HStatistics* GetTStatistics();
+ CompilationStatistics* GetTurboStatistics();
HTracer* GetHTracer();
CodeTracer* GetCodeTracer();
ASSERT_EQ(total, zone_pool()->GetTotalAllocatedBytes());
}
- void Expect(ZonePool::StatsScope* stats, size_t current, size_t max) {
+ void Expect(ZonePool::StatsScope* stats, size_t current, size_t max,
+ size_t total) {
ASSERT_EQ(current, stats->GetCurrentAllocatedBytes());
ASSERT_EQ(max, stats->GetMaxAllocatedBytes());
+ ASSERT_EQ(total, stats->GetTotalAllocatedBytes());
}
size_t Allocate(Zone* zone) {
ExpectForPool(0, 0, 0);
{
ZonePool::StatsScope stats(zone_pool());
- Expect(&stats, 0, 0);
+ Expect(&stats, 0, 0, 0);
}
ExpectForPool(0, 0, 0);
{
before_deletion += Allocate(scopes[i]->zone()); // Add some stuff.
}
- Expect(&stats, before_deletion, before_deletion);
+ Expect(&stats, before_deletion, before_deletion, before_deletion);
ExpectForPool(before_stats + before_deletion, before_stats + before_deletion,
before_stats + before_deletion);
scopes[i] = new ZonePool::Scope(zone_pool());
}
- Expect(&stats, 0, before_deletion);
+ Expect(&stats, 0, before_deletion, before_deletion);
ExpectForPool(0, before_stats + before_deletion,
before_stats + before_deletion);
after_deletion += Allocate(scopes[i]->zone()); // Add some stuff.
}
- Expect(&stats, after_deletion, std::max(after_deletion, before_deletion));
+ Expect(&stats, after_deletion, std::max(after_deletion, before_deletion),
+ before_deletion + after_deletion);
ExpectForPool(after_deletion,
std::max(after_deletion, before_stats + before_deletion),
before_stats + before_deletion + after_deletion);
delete scopes[i];
}
- Expect(&stats, 0, std::max(after_deletion, before_deletion));
+ Expect(&stats, 0, std::max(after_deletion, before_deletion),
+ before_deletion + after_deletion);
ExpectForPool(0, std::max(after_deletion, before_stats + before_deletion),
before_stats + before_deletion + after_deletion);
}
total_allocated += bytes;
max_loop_allocation =
std::max(max_loop_allocation, outer_allocated + allocated);
- Expect(&inner_stats, allocated, allocated);
- Expect(&outer_stats, outer_allocated + allocated,
- max_loop_allocation);
+ Expect(&inner_stats, allocated, allocated, allocated);
+ Expect(&outer_stats, outer_allocated + allocated, max_loop_allocation,
+ total_allocated);
ExpectForPool(outer_allocated + allocated, max_loop_allocation,
total_allocated);
}
}
- Expect(&inner_stats, 0, allocated);
- Expect(&outer_stats, outer_allocated, max_loop_allocation);
+ Expect(&inner_stats, 0, allocated, allocated);
+ Expect(&outer_stats, outer_allocated, max_loop_allocation,
+ total_allocated);
ExpectForPool(outer_allocated, max_loop_allocation, total_allocated);
}
}
- Expect(&outer_stats, 0, max_loop_allocation);
+ Expect(&outer_stats, 0, max_loop_allocation, total_allocated);
ExpectForPool(0, max_loop_allocation, total_allocated);
}
'../../src/codegen.h',
'../../src/compilation-cache.cc',
'../../src/compilation-cache.h',
+ '../../src/compilation-statistics.cc',
+ '../../src/compilation-statistics.h',
'../../src/compiler/access-builder.cc',
'../../src/compiler/access-builder.h',
'../../src/compiler/ast-graph-builder.cc',
'../../src/compiler/phi-reducer.h',
'../../src/compiler/pipeline.cc',
'../../src/compiler/pipeline.h',
+ '../../src/compiler/pipeline-statistics.cc',
+ '../../src/compiler/pipeline-statistics.h',
'../../src/compiler/raw-machine-assembler.cc',
'../../src/compiler/raw-machine-assembler.h',
'../../src/compiler/register-allocator.cc',