From 76db49db5f934c7bc7b322743acbe57ab3a9c253 Mon Sep 17 00:00:00 2001
From: Josh Bleecher Snyder
Date: Sat, 13 May 2017 16:40:52 -0700
Subject: [PATCH] cmd/compile: add CFG graphs to ssa.html
DO NOT SUBMIT
This CL adds CFG graphs to ssa.html.
It execs dot to generate SVG,
which then gets inlined into the html.
Some standard naming and javascript hacks
enable integration with the rest of ssa.html:
Clicking on blocks highlights the relevant
part of the CFG graph, and vice versa.
Sample output and screenshots can be seen
in issues #20355 and #20356.
There are serious problems with this CL, though.
Performance:
* Calling dot after every pass is noticeably slow.
* The generated output is giant.
* The browser is very slow to render the resulting page.
* Clicking on blocks is even slower than before.
* Some things I want to do, like allow the user to change
the table column widths, lock up the browser.
Appearance:
* The CFGs can easily be large and overwhelming.
Toggling them on/off might be workable, if the
performance concerns above were addressed.
* I can't figure out the right size to render the CFGs;
simple ones are currently oversized and cartoonish,
while larger ones are unreadable.
* They requires an unsatisfying amount of explanation (see #20356).
Block layout information is particularly inferior/confusing.
* Dead blocks float awkwardly in the sky, with no indication
that they are dead.
* It'd be nice to somehow add visual information about loops,
which we can calculate, and which is non-obvious in large graphs,
but I don't know how.
* It'd be nice to add more information per block,
like the number of values it contains,
or even the values themselves,
but adding info to a node makes the graph even less readable.
Just adding the f.Blocks index in parens was not good.
Bugs, incompleteness:
* I seem to have broken highlighting around the entire
block in the text.
* Need to hook up some way to communicate dot-related errors
without bringing down the process.
* Might need some way to enable/disable dot entirely.
Change-Id: I19abc3007f396bdb710ba7563668d343c0924feb
---
src/cmd/compile/fmt_test.go | 1 +
src/cmd/compile/internal/ssa/func.go | 1 +
src/cmd/compile/internal/ssa/html.go | 221 +++++++++++++++++++++++--
src/cmd/compile/internal/ssa/layout.go | 1 +
4 files changed, 207 insertions(+), 17 deletions(-)
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index 59de326a91947..2a989261225d0 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -626,6 +626,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/gc.Val %v": "",
"cmd/compile/internal/gc.fmtMode %d": "",
"cmd/compile/internal/gc.initKind %d": "",
+ "cmd/compile/internal/ssa.BlockKind %v": "",
"cmd/compile/internal/ssa.BranchPrediction %d": "",
"cmd/compile/internal/ssa.Edge %v": "",
"cmd/compile/internal/ssa.GCNode %v": "",
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 7ec596372adeb..64b7c8c53a19f 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -42,6 +42,7 @@ type Func struct {
DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
scheduled bool // Values in Blocks are in final order
+ laidout bool // Blocks are ordered
NoSplit bool // true if function is marked as nosplit. Used by schedule check pass.
WBPos src.XPos // line number of first write barrier
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index d554907bebe54..54965d33466f9 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -10,12 +10,15 @@ import (
"fmt"
"html"
"io"
+ "io/ioutil"
"os"
+ "os/exec"
)
type HTMLWriter struct {
Logger
- w io.WriteCloser
+ w io.WriteCloser
+ dot *dotWriter
}
func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
@@ -24,6 +27,7 @@ func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
logger.Fatalf(src.NoXPos, "%v", err)
}
html := HTMLWriter{w: out, Logger: logger}
+ html.dot = newDotWriter()
html.start(funcname)
return &html
}
@@ -33,6 +37,23 @@ func (w *HTMLWriter) start(name string) {
return
}
w.WriteString("")
+ // TODO: These numbers work well for fannkuch.
+ // The columns are too big for simpler CFGs.
+ // How do I pick a good size?
+ // And it will need to be applied post-facto;
+ // should we buffer the entire HTML so that
+ // we can fix it up in html head,
+ // or should we fix it with javascript?
+ // If we fix it with javascript,
+ // we can just let the user pick the size.
+ // This seems better but the resulting reflow
+ // seems to make Chrome lock up.
+ tableWidth := "400"
+ elemWidth := "300"
+ if w.dot.err == nil {
+ tableWidth = "800"
+ elemWidth = "700"
+ }
w.WriteString(`
@@ -252,6 +281,39 @@ window.onload = function() {
for (var i = 0; i < ssablocks.length; i++) {
ssablocks[i].addEventListener('click', ssaBlockClicked);
}
+
+ // find all svg block nodes, add their block classes
+ var nodes = document.querySelectorAll('*[id^="graph_node_"]');
+ for (var i = 0; i < nodes.length; i++) {
+ var node = nodes[i];
+ var name = node.id.toString();
+ var block = name.substring(name.lastIndexOf("_")+1);
+ node.classList.remove("node");
+ node.classList.add(block);
+ node.addEventListener('click', ssaBlockClicked);
+ var ellipse = node.getElementsByTagName('ellipse')[0];
+ ellipse.classList.add(block);
+ }
+
+ document.onkeypress = function(e) {
+ console.log(e.keyCode);
+ return; // TODO: decide what to do here...see comments about table width above
+ switch (e.keyCode) {
+ case 'w'.charCodeAt():
+ // Make columns wider by applying a new "wide columns" class.
+ var tagnames = ["table", "th", "td"];
+ for (var j = 0; j < tagnames.length; i++) {
+ console.log("tag", tagnames[j])
+ var x = document.getElementsByTagName(tagnames[j]);
+ for (var i = 0; i < x.length; i++) {
+ console.log("add width3 to", x[i])
+ x[i].classList.add("width3");
+ }
+ }
+ case 's'.charCodeAt():
+ // TODO: make skinnier
+ }
+ };
};
function toggle_visibility(id) {
@@ -287,6 +349,10 @@ Faded out values and blocks are dead code that has not been eliminated.
Values printed in italics have a dependency cycle.
+
+Press 'w' to make the columns wider, 's' to make them skinnier.
+
+
`)
w.WriteString("