From ca080a4f40917dc3b689c164ef5e35d8191997f9 Mon Sep 17 00:00:00 2001 From: "danno@chromium.org" Date: Thu, 25 Sep 2014 11:13:50 +0000 Subject: [PATCH] [TurboFan]: Add JSON output for the visualizer R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/599453002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24220 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/compiler/graph-visualizer.cc | 165 ++++++++++++++++++++++++++++++++------- src/compiler/graph-visualizer.h | 7 ++ src/compiler/pipeline.cc | 26 ++++-- 3 files changed, 161 insertions(+), 37 deletions(-) diff --git a/src/compiler/graph-visualizer.cc b/src/compiler/graph-visualizer.cc index 10d6698..3047875 100644 --- a/src/compiler/graph-visualizer.cc +++ b/src/compiler/graph-visualizer.cc @@ -22,6 +22,141 @@ namespace compiler { #define DEAD_COLOR "#999999" +class Escaped { + public: + explicit Escaped(const OStringStream& os, const char* escaped_chars = "<>|{}") + : str_(os.c_str()), escaped_chars_(escaped_chars) {} + + friend OStream& operator<<(OStream& os, const Escaped& e) { + for (const char* s = e.str_; *s != '\0'; ++s) { + if (e.needs_escape(*s)) os << "\\"; + os << *s; + } + return os; + } + + private: + bool needs_escape(char ch) const { + for (size_t i = 0; i < strlen(escaped_chars_); ++i) { + if (ch == escaped_chars_[i]) return true; + } + return false; + } + + const char* const str_; + const char* const escaped_chars_; +}; + +class JSONGraphNodeWriter : public NullNodeVisitor { + public: + JSONGraphNodeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT + : os_(os), + graph_(graph), + first_node_(true) {} + + void Print() { const_cast(graph_)->VisitNodeInputsFromEnd(this); } + + GenericGraphVisit::Control Pre(Node* node); + + private: + OStream& os_; + const Graph* const graph_; + bool first_node_; + + DISALLOW_COPY_AND_ASSIGN(JSONGraphNodeWriter); +}; + + +GenericGraphVisit::Control JSONGraphNodeWriter::Pre(Node* node) { + if (first_node_) { + first_node_ = false; + } else { + os_ << ","; + } + OStringStream label; + label << *node->op(); + os_ << "{\"id\":" << node->id() << ",\"label\":\"" << Escaped(label, "\"") + << "\""; + IrOpcode::Value opcode = node->opcode(); + if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) { + os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node) + << "]"; + os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node) + << "]"; + } else if (opcode == IrOpcode::kIfTrue || opcode == IrOpcode::kIfFalse || + opcode == IrOpcode::kLoop) { + os_ << ",\"rankInputs\":[" << NodeProperties::FirstControlIndex(node) + << "]"; + } + if (opcode == IrOpcode::kBranch) { + os_ << ",\"rankInputs\":[0]"; + } + os_ << ",\"opcode\":\"" << IrOpcode::Mnemonic(node->opcode()) << "\""; + os_ << ",\"control\":" << (NodeProperties::IsControl(node) ? "true" + : "false"); + os_ << "}"; + return GenericGraphVisit::CONTINUE; +} + + +class JSONGraphEdgeWriter : public NullNodeVisitor { + public: + JSONGraphEdgeWriter(OStream& os, Zone* zone, const Graph* graph) // NOLINT + : os_(os), + graph_(graph), + first_edge_(true) {} + + void Print() { const_cast(graph_)->VisitNodeInputsFromEnd(this); } + + GenericGraphVisit::Control PreEdge(Node* from, int index, Node* to); + + private: + OStream& os_; + const Graph* const graph_; + bool first_edge_; + + DISALLOW_COPY_AND_ASSIGN(JSONGraphEdgeWriter); +}; + + +GenericGraphVisit::Control JSONGraphEdgeWriter::PreEdge(Node* from, int index, + Node* to) { + if (first_edge_) { + first_edge_ = false; + } else { + os_ << ","; + } + const char* edge_type = NULL; + if (index < NodeProperties::FirstValueIndex(from)) { + edge_type = "unknown"; + } else if (index < NodeProperties::FirstContextIndex(from)) { + edge_type = "value"; + } else if (index < NodeProperties::FirstFrameStateIndex(from)) { + edge_type = "context"; + } else if (index < NodeProperties::FirstEffectIndex(from)) { + edge_type = "frame-state"; + } else if (index < NodeProperties::FirstControlIndex(from)) { + edge_type = "effect"; + } else { + edge_type = "control"; + } + os_ << "{\"source\":" << to->id() << ",\"target\":" << from->id() + << ",\"index\":" << index << ",\"type\":\"" << edge_type << "\"}"; + return GenericGraphVisit::CONTINUE; +} + + +OStream& operator<<(OStream& os, const AsJSON& ad) { + Zone tmp_zone(ad.graph.zone()->isolate()); + os << "{\"nodes\":["; + JSONGraphNodeWriter(os, &tmp_zone, &ad.graph).Print(); + os << "],\"edges\":["; + JSONGraphEdgeWriter(os, &tmp_zone, &ad.graph).Print(); + os << "]}"; + return os; +} + + class GraphVisualizer : public NullNodeVisitor { public: GraphVisualizer(OStream& os, Zone* zone, const Graph* graph); // NOLINT @@ -87,36 +222,6 @@ GenericGraphVisit::Control GraphVisualizer::PreEdge(Node* from, int index, } -class Escaped { - public: - explicit Escaped(const OStringStream& os) : str_(os.c_str()) {} - - friend OStream& operator<<(OStream& os, const Escaped& e) { - for (const char* s = e.str_; *s != '\0'; ++s) { - if (needs_escape(*s)) os << "\\"; - os << *s; - } - return os; - } - - private: - static bool needs_escape(char ch) { - switch (ch) { - case '>': - case '<': - case '|': - case '}': - case '{': - return true; - default: - return false; - } - } - - const char* const str_; -}; - - static bool IsLikelyBackEdge(Node* from, int index, Node* to) { if (from->opcode() == IrOpcode::kPhi || from->opcode() == IrOpcode::kEffectPhi) { diff --git a/src/compiler/graph-visualizer.h b/src/compiler/graph-visualizer.h index 12532ba..db92dc2 100644 --- a/src/compiler/graph-visualizer.h +++ b/src/compiler/graph-visualizer.h @@ -22,6 +22,13 @@ struct AsDOT { }; OStream& operator<<(OStream& os, const AsDOT& ad); + +struct AsJSON { + explicit AsJSON(const Graph& g) : graph(g) {} + const Graph& graph; +}; + +OStream& operator<<(OStream& os, const AsJSON& ad); } } } // namespace v8::internal::compiler diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc index 9889b6a..4882d0b 100644 --- a/src/compiler/pipeline.cc +++ b/src/compiler/pipeline.cc @@ -95,19 +95,31 @@ void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) { SmartArrayPointer functionname = info_->shared_info()->DebugName()->ToCString(); if (strlen(functionname.get()) > 0) { - SNPrintF(filename, "turbo-%s-%s.dot", functionname.get(), phase); + SNPrintF(filename, "turbo-%s-%s", functionname.get(), phase); } else { - SNPrintF(filename, "turbo-%p-%s.dot", static_cast(info_), phase); + SNPrintF(filename, "turbo-%p-%s", static_cast(info_), phase); } } else { - SNPrintF(filename, "turbo-none-%s.dot", phase); + SNPrintF(filename, "turbo-none-%s", phase); } std::replace(filename.start(), filename.start() + filename.length(), ' ', '_'); - FILE* file = base::OS::FOpen(filename.start(), "w+"); - OFStream of(file); - of << AsDOT(*graph); - fclose(file); + + char dot_buffer[256]; + Vector dot_filename(dot_buffer, sizeof(dot_buffer)); + SNPrintF(dot_filename, "%s.dot", filename.start()); + FILE* dot_file = base::OS::FOpen(dot_filename.start(), "w+"); + OFStream dot_of(dot_file); + dot_of << AsDOT(*graph); + fclose(dot_file); + + char json_buffer[256]; + Vector json_filename(json_buffer, sizeof(json_buffer)); + SNPrintF(json_filename, "%s.json", filename.start()); + FILE* json_file = base::OS::FOpen(json_filename.start(), "w+"); + OFStream json_of(json_file); + json_of << AsJSON(*graph); + fclose(json_file); OFStream os(stdout); os << "-- " << phase << " graph printed to file " << filename.start() -- 2.7.4