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.debug; 24 25 import static java.util.FormattableFlags.LEFT_JUSTIFY; 26 import static java.util.FormattableFlags.UPPERCASE; 27 import static org.graalvm.compiler.debug.DebugOptions.Count; 28 import static org.graalvm.compiler.debug.DebugOptions.Counters; 29 import static org.graalvm.compiler.debug.DebugOptions.Dump; 30 import static org.graalvm.compiler.debug.DebugOptions.DumpOnError; 31 import static org.graalvm.compiler.debug.DebugOptions.DumpOnPhaseChange; 32 import static org.graalvm.compiler.debug.DebugOptions.ListMetrics; 33 import static org.graalvm.compiler.debug.DebugOptions.Log; 34 import static org.graalvm.compiler.debug.DebugOptions.MemUseTrackers; 35 import static org.graalvm.compiler.debug.DebugOptions.Time; 36 import static org.graalvm.compiler.debug.DebugOptions.Timers; 37 import static org.graalvm.compiler.debug.DebugOptions.TrackMemUse; 38 39 import java.io.ByteArrayOutputStream; 40 import java.io.File; 41 import java.io.IOException; 42 import java.io.PrintStream; 43 import java.nio.file.Files; 44 import java.nio.file.Path; 45 import java.nio.file.Paths; 46 import java.nio.file.StandardOpenOption; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.Collection; 50 import java.util.Collections; 51 import java.util.Formatter; 52 import java.util.List; 53 import java.util.Map; 54 import java.util.SortedMap; 55 import java.util.TreeMap; 56 57 import org.graalvm.compiler.options.OptionKey; 58 import org.graalvm.compiler.options.OptionValues; 59 import org.graalvm.util.EconomicMap; 60 import org.graalvm.util.EconomicSet; 61 import org.graalvm.util.Pair; 62 63 import jdk.vm.ci.meta.JavaMethod; 64 65 /** 66 * A facility for logging and dumping as well as a container for values associated with 67 * {@link MetricKey}s. 68 * 69 * A {@code DebugContext} object must only be used on the thread that created it. This means it 70 * needs to be passed around as a parameter. For convenience, it can be encapsulated in a widely 71 * used object that is in scope wherever a {@code DebugContext} is needed. However, care must be 72 * taken when such objects can be exposed to multiple threads (e.g., they are in a non-thread-local 73 * cache). 74 */ 75 public final class DebugContext implements AutoCloseable { 76 77 public static final Description NO_DESCRIPTION = null; 78 public static final GlobalMetrics NO_GLOBAL_METRIC_VALUES = null; 81 public static final PrintStream DEFAULT_LOG_STREAM = TTY.out; 82 83 /** 84 * Contains the immutable parts of a debug context. This separation allows the immutable parts 85 * to be shared and reduces the overhead of initialization since most immutable fields are 86 * configured by parsing options. 87 */ 88 final Immutable immutable; 89 90 /** 91 * Determines whether metrics are enabled. 92 */ 93 boolean metricsEnabled; 94 95 DebugConfig currentConfig; 96 ScopeImpl currentScope; 97 CloseableCounter currentTimer; 98 CloseableCounter currentMemUseTracker; 99 Scope lastClosedScope; 100 Throwable lastExceptionThrown; 101 102 /** 103 * Stores the {@link MetricKey} values. 104 */ 105 private long[] metricValues; 106 107 /** 108 * Determines if dynamic scopes are enabled. 109 */ 110 public boolean areScopesEnabled() { 111 return immutable.scopesEnabled; 112 } 113 114 /** 115 * The immutable configuration that can be shared between {@link DebugContext} objects. 116 */ 117 static final class Immutable { 118 119 private static final Immutable[] CACHE = new Immutable[5]; 120 121 /** 122 * The options from which this object was configured. 123 */ 124 final OptionValues options; 125 126 /** 127 * Specifies if dynamic scopes are enabled. 128 */ 129 final boolean scopesEnabled; 130 131 final boolean listMetrics; 132 133 /** 306 /** 307 * The primary input to the computation. 308 */ 309 final Object compilable; 310 311 /** 312 * A runtime based identifier that is most likely to be unique. 313 */ 314 final String identifier; 315 316 public Description(Object compilable, String identifier) { 317 this.compilable = compilable; 318 this.identifier = identifier; 319 } 320 321 @Override 322 public String toString() { 323 String compilableName = compilable instanceof JavaMethod ? ((JavaMethod) compilable).format("%H.%n(%p)%R") : String.valueOf(compilable); 324 return identifier + ":" + compilableName; 325 } 326 } 327 328 private final Description description; 329 330 /** 331 * Gets a description of the computation associated with this debug context. 332 * 333 * @return {@code null} if no description is available 334 */ 335 public Description getDescription() { 336 return description; 337 } 338 339 /** 340 * Gets the global metrics associated with this debug context. 341 * 342 * @return {@code null} if no global metrics are available 343 */ 344 public GlobalMetrics getGlobalMetrics() { 345 return globalMetrics; 377 List<DebugVerifyHandler> verifyHandlers = new ArrayList<>(); 378 for (DebugHandlersFactory factory : factories) { 379 for (DebugHandler handler : factory.createHandlers(options)) { 380 if (handler instanceof DebugDumpHandler) { 381 dumpHandlers.add((DebugDumpHandler) handler); 382 } else { 383 assert handler instanceof DebugVerifyHandler; 384 verifyHandlers.add((DebugVerifyHandler) handler); 385 } 386 } 387 } 388 currentConfig = new DebugConfigImpl(options, logStream, dumpHandlers, verifyHandlers); 389 currentScope = new ScopeImpl(this, Thread.currentThread()); 390 currentScope.updateFlags(currentConfig); 391 metricsEnabled = true; 392 } else { 393 metricsEnabled = immutable.hasUnscopedMetrics() || immutable.listMetrics; 394 } 395 } 396 397 /** 398 * A special dump level that indicates the dumping machinery is enabled but no dumps will be 399 * produced except through other options. 400 */ 401 public static final int ENABLED_LEVEL = 0; 402 403 /** 404 * Basic debug level. 405 * 406 * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier, 407 * after mid tier, after low tier. 408 * 409 * LIR dumping: After LIR generation, after each pre-allocation, allocation and post allocation 410 * stage, and after code installation. 411 */ 412 public static final int BASIC_LEVEL = 1; 413 414 /** 415 * Informational debug level. 416 * 2025 continue; 2026 } 2027 valueString = ms + "ms"; 2028 } else { 2029 valueString = String.valueOf(value); 2030 } 2031 res.put(name, valueString); 2032 maxKeyWidth = Math.max(maxKeyWidth, name.length()); 2033 } 2034 } 2035 2036 String title = String.format("%s [id:%s compilation:%d compilation_id:%s]", compilableName, identity, compilationNr, compilationId); 2037 out.println(new String(new char[title.length()]).replace('\0', '#')); 2038 out.printf("%s%n", title); 2039 out.println(new String(new char[title.length()]).replace('\0', '~')); 2040 2041 for (Map.Entry<String, String> e : res.entrySet()) { 2042 out.printf("%-" + String.valueOf(maxKeyWidth) + "s = %20s%n", e.getKey(), e.getValue()); 2043 } 2044 out.println(); 2045 } 2046 } | 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.debug; 24 25 import static java.util.FormattableFlags.LEFT_JUSTIFY; 26 import static java.util.FormattableFlags.UPPERCASE; 27 import static org.graalvm.compiler.debug.DebugOptions.Count; 28 import static org.graalvm.compiler.debug.DebugOptions.Counters; 29 import static org.graalvm.compiler.debug.DebugOptions.Dump; 30 import static org.graalvm.compiler.debug.DebugOptions.DumpOnError; 31 import static org.graalvm.compiler.debug.DebugOptions.DumpOnPhaseChange; 32 import static org.graalvm.compiler.debug.DebugOptions.DumpPath; 33 import static org.graalvm.compiler.debug.DebugOptions.ListMetrics; 34 import static org.graalvm.compiler.debug.DebugOptions.Log; 35 import static org.graalvm.compiler.debug.DebugOptions.MemUseTrackers; 36 import static org.graalvm.compiler.debug.DebugOptions.ShowDumpFiles; 37 import static org.graalvm.compiler.debug.DebugOptions.Time; 38 import static org.graalvm.compiler.debug.DebugOptions.Timers; 39 import static org.graalvm.compiler.debug.DebugOptions.TrackMemUse; 40 41 import java.io.ByteArrayOutputStream; 42 import java.io.File; 43 import java.io.IOException; 44 import java.io.PrintStream; 45 import java.nio.file.Files; 46 import java.nio.file.Path; 47 import java.nio.file.Paths; 48 import java.nio.file.StandardOpenOption; 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.Collection; 52 import java.util.Collections; 53 import java.util.Formatter; 54 import java.util.List; 55 import java.util.Map; 56 import java.util.SortedMap; 57 import java.util.TreeMap; 58 59 import org.graalvm.compiler.options.OptionKey; 60 import org.graalvm.compiler.options.OptionValues; 61 import org.graalvm.graphio.GraphOutput; 62 import org.graalvm.util.EconomicMap; 63 import org.graalvm.util.EconomicSet; 64 import org.graalvm.util.Pair; 65 66 import jdk.vm.ci.meta.JavaMethod; 67 68 /** 69 * A facility for logging and dumping as well as a container for values associated with 70 * {@link MetricKey}s. 71 * 72 * A {@code DebugContext} object must only be used on the thread that created it. This means it 73 * needs to be passed around as a parameter. For convenience, it can be encapsulated in a widely 74 * used object that is in scope wherever a {@code DebugContext} is needed. However, care must be 75 * taken when such objects can be exposed to multiple threads (e.g., they are in a non-thread-local 76 * cache). 77 */ 78 public final class DebugContext implements AutoCloseable { 79 80 public static final Description NO_DESCRIPTION = null; 81 public static final GlobalMetrics NO_GLOBAL_METRIC_VALUES = null; 84 public static final PrintStream DEFAULT_LOG_STREAM = TTY.out; 85 86 /** 87 * Contains the immutable parts of a debug context. This separation allows the immutable parts 88 * to be shared and reduces the overhead of initialization since most immutable fields are 89 * configured by parsing options. 90 */ 91 final Immutable immutable; 92 93 /** 94 * Determines whether metrics are enabled. 95 */ 96 boolean metricsEnabled; 97 98 DebugConfig currentConfig; 99 ScopeImpl currentScope; 100 CloseableCounter currentTimer; 101 CloseableCounter currentMemUseTracker; 102 Scope lastClosedScope; 103 Throwable lastExceptionThrown; 104 private IgvDumpChannel sharedChannel; 105 private GraphOutput<?, ?> parentOutput; 106 107 /** 108 * Stores the {@link MetricKey} values. 109 */ 110 private long[] metricValues; 111 112 /** 113 * Determines if dynamic scopes are enabled. 114 */ 115 public boolean areScopesEnabled() { 116 return immutable.scopesEnabled; 117 } 118 119 public <G, N, M> GraphOutput<G, M> buildOutput(GraphOutput.Builder<G, N, M> builder) throws IOException { 120 if (parentOutput != null) { 121 return builder.build(parentOutput); 122 } else { 123 if (sharedChannel == null) { 124 sharedChannel = new IgvDumpChannel(() -> getDumpPath(".bgv", false), immutable.options); 125 } 126 final GraphOutput<G, M> output = builder.build(sharedChannel); 127 parentOutput = output; 128 return output; 129 } 130 } 131 132 /** 133 * The immutable configuration that can be shared between {@link DebugContext} objects. 134 */ 135 static final class Immutable { 136 137 private static final Immutable[] CACHE = new Immutable[5]; 138 139 /** 140 * The options from which this object was configured. 141 */ 142 final OptionValues options; 143 144 /** 145 * Specifies if dynamic scopes are enabled. 146 */ 147 final boolean scopesEnabled; 148 149 final boolean listMetrics; 150 151 /** 324 /** 325 * The primary input to the computation. 326 */ 327 final Object compilable; 328 329 /** 330 * A runtime based identifier that is most likely to be unique. 331 */ 332 final String identifier; 333 334 public Description(Object compilable, String identifier) { 335 this.compilable = compilable; 336 this.identifier = identifier; 337 } 338 339 @Override 340 public String toString() { 341 String compilableName = compilable instanceof JavaMethod ? ((JavaMethod) compilable).format("%H.%n(%p)%R") : String.valueOf(compilable); 342 return identifier + ":" + compilableName; 343 } 344 345 final String getLabel() { 346 if (compilable instanceof JavaMethod) { 347 JavaMethod method = (JavaMethod) compilable; 348 return method.format("%h.%n(%p)%r"); 349 } 350 return String.valueOf(compilable); 351 } 352 } 353 354 private final Description description; 355 356 /** 357 * Gets a description of the computation associated with this debug context. 358 * 359 * @return {@code null} if no description is available 360 */ 361 public Description getDescription() { 362 return description; 363 } 364 365 /** 366 * Gets the global metrics associated with this debug context. 367 * 368 * @return {@code null} if no global metrics are available 369 */ 370 public GlobalMetrics getGlobalMetrics() { 371 return globalMetrics; 403 List<DebugVerifyHandler> verifyHandlers = new ArrayList<>(); 404 for (DebugHandlersFactory factory : factories) { 405 for (DebugHandler handler : factory.createHandlers(options)) { 406 if (handler instanceof DebugDumpHandler) { 407 dumpHandlers.add((DebugDumpHandler) handler); 408 } else { 409 assert handler instanceof DebugVerifyHandler; 410 verifyHandlers.add((DebugVerifyHandler) handler); 411 } 412 } 413 } 414 currentConfig = new DebugConfigImpl(options, logStream, dumpHandlers, verifyHandlers); 415 currentScope = new ScopeImpl(this, Thread.currentThread()); 416 currentScope.updateFlags(currentConfig); 417 metricsEnabled = true; 418 } else { 419 metricsEnabled = immutable.hasUnscopedMetrics() || immutable.listMetrics; 420 } 421 } 422 423 public Path getDumpPath(String extension, boolean directory) { 424 try { 425 String id = description == null ? null : description.identifier; 426 String label = description == null ? null : description.getLabel(); 427 Path result = PathUtilities.createUnique(immutable.options, DumpPath, id, label, extension, directory); 428 if (ShowDumpFiles.getValue(immutable.options)) { 429 TTY.println("Dumping debug output to %s", result.toAbsolutePath().toString()); 430 } 431 return result; 432 } catch (IOException ex) { 433 throw rethrowSilently(RuntimeException.class, ex); 434 } 435 } 436 437 /** 438 * A special dump level that indicates the dumping machinery is enabled but no dumps will be 439 * produced except through other options. 440 */ 441 public static final int ENABLED_LEVEL = 0; 442 443 /** 444 * Basic debug level. 445 * 446 * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier, 447 * after mid tier, after low tier. 448 * 449 * LIR dumping: After LIR generation, after each pre-allocation, allocation and post allocation 450 * stage, and after code installation. 451 */ 452 public static final int BASIC_LEVEL = 1; 453 454 /** 455 * Informational debug level. 456 * 2065 continue; 2066 } 2067 valueString = ms + "ms"; 2068 } else { 2069 valueString = String.valueOf(value); 2070 } 2071 res.put(name, valueString); 2072 maxKeyWidth = Math.max(maxKeyWidth, name.length()); 2073 } 2074 } 2075 2076 String title = String.format("%s [id:%s compilation:%d compilation_id:%s]", compilableName, identity, compilationNr, compilationId); 2077 out.println(new String(new char[title.length()]).replace('\0', '#')); 2078 out.printf("%s%n", title); 2079 out.println(new String(new char[title.length()]).replace('\0', '~')); 2080 2081 for (Map.Entry<String, String> e : res.entrySet()) { 2082 out.printf("%-" + String.valueOf(maxKeyWidth) + "s = %20s%n", e.getKey(), e.getValue()); 2083 } 2084 out.println(); 2085 } 2086 2087 @SuppressWarnings({"unused", "unchecked"}) 2088 private static <E extends Exception> E rethrowSilently(Class<E> type, Throwable ex) throws E { 2089 throw (E) ex; 2090 } 2091 } |