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.hotspot; 24 25 import static org.graalvm.compiler.debug.Debug.VERBOSE_LEVEL; 26 import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.DUMP_METHOD; 27 import static org.graalvm.compiler.debug.DelegatingDebugConfig.Level.DUMP; 28 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; 29 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DumpPath; 30 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.ForceDebugEnable; 31 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCFGFileName; 32 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFileName; 33 34 import java.io.ByteArrayOutputStream; 35 import java.io.File; 36 import java.io.FileNotFoundException; 37 import java.io.FileOutputStream; 38 import java.io.PrintStream; 39 import java.nio.file.InvalidPathException; 40 import java.nio.file.Paths; 41 import java.util.ArrayList; 42 import java.util.Collection; 43 44 import org.graalvm.compiler.debug.Debug; 45 import org.graalvm.compiler.debug.DebugDumpHandler; 46 import org.graalvm.compiler.debug.DebugRetryableTask; 47 import org.graalvm.compiler.debug.TTY; 48 import org.graalvm.compiler.options.OptionValues; 49 import org.graalvm.compiler.printer.GraalDebugConfigCustomizer; 50 51 import jdk.vm.ci.code.BailoutException; 52 53 /** 54 * Utility for retrying a compilation that throws an exception where the retry enables extra logging 55 * for subsequently diagnosing the failure. 56 */ 57 public abstract class HotSpotRetryableCompilation<T> extends DebugRetryableTask<T> { 58 59 protected final OptionValues originalOptions; 60 protected final HotSpotGraalRuntimeProvider runtime; 61 62 public HotSpotRetryableCompilation(HotSpotGraalRuntimeProvider runtime, OptionValues options) { 63 this.runtime = runtime; 64 this.originalOptions = options; 65 } 66 67 /** 68 * Gets a value that represents the compilation unit being compiled. 69 */ 70 @Override 71 public abstract String toString(); 72 73 private static String sanitizedFileName(String name) { 74 StringBuilder buf = new StringBuilder(name.length()); 75 for (int i = 0; i < name.length(); i++) { 76 char c = name.charAt(i); 77 try { 78 Paths.get(String.valueOf(c)); 79 } catch (InvalidPathException e) { 80 buf.append('_'); 81 } 82 buf.append(c); 83 } 84 return buf.toString(); 85 } 86 87 @Override 88 protected boolean onRetry(Throwable t) { 89 if (t instanceof BailoutException) { 90 return false; 91 } 92 93 if (!Debug.isEnabled()) { 94 TTY.printf("Error while compiling %s due to %s.%nRe-run with -D%s%s=true to capture graph dumps upon a compilation failure.%n", this, 95 t, HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX, ForceDebugEnable.getName()); 96 return false; 97 } 98 99 if (Dump.hasBeenSet(originalOptions)) { 100 // If dumping is explicitly enabled, Graal is being debugged 101 // so don't interfere with what the user is expecting to see. 102 return false; 103 } 104 105 String outputDirectory = runtime.getOutputDirectory(); 106 if (outputDirectory == null) { 107 return false; 108 } 109 String dumpName = sanitizedFileName(toString()); 110 File dumpPath = new File(outputDirectory, dumpName); 111 dumpPath.mkdirs(); 112 if (!dumpPath.exists()) { 113 TTY.println("Warning: could not create dump directory " + dumpPath); 114 return false; 115 } 116 117 TTY.println("Retrying compilation of " + this + " due to " + t); 118 retryLogPath = new File(dumpPath, "retry.log").getPath(); 119 log("Exception causing retry", t); 120 retryDumpHandlers = new ArrayList<>(); 121 retryOptions = new OptionValues(originalOptions, 122 PrintCFGFileName, dumpName, 123 PrintGraphFileName, dumpName, 124 DumpPath, dumpPath.getPath()); 125 override(DUMP, VERBOSE_LEVEL).enable(DUMP_METHOD); 126 new GraalDebugConfigCustomizer().customize(this); 127 return true; 128 } 129 130 private Collection<DebugDumpHandler> retryDumpHandlers; 131 private OptionValues retryOptions; 132 private String retryLogPath; 133 134 /** 135 * Prints a message to a retry log file. 136 * 137 * @param message the message to print 138 * @param t if non-{@code null}, the stack trace for this exception is written to the retry log 139 * after {@code message} 140 */ 141 protected void log(String message, Throwable t) { 142 if (retryLogPath != null) { 143 try (PrintStream retryLog = new PrintStream(new FileOutputStream(retryLogPath), true)) { 144 StringBuilder buf = new StringBuilder(Thread.currentThread() + ": " + message); 145 if (t != null) { 146 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 147 t.printStackTrace(new PrintStream(baos)); 148 buf.append(System.lineSeparator()).append(baos.toString()); 149 } 150 retryLog.println(buf); 151 } catch (FileNotFoundException e) { 152 TTY.println("Warning: could not open retry log file " + retryLogPath + " [" + e + "]"); 153 } 154 } 155 } 156 157 @Override 158 public Collection<DebugDumpHandler> dumpHandlers() { 159 return retryDumpHandlers; 160 } 161 162 @Override 163 public OptionValues getOptions() { 164 return retryOptions; 165 } 166 } | 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.hotspot; 24 25 import static org.graalvm.compiler.debug.DebugContext.VERBOSE_LEVEL; 26 import static org.graalvm.compiler.debug.DebugOptions.Dump; 27 import static org.graalvm.compiler.debug.DebugOptions.DumpPath; 28 import static org.graalvm.compiler.debug.DebugOptions.MethodFilter; 29 30 import java.io.ByteArrayOutputStream; 31 import java.io.File; 32 import java.io.FileNotFoundException; 33 import java.io.FileOutputStream; 34 import java.io.PrintStream; 35 36 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 37 import org.graalvm.compiler.debug.DebugContext; 38 import org.graalvm.compiler.debug.DebugRetryableTask; 39 import org.graalvm.compiler.debug.TTY; 40 import org.graalvm.compiler.options.OptionValues; 41 import org.graalvm.compiler.printer.GraalDebugHandlersFactory; 42 43 import jdk.vm.ci.code.BailoutException; 44 45 /** 46 * Utility for retrying a compilation that throws an exception where the retry enables extra logging 47 * for subsequently diagnosing the failure. 48 */ 49 public abstract class HotSpotRetryableCompilation<T> extends DebugRetryableTask<T> { 50 51 protected final HotSpotGraalRuntimeProvider runtime; 52 53 public HotSpotRetryableCompilation(HotSpotGraalRuntimeProvider runtime) { 54 this.runtime = runtime; 55 } 56 57 /** 58 * Gets a value that represents the compilation unit being compiled. 59 */ 60 @Override 61 public abstract String toString(); 62 63 @Override 64 protected DebugContext getRetryContext(DebugContext initialDebug, Throwable t) { 65 if (t instanceof BailoutException) { 66 return null; 67 } 68 69 OptionValues initialOptions = initialDebug.getOptions(); 70 if (Dump.hasBeenSet(initialOptions)) { 71 // If dumping is explicitly enabled, Graal is being debugged 72 // so don't interfere with what the user is expecting to see. 73 return null; 74 } 75 76 String outputDirectory = runtime.getOutputDirectory(); 77 if (outputDirectory == null) { 78 return null; 79 } 80 String dumpName = GraalDebugHandlersFactory.sanitizedFileName(toString()); 81 File dumpPath = new File(outputDirectory, dumpName); 82 dumpPath.mkdirs(); 83 if (!dumpPath.exists()) { 84 TTY.println("Warning: could not create dump directory " + dumpPath); 85 return null; 86 } 87 88 TTY.println("Retrying compilation of " + this + " due to " + t); 89 retryLogPath = new File(dumpPath, "retry.log").getPath(); 90 log("Exception causing retry", t); 91 OptionValues retryOptions = new OptionValues(initialOptions, 92 Dump, ":" + VERBOSE_LEVEL, 93 MethodFilter, null, 94 DumpPath, dumpPath.getPath()); 95 SnippetReflectionProvider snippetReflection = runtime.getHostProviders().getSnippetReflection(); 96 return DebugContext.create(retryOptions, new GraalDebugHandlersFactory(snippetReflection)); 97 } 98 99 private String retryLogPath; 100 101 /** 102 * Prints a message to a retry log file. 103 * 104 * @param message the message to print 105 * @param t if non-{@code null}, the stack trace for this exception is written to the retry log 106 * after {@code message} 107 */ 108 protected void log(String message, Throwable t) { 109 if (retryLogPath != null) { 110 try (PrintStream retryLog = new PrintStream(new FileOutputStream(retryLogPath), true)) { 111 StringBuilder buf = new StringBuilder(Thread.currentThread() + ": " + message); 112 if (t != null) { 113 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 114 t.printStackTrace(new PrintStream(baos)); 115 buf.append(System.lineSeparator()).append(baos.toString()); 116 } 117 retryLog.println(buf); 118 } catch (FileNotFoundException e) { 119 TTY.println("Warning: could not open retry log file " + retryLogPath + " [" + e + "]"); 120 } 121 } 122 } 123 } |