1 /*
   2  * Copyright (c) 2016, 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 package jdk.tools.jaotc;
  25 
  26 import java.util.concurrent.TimeUnit;
  27 import java.util.concurrent.atomic.AtomicInteger;
  28 
  29 import org.graalvm.compiler.code.CompilationResult;
  30 import org.graalvm.compiler.core.GraalCompilerOptions;
  31 import org.graalvm.compiler.debug.Debug;
  32 import org.graalvm.compiler.debug.DebugEnvironment;
  33 import org.graalvm.compiler.debug.Management;
  34 import org.graalvm.compiler.debug.TTY;
  35 import org.graalvm.compiler.debug.internal.DebugScope;
  36 import org.graalvm.compiler.options.OptionValues;
  37 
  38 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  39 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  40 import jdk.vm.ci.meta.ResolvedJavaMethod;
  41 import jdk.vm.ci.runtime.JVMCICompiler;
  42 
  43 /**
  44  * Represents a task in the compile queue.
  45  *
  46  * This class encapsulates all Graal-specific information that is used during offline AOT
  47  * compilation of classes. It also defines methods that parse compilation result of Graal to create
  48  * target-independent representation {@code BinaryContainer} of the intended target binary.
  49  */
  50 public class AOTCompilationTask implements Runnable, Comparable<Object> {
  51 
  52     private static final AtomicInteger ids = new AtomicInteger();
  53 
  54     private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) Management.getThreadMXBean();
  55 
  56     private final Main main;
  57 
  58     private OptionValues graalOptions;
  59 
  60     /**
  61      * The compilation id of this task.
  62      */
  63     private final int id;
  64 
  65     private final AOTCompiledClass holder;
  66 
  67     /**
  68      * Method this task represents.
  69      */
  70     private final ResolvedJavaMethod method;
  71 
  72     private final AOTBackend aotBackend;
  73 
  74     /**
  75      * The result of this compilation task.
  76      */
  77     private CompiledMethodInfo result;
  78 
  79     public AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
  80         this.main = main;
  81         this.graalOptions = graalOptions;
  82         this.id = ids.getAndIncrement();
  83         this.holder = holder;
  84         this.method = method;
  85         this.aotBackend = aotBackend;
  86     }
  87 
  88     /**
  89      * Compile a method or a constructor.
  90      */
  91     public void run() {
  92         // Ensure a JVMCI runtime is initialized prior to Debug being initialized as the former
  93         // may include processing command line options used by the latter.
  94         HotSpotJVMCIRuntime.runtime();
  95 
  96         // Ensure a debug configuration for this thread is initialized
  97         if (Debug.isEnabled() && DebugScope.getConfig() == null) {
  98             DebugEnvironment.ensureInitialized(graalOptions);
  99         }
 100         AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
 101 
 102         final long threadId = Thread.currentThread().getId();
 103 
 104         final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed();
 105         final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue(graalOptions) && !TTY.isSuppressed();
 106         if (printCompilation) {
 107             TTY.println(getMethodDescription() + "...");
 108         }
 109 
 110         final long start;
 111         final long allocatedBytesBefore;
 112         if (printAfterCompilation || printCompilation) {
 113             start = System.currentTimeMillis();
 114             allocatedBytesBefore = printAfterCompilation || printCompilation ? threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
 115         } else {
 116             start = 0L;
 117             allocatedBytesBefore = 0L;
 118         }
 119 
 120         final long startTime = System.currentTimeMillis();
 121         CompilationResult compResult = aotBackend.compileMethod(method);
 122         final long endTime = System.currentTimeMillis();
 123 
 124         if (printAfterCompilation || printCompilation) {
 125             final long stop = System.currentTimeMillis();
 126             final int targetCodeSize = compResult != null ? compResult.getTargetCodeSize() : -1;
 127             final long allocatedBytesAfter = threadMXBean.getThreadAllocatedBytes(threadId);
 128             final long allocatedBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
 129 
 130             if (printAfterCompilation) {
 131                 TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dkB", stop - start, targetCodeSize, allocatedBytes));
 132             } else if (printCompilation) {
 133                 TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dkB", getId(), "", "", "", stop - start, targetCodeSize, allocatedBytes));
 134             }
 135         }
 136 
 137         if (compResult == null) {
 138             result = null;
 139             return;
 140         }
 141 
 142         // For now precision to the nearest second is sufficient.
 143         Main.writeLog("    Compile Time: " + TimeUnit.MILLISECONDS.toSeconds(endTime - startTime) + "secs");
 144         if (main.options.debug) {
 145             aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
 146         }
 147 
 148         result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method));
 149     }
 150 
 151     private String getMethodDescription() {
 152         return String.format("%-6d JVMCI %-70s %-45s %-50s %s", getId(), method.getDeclaringClass().getName(), method.getName(), method.getSignature().toMethodDescriptor(),
 153                         getEntryBCI() == JVMCICompiler.INVOCATION_ENTRY_BCI ? "" : "(OSR@" + getEntryBCI() + ") ");
 154     }
 155 
 156     private int getId() {
 157         return id;
 158     }
 159 
 160     public int getEntryBCI() {
 161         return JVMCICompiler.INVOCATION_ENTRY_BCI;
 162     }
 163 
 164     public ResolvedJavaMethod getMethod() {
 165         return method;
 166     }
 167 
 168     /**
 169      * Returns the holder of this method as a {@link AOTCompiledClass}.
 170      *
 171      * @return the holder of this method
 172      */
 173     public AOTCompiledClass getHolder() {
 174         return holder;
 175     }
 176 
 177     /**
 178      * Returns the result of this compilation task.
 179      *
 180      * @return result of this compilation task
 181      */
 182     public CompiledMethodInfo getResult() {
 183         return result;
 184     }
 185 
 186     @Override
 187     public int compareTo(Object obj) {
 188         AOTCompilationTask other = (AOTCompilationTask) obj;
 189         return this.id - other.id;
 190     }
 191 
 192     @Override
 193     public boolean equals(Object obj) {
 194         if (this == obj)
 195             return true;
 196         if (obj == null)
 197             return false;
 198         if (getClass() != obj.getClass())
 199             return false;
 200         AOTCompilationTask other = (AOTCompilationTask) obj;
 201         return (this.id == other.id);
 202     }
 203 
 204     @Override
 205     public int hashCode() {
 206         return 31 + id;
 207     }
 208 
 209 }