1 /*
   2  * Copyright (c) 2017, 2018, 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 
  24 
  25 package org.graalvm.compiler.debug;
  26 
  27 import java.io.IOException;
  28 import java.nio.file.Files;
  29 import java.nio.file.Path;
  30 import java.nio.file.Paths;
  31 import java.text.SimpleDateFormat;
  32 import java.util.Date;
  33 
  34 import jdk.internal.vm.compiler.collections.EconomicMap;
  35 import org.graalvm.compiler.options.EnumOptionKey;
  36 import org.graalvm.compiler.options.Option;
  37 import org.graalvm.compiler.options.OptionKey;
  38 import org.graalvm.compiler.options.OptionStability;
  39 import org.graalvm.compiler.options.OptionType;
  40 import org.graalvm.compiler.options.OptionValues;
  41 import org.graalvm.compiler.serviceprovider.GraalServices;
  42 
  43 /**
  44  * Options that configure a {@link DebugContext} and related functionality.
  45  */
  46 public class DebugOptions {
  47 
  48     /**
  49      * Values for the {@link DebugOptions#PrintGraph} option denoting where graphs dumped as a
  50      * result of the {@link DebugOptions#Dump} option are sent.
  51      */
  52     public enum PrintGraphTarget {
  53         /**
  54          * Dump graphs to files.
  55          */
  56         File,
  57 
  58         /**
  59          * Dump graphs to the network. The network destination is specified by the
  60          * {@link DebugOptions#PrintGraphHost} and {@link DebugOptions#PrintGraphPort} options. If a
  61          * network connection cannot be opened, dumping falls back to {@link #File} dumping.
  62          */
  63         Network,
  64 
  65         /**
  66          * Do not dump graphs.
  67          */
  68         Disable;
  69     }
  70 
  71     // @formatter:off
  72     @Option(help = "Comma separated names of timers that are enabled irrespective of the value for Time option. " +
  73                    "An empty value enables all timers unconditionally.", type = OptionType.Debug)
  74     public static final OptionKey<String> Timers = new OptionKey<>(null);
  75     @Option(help = "Comma separated names of counters that are enabled irrespective of the value for Count option. " +
  76                    "An empty value enables all counters unconditionally.", type = OptionType.Debug)
  77     public static final OptionKey<String> Counters = new OptionKey<>(null);
  78     @Option(help = "Comma separated names of memory usage trackers that are enabled irrespective of the value for TrackMemUse option. " +
  79                    "An empty value enables all memory usage trackers unconditionally.", type = OptionType.Debug)
  80     public static final OptionKey<String> MemUseTrackers = new OptionKey<>(null);
  81 
  82     @Option(help = "Pattern for specifying scopes in which counters are enabled. " +
  83                    "See the Dump option for the pattern syntax. " +
  84                    "An empty value enables all counters unconditionally.", type = OptionType.Debug)
  85     public static final OptionKey<String> Count = new OptionKey<>(null);
  86     @Option(help = "Pattern for specifying scopes in which memory use tracking is enabled. " +
  87                    "See the Dump option for the pattern syntax. " +
  88                    "An empty value enables all memory use trackers unconditionally.", type = OptionType.Debug)
  89     public static final OptionKey<String> TrackMemUse = new OptionKey<>(null);
  90     @Option(help = "Pattern for specifying scopes in which timing is enabled. " +
  91                    "See the Dump option for the pattern syntax. " +
  92                    "An empty value enables all timers unconditionally.", type = OptionType.Debug)
  93     public static final OptionKey<String> Time = new OptionKey<>(null);
  94 
  95     @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
  96                    "See the Dump option for the pattern syntax.", type = OptionType.Debug)
  97     public static final OptionKey<String> Verify = new OptionKey<>(null);
  98     @Option(help = "file:doc-files/DumpHelp.txt", type = OptionType.Debug, stability = OptionStability.STABLE)
  99     public static final OptionKey<String> Dump = new OptionKey<>(null);
 100     @Option(help = "Pattern for specifying scopes in which logging is enabled. " +
 101                    "See the Dump option for the pattern syntax.", type = OptionType.Debug)
 102     public static final OptionKey<String> Log = new OptionKey<>(null);
 103     @Option(help = "file:doc-files/MethodFilterHelp.txt", stability = OptionStability.STABLE)
 104     public static final OptionKey<String> MethodFilter = new OptionKey<>(null);
 105     @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug)
 106     public static final OptionKey<Boolean> MethodFilterRootOnly = new OptionKey<>(false);
 107     @Option(help = "Dump a before and after graph if the named phase changes the graph.%n" +
 108                    "The argument is substring matched against the simple name of the phase class", type = OptionType.Debug)
 109     public static final OptionKey<String> DumpOnPhaseChange = new OptionKey<>(null);
 110 
 111     @Option(help = "Lists on the console at VM shutdown the metric names available to the Timers, Counters and MemUseTrackers options. " +
 112                    "Note that this only lists the metrics that were initialized during the VM execution and so " +
 113                    "will not include metrics for compiler code that is not executed.", type = OptionType.Debug)
 114     public static final OptionKey<Boolean> ListMetrics = new OptionKey<>(false);
 115     @Option(help = "file:doc-files/MetricsFileHelp.txt", type = OptionType.Debug)
 116      public static final OptionKey<String> MetricsFile = new OptionKey<>(null);
 117     @Option(help = "File to which aggregated metrics are dumped at shutdown. A CSV format is used if the file ends with .csv " +
 118                     "otherwise a more human readable format is used. If not specified, metrics are dumped to the console.", type = OptionType.Debug)
 119     public static final OptionKey<String> AggregatedMetricsFile = new OptionKey<>(null);
 120 
 121     @Option(help = "Only report metrics for threads whose name matches the regular expression.", type = OptionType.Debug)
 122     public static final OptionKey<String> MetricsThreadFilter = new OptionKey<>(null);
 123     @Option(help = "Enable debug output for stub code generation and snippet preparation.", type = OptionType.Debug)
 124     public static final OptionKey<Boolean> DebugStubsAndSnippets = new OptionKey<>(false);
 125     @Option(help = "Send compiler IR to dump handlers on error.", type = OptionType.Debug)
 126     public static final OptionKey<Boolean> DumpOnError = new OptionKey<>(false);
 127     @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
 128     public static final OptionKey<Boolean> InterceptBailout = new OptionKey<>(false);
 129     @Option(help = "Enable more verbose log output when available", type = OptionType.Debug)
 130     public static final OptionKey<Boolean> LogVerbose = new OptionKey<>(false);
 131 
 132     @Option(help = "The directory where various Graal dump files are written.")
 133     public static final OptionKey<String> DumpPath = new OptionKey<>("graal_dumps");
 134     @Option(help = "Print the name of each dump file path as it's created.")
 135     public static final OptionKey<Boolean> ShowDumpFiles = new OptionKey<>(false);
 136 
 137     @Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug)
 138     public static final OptionKey<Boolean> PrintCFG = new OptionKey<>(false);
 139     @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.", type = OptionType.Debug)
 140     public static final OptionKey<Boolean> PrintBackendCFG = new OptionKey<>(true);
 141 
 142     @Option(help = "file:doc-files/PrintGraphHelp.txt", type = OptionType.Debug)
 143     public static final EnumOptionKey<PrintGraphTarget> PrintGraph = new EnumOptionKey<>(PrintGraphTarget.File);
 144 
 145     @Option(help = "Setting to true sets PrintGraph=file, setting to false sets PrintGraph=network", type = OptionType.Debug)
 146     public static final OptionKey<Boolean> PrintGraphFile = new OptionKey<Boolean>(true) {
 147         @Override
 148         protected void onValueUpdate(EconomicMap<OptionKey<?>, Object> values, Boolean oldValue, Boolean newValue) {
 149             PrintGraphTarget v = PrintGraph.getValueOrDefault(values);
 150             if (newValue.booleanValue()) {
 151                 if (v != PrintGraphTarget.File) {
 152                     PrintGraph.update(values, PrintGraphTarget.File);
 153                 }
 154             } else {
 155                 if (v != PrintGraphTarget.Network) {
 156                     PrintGraph.update(values, PrintGraphTarget.Network);
 157                 }
 158             }
 159         }
 160     };
 161 
 162     @Option(help = "Host part of the address to which graphs are dumped.", type = OptionType.Debug)
 163     public static final OptionKey<String> PrintGraphHost = new OptionKey<>("127.0.0.1");
 164     @Option(help = "Port part of the address to which graphs are dumped in binary format.", type = OptionType.Debug)
 165     public static final OptionKey<Integer> PrintGraphPort = new OptionKey<>(4445);
 166     @Option(help = "Schedule graphs as they are dumped.", type = OptionType.Debug)
 167     public static final OptionKey<Boolean> PrintGraphWithSchedule = new OptionKey<>(false);
 168 
 169     @Option(help = "Enable dumping Truffle ASTs to the IdealGraphVisualizer.", type = OptionType.Debug)
 170     public static final OptionKey<Boolean> PrintTruffleTrees = new OptionKey<>(true);
 171 
 172     @Option(help = "Treat any exceptions during dumping as fatal.", type = OptionType.Debug)
 173     public static final OptionKey<Boolean> DumpingErrorsAreFatal = new OptionKey<>(false);
 174 
 175     @Option(help = "Enable dumping canonical text from for graphs.", type = OptionType.Debug)
 176     public static final OptionKey<Boolean> PrintCanonicalGraphStrings = new OptionKey<>(false);
 177     @Option(help = "Choose format used when dumping canonical text for graphs: " +
 178             "0 gives a scheduled graph (better for spotting changes involving the schedule) " +
 179             "while 1 gives a CFG containing expressions rooted at fixed nodes (better for spotting small structure differences)", type = OptionType.Debug)
 180     public static final OptionKey<Integer> PrintCanonicalGraphStringFlavor = new OptionKey<>(0);
 181     @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug)
 182     public static final OptionKey<Boolean> CanonicalGraphStringsExcludeVirtuals = new OptionKey<>(true);
 183     @Option(help = "Exclude virtual nodes when dumping canonical text for graphs.", type = OptionType.Debug)
 184     public static final OptionKey<Boolean> CanonicalGraphStringsCheckConstants = new OptionKey<>(false);
 185     @Option(help = "Attempts to remove object identity hashes when dumping canonical text for graphs.", type = OptionType.Debug)
 186     public static final OptionKey<Boolean> CanonicalGraphStringsRemoveIdentities = new OptionKey<>(true);
 187 
 188     @Option(help = "Clear the debug metrics after bootstrap.", type = OptionType.Debug)
 189     public static final OptionKey<Boolean> ClearMetricsAfterBootstrap = new OptionKey<>(false);
 190     @Option(help = "Do not compile anything on bootstrap but just initialize the compiler.", type = OptionType.Debug)
 191     public static final OptionKey<Boolean> BootstrapInitializeOnly = new OptionKey<>(false);
 192 
 193     /**
 194      * Gets the directory in which {@link DebugDumpHandler}s can generate output. This will be the
 195      * directory specified by {@link #DumpPath} if it has been set otherwise it will be derived from
 196      * the default value of {@link #DumpPath} and {@link GraalServices#getGlobalTimeStamp()}.
 197      *
 198      * This method will ensure the returned directory exists, printing a message to {@link TTY} if
 199      * it creates it.
 200      *
 201      * @return a path as described above whose directories are guaranteed to exist
 202      * @throws IOException if there was an error in {@link Files#createDirectories}
 203      */
 204     public static Path getDumpDirectory(OptionValues options) throws IOException {
 205         Path dumpDir;
 206         if (DumpPath.hasBeenSet(options)) {
 207             dumpDir = Paths.get(DumpPath.getValue(options));
 208         } else {
 209             Date date = new Date(GraalServices.getGlobalTimeStamp());
 210             SimpleDateFormat formatter = new SimpleDateFormat( "YYYY.MM.dd.HH.mm.ss.SSS" );
 211             dumpDir = Paths.get(DumpPath.getValue(options), formatter.format(date));
 212         }
 213         dumpDir = dumpDir.toAbsolutePath();
 214         if (!Files.exists(dumpDir)) {
 215             synchronized (DebugConfigImpl.class) {
 216                 if (!Files.exists(dumpDir)) {
 217                     Files.createDirectories(dumpDir);
 218                     if (ShowDumpFiles.getValue(options)) {
 219                         TTY.println("Dumping debug output in %s", dumpDir.toString());
 220                     }
 221                 }
 222             }
 223         }
 224         return dumpDir;
 225     }
 226 }