[turboshaft] Generating JSON from Turboshaft graphs

Change-Id: If1414fd2c01816461983d9bcebeaef5785ef355a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3669694
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80809}
This commit is contained in:
Danylo Boiko 2022-05-30 11:18:59 +03:00 committed by V8 LUCI CQ
parent 2117278882
commit 010e15a7e3
10 changed files with 218 additions and 37 deletions

View File

@ -2827,6 +2827,8 @@ filegroup(
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph.cc",
"src/compiler/turboshaft/graph.h",
"src/compiler/turboshaft/graph-visualizer.cc",
"src/compiler/turboshaft/graph-visualizer.h",
"src/compiler/turboshaft/operations.cc",
"src/compiler/turboshaft/operations.h",
"src/compiler/turboshaft/optimization-phase.cc",

View File

@ -2909,6 +2909,7 @@ v8_header_set("v8_internal_headers") {
"src/compiler/turboshaft/assembler.h",
"src/compiler/turboshaft/deopt-data.h",
"src/compiler/turboshaft/graph-builder.h",
"src/compiler/turboshaft/graph-visualizer.h",
"src/compiler/turboshaft/graph.h",
"src/compiler/turboshaft/operations.h",
"src/compiler/turboshaft/optimization-phase.h",
@ -4117,6 +4118,7 @@ v8_source_set("v8_turboshaft") {
sources = [
"src/compiler/turboshaft/graph-builder.cc",
"src/compiler/turboshaft/graph-visualizer.cc",
"src/compiler/turboshaft/graph.cc",
"src/compiler/turboshaft/operations.cc",
"src/compiler/turboshaft/optimization-phase.cc",

View File

@ -77,6 +77,7 @@
#include "src/compiler/store-store-elimination.h"
#include "src/compiler/turboshaft/assembler.h"
#include "src/compiler/turboshaft/graph-builder.h"
#include "src/compiler/turboshaft/graph-visualizer.h"
#include "src/compiler/turboshaft/graph.h"
#include "src/compiler/turboshaft/optimization-phase.h"
#include "src/compiler/turboshaft/recreate-schedule.h"
@ -965,15 +966,12 @@ void PrintCode(Isolate* isolate, Handle<Code> code,
#endif // ENABLE_DISASSEMBLER
}
void TraceScheduleAndVerify(OptimizedCompilationInfo* info, PipelineData* data,
Schedule* schedule, const char* phase_name) {
RCS_SCOPE(data->runtime_call_stats(),
RuntimeCallCounterId::kOptimizeTraceScheduleAndVerify,
RuntimeCallStats::kThreadSpecific);
TRACE_EVENT0(PipelineStatistics::kTraceCategory, "V8.TraceScheduleAndVerify");
void TraceSchedule(OptimizedCompilationInfo* info, PipelineData* data,
Schedule* schedule, const char* phase_name) {
if (info->trace_turbo_json()) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
TurboJsonFile json_of(info, std::ios_base::app);
json_of << "{\"name\":\"" << phase_name << "\",\"type\":\"schedule\""
<< ",\"data\":\"";
@ -985,14 +983,26 @@ void TraceScheduleAndVerify(OptimizedCompilationInfo* info, PipelineData* data,
}
json_of << "\"},\n";
}
if (info->trace_turbo_graph() || FLAG_trace_turbo_scheduler) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "-- Schedule --------------------------------------\n"
<< "----- " << phase_name << " -----\n"
<< *schedule;
}
}
void TraceScheduleAndVerify(OptimizedCompilationInfo* info, PipelineData* data,
Schedule* schedule, const char* phase_name) {
RCS_SCOPE(data->runtime_call_stats(),
RuntimeCallCounterId::kOptimizeTraceScheduleAndVerify,
RuntimeCallStats::kThreadSpecific);
TRACE_EVENT0(PipelineStatistics::kTraceCategory, "V8.TraceScheduleAndVerify");
TraceSchedule(info, data, schedule, phase_name);
if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule);
}
@ -2493,7 +2503,6 @@ struct FinalizeCodePhase {
}
};
struct PrintGraphPhase {
DECL_PIPELINE_PHASE_CONSTANTS(PrintGraph)
@ -2524,19 +2533,44 @@ struct PrintGraphPhase {
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "-- Graph after " << phase << " -- " << std::endl
<< "----- Graph after " << phase << " ----- " << std::endl
<< AsScheduledGraph(schedule);
} else if (info->trace_turbo_graph()) { // Simple textual RPO.
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "-- Graph after " << phase << " -- " << std::endl
<< "----- Graph after " << phase << " ----- " << std::endl
<< AsRPO(*graph);
}
}
};
struct PrintTurboshaftGraphPhase {
DECL_PIPELINE_PHASE_CONSTANTS(PrintTurboshaftGraph)
void Run(PipelineData* data, Zone* temp_zone, const char* phase) {
if (data->info()->trace_turbo_json()) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
TurboJsonFile json_of(data->info(), std::ios_base::app);
json_of << "{\"name\":\"" << phase << "\",\"type\":\"turboshaft_graph\",\"data\":"
<< AsJSON(data->turboshaft_graph(), temp_zone)
<< "},\n";
}
if (data->info()->trace_turbo_graph()) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "\n----- " << phase << " -----\n"
<< data->turboshaft_graph();
}
}
};
struct VerifyGraphPhase {
DECL_PIPELINE_PHASE_CONSTANTS(VerifyGraph)
@ -2883,26 +2917,14 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
if (FLAG_turboshaft) {
Run<BuildTurboshaftPhase>();
if (data->info()->trace_turbo_graph()) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "\n-- Turboshaft Graph ----------------------------\n"
<< data->turboshaft_graph();
}
Run<PrintTurboshaftGraphPhase>(BuildTurboshaftPhase::phase_name());
Run<OptimizeTurboshaftPhase>();
Run<PrintTurboshaftGraphPhase>(OptimizeTurboshaftPhase::phase_name());
Run<TurboshaftRecreateSchedulePhase>(linkage);
if (data->info()->trace_turbo_graph() || FLAG_trace_turbo_scheduler) {
UnparkedScopeIfNeeded scope(data->broker());
AllowHandleDereference allow_deref;
CodeTracer::StreamScope tracing_scope(data->GetCodeTracer());
tracing_scope.stream()
<< "\n-- Recreated Schedule ----------------------------\n"
<< *data->schedule();
}
TraceSchedule(data->info(), data, data->schedule(),
TurboshaftRecreateSchedulePhase::phase_name());
}
return SelectInstructions(linkage);

View File

@ -0,0 +1,82 @@
// Copyright 2022 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/turboshaft/graph-visualizer.h"
namespace v8::internal::compiler::turboshaft {
JSONTurboshaftGraphWriter::JSONTurboshaftGraphWriter(std::ostream& os,
const Graph& turboshaft_graph,
Zone* zone)
: os_(os),
zone_(zone),
turboshaft_graph_(turboshaft_graph) {}
void JSONTurboshaftGraphWriter::Print() {
os_ << "{\n\"nodes\":[";
PrintNodes();
os_ << "\n],\n\"edges\":[";
PrintEdges();
os_ << "\n],\n\"blocks\":[";
PrintBlocks();
os_ << "\n]}";
}
void JSONTurboshaftGraphWriter::PrintNodes() {
bool first = true;
for (const Block& block : turboshaft_graph_.blocks()) {
for (const Operation& op : turboshaft_graph_.operations(block)) {
if (!first) os_ << ",\n";
first = false;
os_ << "{\"id\":" << turboshaft_graph_.Index(op).id() << ",";
os_ << "\"title\":\"" << OpcodeName(op.opcode) << "\",";
os_ << "\"block_id\":\"" << block.index() << "\",";
os_ << "\"properties\":\"";
op.PrintOptions(os_);
os_ << "\"}";
}
}
}
void JSONTurboshaftGraphWriter::PrintEdges() {
bool first = true;
for (const Block& block : turboshaft_graph_.blocks()) {
for (const Operation& op : turboshaft_graph_.operations(block)) {
int target_id = turboshaft_graph_.Index(op).id();
for (OpIndex input : op.inputs()) {
if (!first) os_ << ",\n";
first = false;
os_ << "{\"source\":" << input.id() << ",";
os_ << "\"target\":" << target_id << "}";
}
}
}
}
void JSONTurboshaftGraphWriter::PrintBlocks() {
bool first_block = true;
for (const Block& block : turboshaft_graph_.blocks()) {
if (!first_block) os_ << ",\n";
first_block = false;
os_ << "{\"id\":\"" << block.index() << "\",";
os_ << "\"type\":\"" << block.kind() << "\",";
os_ << "\"deferred\":" << std::boolalpha << block.IsDeferred() << ",";
os_ << "\"predecessors\":[";
bool first_predecessor = true;
for (const Block* pred : block.Predecessors()) {
if (!first_predecessor) os_ << ", ";
first_predecessor = false;
os_ << "\"" << pred->index() << "\"";
}
os_ << "]}";
}
}
std::ostream& operator<<(std::ostream& os, const TurboshaftGraphAsJSON& ad) {
JSONTurboshaftGraphWriter writer(os, ad.turboshaft_graph, ad.temp_zone);
writer.Print();
return os;
}
} // namespace v8::internal::compiler::turboshaft

View File

@ -0,0 +1,53 @@
// Copyright 2022 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_TURBOSHAFT_GRAPH_VISUALIZER_H_
#define V8_COMPILER_TURBOSHAFT_GRAPH_VISUALIZER_H_
#include "src/compiler/turboshaft/graph.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
namespace v8::internal::compiler::turboshaft {
struct TurboshaftGraphAsJSON {
TurboshaftGraphAsJSON(const Graph& tg, Zone* z): turboshaft_graph(tg),
temp_zone(z){}
const Graph& turboshaft_graph;
Zone* temp_zone;
};
V8_INLINE V8_EXPORT_PRIVATE TurboshaftGraphAsJSON AsJSON(const Graph& tg,
Zone* z) {
return TurboshaftGraphAsJSON(tg, z);
}
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const TurboshaftGraphAsJSON& ad);
class JSONTurboshaftGraphWriter {
public:
JSONTurboshaftGraphWriter(std::ostream& os, const Graph& turboshaft_graph,
Zone* zone);
JSONTurboshaftGraphWriter(const JSONTurboshaftGraphWriter&) = delete;
JSONTurboshaftGraphWriter& operator=(const JSONTurboshaftGraphWriter&) = delete;
void Print();
protected:
void PrintNodes();
void PrintEdges();
void PrintBlocks();
protected:
std::ostream& os_;
Zone* zone_;
const Graph& turboshaft_graph_;
};
} // namespace v8::internal::compiler::turboshaft
#endif // V8_COMPILER_TURBOSHAFT_GRAPH_VISUALIZER_H_

View File

@ -10,9 +10,7 @@ namespace v8::internal::compiler::turboshaft {
std::ostream& operator<<(std::ostream& os, PrintAsBlockHeader block_header) {
const Block& block = block_header.block;
const char* block_type =
block.IsLoop() ? "LOOP" : block.IsMerge() ? "MERGE" : "BLOCK";
os << "\n" << block_type << " " << block.index();
os << "\n" << block.kind() << " " << block.index();
if (block.IsDeferred()) os << " (deferred)";
if (!block.Predecessors().empty()) {
os << " <- ";
@ -36,4 +34,19 @@ std::ostream& operator<<(std::ostream& os, const Graph& graph) {
return os;
}
std::ostream& operator<<(std::ostream& os, const Block::Kind& kind) {
switch (kind) {
case Block::Kind::kLoopHeader:
os << "LOOP";
break;
case Block::Kind::kMerge:
os << "MERGE";
break;
case Block::Kind::kBranchTarget:
os << "BLOCK";
break;
}
return os;
}
} // namespace v8::internal::compiler::turboshaft

View File

@ -518,6 +518,7 @@ struct PrintAsBlockHeader {
};
std::ostream& operator<<(std::ostream& os, PrintAsBlockHeader block);
std::ostream& operator<<(std::ostream& os, const Graph& graph);
std::ostream& operator<<(std::ostream& os, const Block::Kind& kind);
} // namespace v8::internal::compiler::turboshaft

View File

@ -34,14 +34,7 @@ std::ostream& operator<<(std::ostream& os, OperationPrintStyle styled_op) {
os << styled_op.op_index_prefix << input.id();
}
os << ")";
switch (op.opcode) {
#define SWITCH_CASE(Name) \
case Opcode::k##Name: \
op.Cast<Name##Op>().PrintOptions(os); \
break;
TURBOSHAFT_OPERATION_LIST(SWITCH_CASE)
#undef SWITCH_CASE
}
op.PrintOptions(os);
return os;
}
@ -122,6 +115,17 @@ std::ostream& operator<<(std::ostream& os, ProjectionOp::Kind kind) {
}
}
void Operation::PrintOptions(std::ostream& os) const {
switch (opcode) {
#define SWITCH_CASE(Name) \
case Opcode::k##Name: \
Cast<Name##Op>().PrintOptions(os); \
break;
TURBOSHAFT_OPERATION_LIST(SWITCH_CASE)
#undef SWITCH_CASE
}
}
void PendingLoopPhiOp::PrintOptions(std::ostream& os) const {
os << "[" << rep << ", #o" << old_backedge_index.id() << "]";
}

View File

@ -267,6 +267,7 @@ struct alignas(OpIndex) Operation {
const OpProperties& properties() const;
std::string ToString() const;
void PrintOptions(std::ostream& os) const;
protected:
// Operation objects store their inputs behind the object. Therefore, they can

View File

@ -359,6 +359,7 @@ class RuntimeCallTimer final {
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, OptimizeMoves) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PopulatePointerMaps) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PrintGraph) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, PrintTurboshaftGraph) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolveControlFlow) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, ResolvePhis) \
ADD_THREAD_SPECIFIC_COUNTER(V, Optimize, \