[TurboFan]: Add JSON output for the visualizer
authordanno@chromium.org <danno@chromium.org>
Thu, 25 Sep 2014 11:13:50 +0000 (11:13 +0000)
committerdanno@chromium.org <danno@chromium.org>
Thu, 25 Sep 2014 11:13:50 +0000 (11:13 +0000)
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
src/compiler/graph-visualizer.h
src/compiler/pipeline.cc

index 10d6698..3047875 100644 (file)
@@ -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*>(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*>(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) {
index 12532ba..db92dc2 100644 (file)
@@ -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
index 9889b6a..4882d0b 100644 (file)
@@ -95,19 +95,31 @@ void Pipeline::VerifyAndPrintGraph(Graph* graph, const char* phase) {
       SmartArrayPointer<char> 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<void*>(info_), phase);
+        SNPrintF(filename, "turbo-%p-%s", static_cast<void*>(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<char> 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<char> 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()