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.printer;
  24 
  25 import java.io.IOException;
  26 import java.io.InterruptedIOException;
  27 import java.net.InetSocketAddress;
  28 import java.net.Socket;
  29 import java.nio.channels.ClosedByInterruptException;
  30 import java.nio.channels.FileChannel;
  31 import java.nio.channels.SocketChannel;
  32 import java.nio.file.Files;
  33 import java.nio.file.Path;
  34 import java.nio.file.StandardOpenOption;
  35 
  36 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  37 import org.graalvm.compiler.debug.Debug;
  38 import org.graalvm.compiler.debug.DebugConfig;
  39 import org.graalvm.compiler.debug.DebugConfigCustomizer;
  40 import org.graalvm.compiler.debug.DebugDumpHandler;
  41 import org.graalvm.compiler.debug.GraalDebugConfig.Options;
  42 import org.graalvm.compiler.debug.TTY;
  43 import org.graalvm.compiler.graph.Node;
  44 import org.graalvm.compiler.nodeinfo.Verbosity;
  45 import org.graalvm.compiler.nodes.util.GraphUtil;
  46 import org.graalvm.compiler.options.UniquePathUtilities;
  47 import org.graalvm.compiler.serviceprovider.ServiceProvider;
  48 
  49 @ServiceProvider(DebugConfigCustomizer.class)
  50 public class GraalDebugConfigCustomizer implements DebugConfigCustomizer {
  51 
  52     private SnippetReflectionProvider snippetReflection;
  53 
  54     @Override
  55     public void customize(DebugConfig config, Object... extraArgs) {
  56         snippetReflection = DebugConfigCustomizer.lookupArg(SnippetReflectionProvider.class, extraArgs);
  57         if (Options.PrintIdealGraphFile.getValue()) {
  58             config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createFilePrinter));
  59         } else {
  60             config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createNetworkPrinter));
  61         }
  62         if (Options.PrintCanonicalGraphStrings.getValue()) {
  63             config.dumpHandlers().add(new GraphPrinterDumpHandler(this::createStringPrinter));
  64         }
  65         config.dumpHandlers().add(new NodeDumper());
  66         if (Options.PrintCFG.getValue() || Options.PrintBackendCFG.getValue()) {
  67             if (Options.PrintBinaryGraphs.getValue() && Options.PrintCFG.getValue()) {
  68                 TTY.out.println("Complete C1Visualizer dumping slows down PrintBinaryGraphs: use -Dgraal.PrintCFG=false to disable it");
  69             }
  70             config.dumpHandlers().add(new CFGPrinterObserver(Options.PrintCFG.getValue()));
  71         }
  72         config.verifyHandlers().add(new NoDeadCodeVerifyHandler());
  73     }
  74 
  75     private static class NodeDumper implements DebugDumpHandler {
  76         @Override
  77         public void dump(Object object, String message) {
  78             if (object instanceof Node) {
  79                 String location = GraphUtil.approxSourceLocation((Node) object);
  80                 String node = ((Node) object).toString(Verbosity.Debugger);
  81                 if (location != null) {
  82                     Debug.log("Context obj %s (approx. location: %s)", node, location);
  83                 } else {
  84                     Debug.log("Context obj %s", node);
  85                 }
  86             }
  87         }
  88 
  89         @Override
  90         public void close() {
  91         }
  92     }
  93 
  94     private CanonicalStringGraphPrinter createStringPrinter() {
  95         // Construct the path to the directory.
  96         Path path = UniquePathUtilities.getPath(Options.PrintCanonicalGraphStringsDirectory, Options.DumpPath, "");
  97         return new CanonicalStringGraphPrinter(path, snippetReflection);
  98     }
  99 
 100     private GraphPrinter createNetworkPrinter() throws IOException {
 101         String host = Options.PrintIdealGraphAddress.getValue();
 102         int port = Options.PrintBinaryGraphs.getValue() ? Options.PrintBinaryGraphPort.getValue() : Options.PrintIdealGraphPort.getValue();
 103         try {
 104             GraphPrinter printer;
 105             if (Options.PrintBinaryGraphs.getValue()) {
 106                 printer = new BinaryGraphPrinter(SocketChannel.open(new InetSocketAddress(host, port)), snippetReflection);
 107             } else {
 108                 printer = new IdealGraphPrinter(new Socket(host, port).getOutputStream(), true, snippetReflection);
 109             }
 110             TTY.println("Connected to the IGV on %s:%d", host, port);
 111             return printer;
 112         } catch (ClosedByInterruptException | InterruptedIOException e) {
 113             /*
 114              * Interrupts should not count as errors because they may be caused by a cancelled Graal
 115              * compilation. ClosedByInterruptException occurs if the SocketChannel could not be
 116              * opened. InterruptedIOException occurs if new Socket(..) was interrupted.
 117              */
 118             return null;
 119         } catch (IOException e) {
 120             throw new IOException(String.format("Could not connect to the IGV on %s:%d", host, port), e);
 121         }
 122     }
 123 
 124     private static Path getFilePrinterPath() {
 125         // Construct the path to the file.
 126         return UniquePathUtilities.getPath(Options.PrintIdealGraphFileName, Options.DumpPath, Options.PrintBinaryGraphs.getValue() ? "bgv" : "gv.xml");
 127     }
 128 
 129     private GraphPrinter createFilePrinter() throws IOException {
 130         Path path = getFilePrinterPath();
 131         try {
 132             GraphPrinter printer;
 133             if (Options.PrintBinaryGraphs.getValue()) {
 134                 printer = new BinaryGraphPrinter(FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW), snippetReflection);
 135             } else {
 136                 printer = new IdealGraphPrinter(Files.newOutputStream(path), true, snippetReflection);
 137             }
 138             TTY.println("Dumping IGV graphs to %s", path.toString());
 139             return printer;
 140         } catch (IOException e) {
 141             throw new IOException(String.format("Failed to open %s to dump IGV graphs", path), e);
 142         }
 143     }
 144 }