Mercurial > hg > graal-compiler
view graal/com.oracle.graal.salver/src/com/oracle/graal/salver/dumper/GraphDumper.java @ 22905:463553e69619
Add basic functionality for debug dumps via Salver trace events.
author | Stefan Rumzucker <stefan.rumzucker@jku.at> |
---|---|
date | Thu, 29 Oct 2015 17:49:30 +0100 |
parents | |
children | 91a0b42ea9ed |
line wrap: on
line source
/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.graal.salver.dumper; import static com.oracle.graal.compiler.common.GraalOptions.PrintGraphProbabilities; import static com.oracle.graal.compiler.common.GraalOptions.PrintIdealGraphSchedule; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.oracle.graal.compiler.common.Fields; import com.oracle.graal.compiler.common.cfg.BlockMap; import com.oracle.graal.debug.Debug; import com.oracle.graal.debug.Debug.Scope; import com.oracle.graal.graph.Edges; import com.oracle.graal.graph.Edges.Type; import com.oracle.graal.graph.Graph; import com.oracle.graal.graph.InputEdges; import com.oracle.graal.graph.Node; import com.oracle.graal.graph.NodeClass; import com.oracle.graal.graph.NodeList; import com.oracle.graal.graph.NodeMap; import com.oracle.graal.graph.iterators.NodeIterable; import com.oracle.graal.nodes.AbstractBeginNode; import com.oracle.graal.nodes.AbstractEndNode; import com.oracle.graal.nodes.AbstractMergeNode; import com.oracle.graal.nodes.ControlSinkNode; import com.oracle.graal.nodes.ControlSplitNode; import com.oracle.graal.nodes.FixedNode; import com.oracle.graal.nodes.PhiNode; import com.oracle.graal.nodes.ProxyNode; import com.oracle.graal.nodes.StructuredGraph; import com.oracle.graal.nodes.VirtualState; import com.oracle.graal.nodes.cfg.Block; import com.oracle.graal.nodes.cfg.ControlFlowGraph; import com.oracle.graal.phases.schedule.SchedulePhase; import com.oracle.graal.salver.data.DataDict; import com.oracle.graal.salver.data.DataList; public class GraphDumper extends AbstractMethodScopeDumper { public static final String EVENT_NAMESPACE = "graal/graph"; private static final Map<Class<?>, String> nodeClassCategoryMap; static { nodeClassCategoryMap = new LinkedHashMap<>(); nodeClassCategoryMap.put(ControlSinkNode.class, "ControlSink"); nodeClassCategoryMap.put(ControlSplitNode.class, "ControlSplit"); nodeClassCategoryMap.put(AbstractMergeNode.class, "Merge"); nodeClassCategoryMap.put(AbstractBeginNode.class, "Begin"); nodeClassCategoryMap.put(AbstractEndNode.class, "End"); nodeClassCategoryMap.put(FixedNode.class, "Fixed"); nodeClassCategoryMap.put(VirtualState.class, "State"); nodeClassCategoryMap.put(PhiNode.class, "Phi"); nodeClassCategoryMap.put(ProxyNode.class, "Proxy"); // nodeClassCategoryMap.put(Object.class, "Floating"); } @Override public void beginDump() throws IOException { beginDump(EVENT_NAMESPACE); } @SuppressWarnings("try") public void dump(Graph graph, String msg) throws IOException { resolveMethodContext(); try (Scope s = Debug.sandbox(getClass().getSimpleName(), null)) { SchedulePhase predefinedSchedule = null; for (Object obj : Debug.context()) { if (obj instanceof SchedulePhase) { predefinedSchedule = (SchedulePhase) obj; } } processGraph(graph, msg, predefinedSchedule); } catch (IOException e) { throw e; } catch (Throwable e) { throw Debug.handle(e); } } private void processGraph(Graph graph, String name, SchedulePhase predefinedSchedule) throws IOException { SchedulePhase schedule = predefinedSchedule; if (schedule == null) { // Also provide a schedule when an error occurs if (PrintIdealGraphSchedule.getValue() || Debug.contextLookup(Throwable.class) != null) { if (graph instanceof StructuredGraph) { schedule = new SchedulePhase(); schedule.apply((StructuredGraph) graph); } } } ControlFlowGraph cfg = null; List<Block> blocks = null; NodeMap<Block> nodeToBlock = null; BlockMap<List<Node>> blockToNodes = null; if (schedule != null) { cfg = schedule.getCFG(); if (cfg != null) { blocks = cfg.getBlocks(); nodeToBlock = schedule.getNodeToBlockMap(); blockToNodes = schedule.getBlockToNodesMap(); } } DataDict dataDict = new DataDict(); dataDict.put("id", nextItemId()); dataDict.put("name", name); DataDict graphDict = new DataDict(); dataDict.put("graph", graphDict); processNodes(graphDict, graph.getNodes(), nodeToBlock, cfg); if (blocks != null && blockToNodes != null) { processBlocks(graphDict, blocks, blockToNodes); } serializeAndFlush(createEventDictWithId("graph", dataDict)); } private static void processNodes(DataDict graphDict, NodeIterable<Node> nodes, NodeMap<Block> nodeToBlock, ControlFlowGraph cfg) { Map<NodeClass<?>, Integer> classMap = new HashMap<>(); DataList classList = new DataList(); graphDict.put("classes", classList); DataList nodeList = new DataList(); graphDict.put("nodes", nodeList); DataList edgeList = new DataList(); graphDict.put("edges", edgeList); for (Node node : nodes) { NodeClass<?> nodeClass = node.getNodeClass(); DataDict nodeDict = new DataDict(); nodeDict.put("id", getNodeId(node)); nodeDict.put("class", getNodeClassId(classMap, classList, nodeClass)); if (nodeToBlock != null) { if (nodeToBlock.isNew(node)) { nodeDict.put("block", -1); } else { Block block = nodeToBlock.get(node); if (block != null) { nodeDict.put("block", block.getId()); } } } if (cfg != null && PrintGraphProbabilities.getValue() && node instanceof FixedNode) { try { nodeDict.put("probability", cfg.blockFor(node).probability()); } catch (Throwable t) { nodeDict.put("probability", t); } } Map<Object, Object> debugProperties = node.getDebugProperties(); if (!debugProperties.isEmpty()) { DataDict propertyDict = new DataDict(); nodeDict.put("properties", propertyDict); for (Map.Entry<Object, Object> entry : debugProperties.entrySet()) { propertyDict.put(entry.getKey().toString(), entry.getValue()); } } nodeList.add(nodeDict); appendEdges(edgeList, node, Type.Inputs); appendEdges(edgeList, node, Type.Successors); } } private static void processBlocks(DataDict graphDict, List<Block> blocks, BlockMap<List<Node>> blockToNodes) { DataList blockList = new DataList(); graphDict.put("blocks", blockList); for (Block block : blocks) { List<Node> nodes = blockToNodes.get(block); if (nodes != null) { DataDict blockDict = new DataDict(); blockDict.put("id", block.getId()); DataList nodeList = new DataList(); blockDict.put("nodes", nodeList); for (Node node : nodes) { nodeList.add(getNodeId(node)); } DataList successorList = new DataList(); blockDict.put("successors", successorList); for (Block successor : block.getSuccessors()) { successorList.add(successor.getId()); } blockList.add(blockDict); } } } private static void appendEdges(DataList edgeList, Node node, Edges.Type type) { NodeClass<?> nodeClass = node.getNodeClass(); Edges edges = nodeClass.getEdges(type); final long[] curOffsets = edges.getOffsets(); for (int i = 0; i < edges.getDirectCount(); i++) { Node other = Edges.getNode(node, curOffsets, i); if (other != null) { DataDict edgeDict = new DataDict(); DataDict nodeDict = new DataDict(); nodeDict.put("node", getNodeId(node)); nodeDict.put("field", edges.getName(i)); edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict); edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other)); edgeList.add(edgeDict); } } for (int i = edges.getDirectCount(); i < edges.getCount(); i++) { NodeList<Node> list = Edges.getNodeList(node, curOffsets, i); if (list != null) { for (int index = 0; index < list.size(); index++) { Node other = list.get(index); if (other != null) { DataDict edgeDict = new DataDict(); DataDict nodeDict = new DataDict(); nodeDict.put("node", getNodeId(node)); nodeDict.put("field", edges.getName(i)); nodeDict.put("index", index); edgeDict.put("from", type == Type.Inputs ? getNodeId(other) : nodeDict); edgeDict.put("to", type == Type.Inputs ? nodeDict : getNodeId(other)); edgeList.add(edgeDict); } } } } } @SuppressWarnings("deprecation") private static int getNodeId(Node node) { return node != null ? node.getId() : -1; } private static int getNodeClassId(Map<NodeClass<?>, Integer> classMap, DataList classList, NodeClass<?> nodeClass) { if (classMap.containsKey(nodeClass)) { return classMap.get(nodeClass); } int classId = classMap.size(); classMap.put(nodeClass, classId); Class<?> javaClass = nodeClass.getJavaClass(); DataDict classDict = new DataDict(); classList.add(classDict); classDict.put("id", classId); classDict.put("name", nodeClass.getNameTemplate()); classDict.put("jtype", javaClass.getName()); String category = getNodeClassCategory(javaClass); if (category != null) { classDict.put("category", category); } Object propertyInfo = getPropertyInfo(nodeClass); if (propertyInfo != null) { classDict.put("properties", propertyInfo); } Object inputInfo = getEdgeInfo(nodeClass, Type.Inputs); if (inputInfo != null) { classDict.put("inputs", inputInfo); } Object successorInfo = getEdgeInfo(nodeClass, Type.Successors); if (successorInfo != null) { classDict.put("successors", successorInfo); } return classId; } private static DataDict getPropertyInfo(NodeClass<?> nodeClass) { Fields properties = nodeClass.getData(); if (properties.getCount() > 0) { DataDict propertyInfoDict = new DataDict(); for (int i = 0; i < properties.getCount(); i++) { DataDict propertyDict = new DataDict(); String name = properties.getName(i); propertyDict.put("name", name); propertyDict.put("jtype", properties.getType(i).getName()); propertyInfoDict.put(name, propertyDict); } return propertyInfoDict; } return null; } private static DataDict getEdgeInfo(NodeClass<?> nodeClass, Edges.Type type) { DataDict edgeInfoDict = new DataDict(); Edges edges = nodeClass.getEdges(type); for (int i = 0; i < edges.getCount(); i++) { DataDict edgeDict = new DataDict(); String name = edges.getName(i); edgeDict.put("name", name); edgeDict.put("jtype", edges.getType(i).getName()); if (type == Type.Inputs) { edgeDict.put("type", ((InputEdges) edges).getInputType(i)); } edgeInfoDict.put(name, edgeDict); } return edgeInfoDict.isEmpty() ? null : edgeInfoDict; } private static String getNodeClassCategory(Class<?> clazz) { for (Map.Entry<Class<?>, String> entry : nodeClassCategoryMap.entrySet()) { if (entry.getKey().isAssignableFrom(clazz)) { return entry.getValue(); } } return null; } }