1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.salver.dumper; 24 25 import java.io.IOException; 26 import java.util.Arrays; 27 import java.util.HashMap; 28 import java.util.LinkedHashMap; 29 import java.util.List; 30 import java.util.Map; 31 32 import org.graalvm.compiler.core.common.Fields; 33 import org.graalvm.compiler.core.common.cfg.BlockMap; 34 import org.graalvm.compiler.debug.Debug; 35 import org.graalvm.compiler.debug.Debug.Scope; 36 import org.graalvm.compiler.debug.GraalDebugConfig.Options; 37 import org.graalvm.compiler.graph.Edges; 38 import org.graalvm.compiler.graph.Edges.Type; 39 import org.graalvm.compiler.graph.Graph; 40 import org.graalvm.compiler.graph.InputEdges; 41 import org.graalvm.compiler.graph.Node; 42 import org.graalvm.compiler.graph.NodeClass; 43 import org.graalvm.compiler.graph.NodeList; 44 import org.graalvm.compiler.graph.NodeMap; 45 import org.graalvm.compiler.graph.iterators.NodeIterable; 46 import org.graalvm.compiler.nodes.AbstractBeginNode; 47 import org.graalvm.compiler.nodes.AbstractEndNode; 48 import org.graalvm.compiler.nodes.AbstractMergeNode; 49 import org.graalvm.compiler.nodes.ControlSinkNode; 50 import org.graalvm.compiler.nodes.ControlSplitNode; 51 import org.graalvm.compiler.nodes.FixedNode; 52 import org.graalvm.compiler.nodes.PhiNode; 53 import org.graalvm.compiler.nodes.ProxyNode; 54 import org.graalvm.compiler.nodes.StructuredGraph; 55 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 56 import org.graalvm.compiler.nodes.VirtualState; 57 import org.graalvm.compiler.nodes.cfg.Block; 58 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 59 import org.graalvm.compiler.phases.schedule.SchedulePhase; 60 import org.graalvm.compiler.salver.data.DataDict; 61 import org.graalvm.compiler.salver.data.DataList; 62 63 public class GraphDumper extends AbstractMethodScopeDumper { 64 65 public static final String EVENT_NAMESPACE = "graal/graph"; 66 67 private static final Map<Class<?>, String> nodeClassCategoryMap; 68 69 static { 70 nodeClassCategoryMap = new LinkedHashMap<>(); 71 nodeClassCategoryMap.put(ControlSinkNode.class, "ControlSink"); 72 nodeClassCategoryMap.put(ControlSplitNode.class, "ControlSplit"); 73 nodeClassCategoryMap.put(AbstractMergeNode.class, "Merge"); 74 nodeClassCategoryMap.put(AbstractBeginNode.class, "Begin"); 75 nodeClassCategoryMap.put(AbstractEndNode.class, "End"); 76 nodeClassCategoryMap.put(FixedNode.class, "Fixed"); 77 nodeClassCategoryMap.put(VirtualState.class, "State"); 78 nodeClassCategoryMap.put(PhiNode.class, "Phi"); 79 nodeClassCategoryMap.put(ProxyNode.class, "Proxy"); 80 // nodeClassCategoryMap.put(Node.class, "Floating"); 81 } 82 83 @Override 84 public void beginDump() throws IOException { 85 beginDump(EVENT_NAMESPACE); 86 } 87 88 @SuppressWarnings("try") 89 public void dump(Graph graph, String msg) throws IOException { 90 resolveMethodContext(); 91 92 try (Scope s = Debug.sandbox(getClass().getSimpleName(), null)) { 93 processGraph(graph, msg); 94 } catch (IOException e) { 95 throw e; 96 } catch (Throwable e) { 97 throw Debug.handle(e); 98 } 99 } 100 101 private void processGraph(Graph graph, String name) throws IOException { 102 103 ScheduleResult scheduleResult = null; 104 if (graph instanceof StructuredGraph) { 105 106 StructuredGraph structuredGraph = (StructuredGraph) graph; 107 scheduleResult = structuredGraph.getLastSchedule(); 108 if (scheduleResult == null) { 109 110 // Also provide a schedule when an error occurs 111 if (Options.PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) { 112 try { 113 SchedulePhase schedule = new SchedulePhase(); 114 schedule.apply(structuredGraph); 115 } catch (Throwable t) { 116 } 117 } 118 119 } 120 } 121 122 DataDict dataDict = new DataDict(); 123 dataDict.put("id", nextItemId()); 124 dataDict.put("name", name); 125 126 DataDict graphDict = new DataDict(); 127 dataDict.put("graph", graphDict); 128 129 processNodes(graphDict, graph.getNodes(), scheduleResult); 130 131 if (scheduleResult != null) { 132 ControlFlowGraph cfg = scheduleResult.getCFG(); 133 if (cfg != null) { 134 List<Block> blocks = Arrays.asList(cfg.getBlocks()); 135 processBlocks(graphDict, blocks, scheduleResult); 136 } 137 } 138 serializeAndFlush(createEventDictWithId("graph", dataDict)); 139 } 140 141 private static void processNodes(DataDict graphDict, NodeIterable<Node> nodes, ScheduleResult schedule) { 142 Map<NodeClass<?>, Integer> classMap = new HashMap<>(); 143 144 DataList classList = new DataList(); 145 graphDict.put("classes", classList); 146 147 DataList nodeList = new DataList(); 148 graphDict.put("nodes", nodeList); 149 150 DataList edgeList = new DataList(); 151 graphDict.put("edges", edgeList); 152 153 for (Node node : nodes) { 154 NodeClass<?> nodeClass = node.getNodeClass(); 155 156 DataDict nodeDict = new DataDict(); 157 nodeList.add(nodeDict); 158 159 nodeDict.put("id", getNodeId(node)); 160 nodeDict.put("class", getNodeClassId(classMap, classList, nodeClass)); 161 162 if (schedule != null) { 163 processNodeSchedule(nodeDict, node, schedule); 164 } 165 166 DataDict propertyDict = new DataDict(); 167 node.getDebugProperties(propertyDict); 168 169 if (!propertyDict.isEmpty()) { 170 nodeDict.put("properties", propertyDict); 171 } 172 173 appendEdges(edgeList, node, Type.Inputs); 174 appendEdges(edgeList, node, Type.Successors); 175 } 176 } 177 178 private static void processNodeSchedule(DataDict nodeDict, Node node, ScheduleResult schedule) { 179 NodeMap<Block> nodeToBlock = schedule.getNodeToBlockMap(); 180 if (nodeToBlock != null) { 181 if (nodeToBlock.isNew(node)) { 182 nodeDict.put("block", -1); 183 } else { 184 Block block = nodeToBlock.get(node); 185 if (block != null) { 186 nodeDict.put("block", block.getId()); 187 } 188 } 189 } 190 191 ControlFlowGraph cfg = schedule.getCFG(); 192 if (cfg != null && Options.PrintGraphProbabilities.getValue() && node instanceof FixedNode) { 193 try { 194 nodeDict.put("probability", cfg.blockFor(node).probability()); 195 } catch (Throwable t) { 196 nodeDict.put("probability", t); 197 } 198 } 199 } 200 201 private static void processBlocks(DataDict graphDict, List<Block> blocks, ScheduleResult schedule) { 202 BlockMap<List<Node>> blockToNodes = schedule.getBlockToNodesMap(); 203 DataList blockList = new DataList(); 204 graphDict.put("blocks", blockList); 205 206 for (Block block : blocks) { 207 List<Node> nodes = blockToNodes.get(block); 208 if (nodes != null) { 209 DataDict blockDict = new DataDict(); 210 blockList.add(blockDict); 211 212 blockDict.put("id", block.getId()); 213 214 DataList nodeList = new DataList(); 215 blockDict.put("nodes", nodeList); 216 217 for (Node node : nodes) { 218 nodeList.add(getNodeId(node)); 219 } 220 221 Block[] successors = block.getSuccessors(); 222 if (successors != null && successors.length > 0) { 223 DataList successorList = new DataList(); 224 blockDict.put("successors", successorList); 225 for (Block successor : successors) { 226 successorList.add(successor.getId()); 227 } 228 } 229 } 230 } 231 } 232 233 private static void appendEdges(DataList edgeList, Node node, Edges.Type type) { 234 NodeClass<?> nodeClass = node.getNodeClass(); 235 236 Edges edges = nodeClass.getEdges(type); 237 final long[] curOffsets = edges.getOffsets(); 238 239 for (int i = 0; i < edges.getDirectCount(); i++) { 240 Node other = Edges.getNode(node, curOffsets, i); 241 if (other != null) { 242 DataDict edgeDict = new DataDict(); 243 244 DataDict nodeDict = new DataDict(); 245 nodeDict.put("node", getNodeId(node)); 246 nodeDict.put("field", edges.getName(i)); 247 248 edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict); 249 edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other)); 250 edgeList.add(edgeDict); 251 } 252 } 253 for (int i = edges.getDirectCount(); i < edges.getCount(); i++) { 254 NodeList<Node> list = Edges.getNodeList(node, curOffsets, i); 255 if (list != null) { 256 for (int index = 0; index < list.size(); index++) { 257 Node other = list.get(index); 258 if (other != null) { 259 DataDict edgeDict = new DataDict(); 260 261 DataDict nodeDict = new DataDict(); 262 nodeDict.put("node", getNodeId(node)); 263 nodeDict.put("field", edges.getName(i)); 264 nodeDict.put("index", index); 265 266 edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict); 267 edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other)); 268 edgeList.add(edgeDict); 269 } 270 } 271 } 272 } 273 } 274 275 @SuppressWarnings("deprecation") 276 private static int getNodeId(Node node) { 277 return node != null ? node.getId() : -1; 278 } 279 280 private static int getNodeClassId(Map<NodeClass<?>, Integer> classMap, DataList classList, NodeClass<?> nodeClass) { 281 if (classMap.containsKey(nodeClass)) { 282 return classMap.get(nodeClass); 283 } 284 int classId = classMap.size(); 285 classMap.put(nodeClass, classId); 286 287 Class<?> javaClass = nodeClass.getJavaClass(); 288 289 DataDict classDict = new DataDict(); 290 classList.add(classDict); 291 292 classDict.put("id", classId); 293 classDict.put("name", nodeClass.getNameTemplate()); 294 classDict.put("jtype", javaClass.getName()); 295 296 String category = getNodeClassCategory(javaClass); 297 if (category != null) { 298 classDict.put("category", category); 299 } 300 301 Object propertyInfo = getPropertyInfo(nodeClass); 302 if (propertyInfo != null) { 303 classDict.put("properties", propertyInfo); 304 } 305 306 Object inputInfo = getEdgeInfo(nodeClass, Type.Inputs); 307 if (inputInfo != null) { 308 classDict.put("inputs", inputInfo); 309 } 310 Object successorInfo = getEdgeInfo(nodeClass, Type.Successors); 311 if (successorInfo != null) { 312 classDict.put("successors", successorInfo); 313 } 314 return classId; 315 } 316 317 private static DataDict getPropertyInfo(NodeClass<?> nodeClass) { 318 Fields properties = nodeClass.getData(); 319 if (properties.getCount() > 0) { 320 DataDict propertyInfoDict = new DataDict(); 321 for (int i = 0; i < properties.getCount(); i++) { 322 DataDict propertyDict = new DataDict(); 323 String name = properties.getName(i); 324 propertyDict.put("name", name); 325 propertyDict.put("jtype", properties.getType(i).getName()); 326 propertyInfoDict.put(name, propertyDict); 327 } 328 return propertyInfoDict; 329 } 330 return null; 331 } 332 333 private static DataDict getEdgeInfo(NodeClass<?> nodeClass, Edges.Type type) { 334 DataDict edgeInfoDict = new DataDict(); 335 Edges edges = nodeClass.getEdges(type); 336 for (int i = 0; i < edges.getCount(); i++) { 337 DataDict edgeDict = new DataDict(); 338 String name = edges.getName(i); 339 Class<?> fieldClass = edges.getType(i); 340 edgeDict.put("name", name); 341 edgeDict.put("jtype", fieldClass.getName()); 342 if (NodeList.class.isAssignableFrom(fieldClass)) { 343 edgeDict.put("isList", true); 344 } 345 if (type == Type.Inputs) { 346 InputEdges inputEdges = ((InputEdges) edges); 347 edgeDict.put("type", inputEdges.getInputType(i)); 348 if (inputEdges.isOptional(i)) { 349 edgeDict.put("isOptional", true); 350 } 351 } 352 edgeInfoDict.put(name, edgeDict); 353 } 354 return edgeInfoDict.isEmpty() ? null : edgeInfoDict; 355 } 356 357 private static String getNodeClassCategory(Class<?> clazz) { 358 for (Map.Entry<Class<?>, String> entry : nodeClassCategoryMap.entrySet()) { 359 if (entry.getKey().isAssignableFrom(clazz)) { 360 return entry.getValue(); 361 } 362 } 363 return null; 364 } 365 }