org.openjdk.jmh.runner.CompilerHints Maven / Gradle / Ivy
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.jmh.runner;
import org.openjdk.jmh.util.FileUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.*;
public class CompilerHints extends AbstractResourceReader {
public static final String LIST = "/META-INF/CompilerHints";
// All OpenJDK/HotSpot VMs are supported
static final String[] HINT_COMPATIBLE_JVMS = { "OpenJDK", "HotSpot", "GraalVM" };
// Zing is only compatible from post 5.10.*.* releases
static final String JVM_ZING = "Zing";
private static volatile CompilerHints defaultList;
private static volatile String hintsFile;
private final Set hints;
static final String XX_COMPILE_COMMAND_FILE = "-XX:CompileCommandFile=";
public static CompilerHints defaultList() {
if (defaultList == null) {
defaultList = fromResource(LIST);
}
return defaultList;
}
public static String hintsFile() {
if (hintsFile == null) {
try {
final Set defaultHints = defaultList().get();
List hints = new ArrayList<>(defaultHints.size() + 2);
hints.add("quiet");
if (Boolean.getBoolean("jmh.blackhole.forceInline")) {
hints.add("inline,org/openjdk/jmh/infra/Blackhole.*");
} else {
hints.add("dontinline,org/openjdk/jmh/infra/Blackhole.*");
}
hints.addAll(defaultHints);
hintsFile = FileUtils.createTempFileWithLines("compilecommand", hints);
} catch (IOException e) {
throw new IllegalStateException("Error creating compiler hints file", e);
}
}
return hintsFile;
}
public static CompilerHints fromResource(String resource) {
return new CompilerHints(null, resource);
}
public static CompilerHints fromFile(String file) {
return new CompilerHints(file, null);
}
private CompilerHints(String file, String resource) {
super(file, resource, null);
hints = Collections.unmodifiableSet(read());
}
/**
* FIXME (low priority): check if supplied JVM is hint compatible. This test is applied to the Runner VM,
* not the Forked and may therefore be wrong if the forked VM is not the same JVM
*/
private static boolean isHintCompatibleVM() {
String name = System.getProperty("java.vm.name");
for (String vmName : HINT_COMPATIBLE_JVMS) {
if (name.contains(vmName)) {
return true;
}
}
if (name.contains(JVM_ZING)) {
// 1.*.0-zing_*.*.*.*
String version = System.getProperty("java.version");
try {
// get the version digits
String[] versionDigits = version.substring(version.indexOf('_') + 1).split("\\.");
if (Integer.valueOf(versionDigits[0]) > 5) {
return true;
} else if (Integer.valueOf(versionDigits[0]) == 5 && Integer.valueOf(versionDigits[1]) >= 10) {
return true;
}
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
// unknown Zing version format
System.err.println("ERROR: Zing version format does not match 1.*.0-zing_*.*.*.*");
}
}
return false;
}
public Set get() {
return hints;
}
private Set read() {
Set result = new TreeSet<>();
try {
for (Reader r : getReaders()) {
BufferedReader reader = null;
try {
reader = new BufferedReader(r);
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
if (line.startsWith("#")) {
continue;
}
if (line.trim().isEmpty()) {
continue;
}
result.add(line);
}
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// ignore
}
}
}
} catch (IOException ex) {
throw new RuntimeException("Error reading compiler hints", ex);
}
return result;
}
/**
* @param command command arguments list
* @return the compiler hint files specified by the command
*/
public static List getCompileCommandFiles(List command){
List compileCommandFiles = new ArrayList<>();
for (String cmdLineWord : command) {
if (cmdLineWord.startsWith(XX_COMPILE_COMMAND_FILE)) {
compileCommandFiles.add(cmdLineWord.substring(XX_COMPILE_COMMAND_FILE.length()));
}
}
return compileCommandFiles;
}
/**
* We need to generate a compiler hints file such that it includes:
*
* - No compile command files are specified and no .hotspotrc file is available, then do JMH hints only
*
- No compile command files are specified and .hotspotrc file is available, then do JMH hints + .hotspotrc
*
- 1 to N compile command files are specified, then do JMH hints + all specified hints in files
*
* This is a departure from default JVM behavior as the JVM would normally just take the last hints file and ignore
* the rest.
*
* @param command all -XX:CompileCommandLine args will be removed and a merged file will be set
*/
public static void addCompilerHints(List command) {
if (!isHintCompatibleVM()) {
System.err.println("WARNING: Not a HotSpot compiler command compatible VM (\""
+ System.getProperty("java.vm.name") + "-" + System.getProperty("java.version")
+ "\"), compilerHints are disabled.");
return;
}
List hintFiles = new ArrayList<>();
hintFiles.add(hintsFile());
removeCompileCommandFiles(command, hintFiles);
if (hintFiles.size() == 1) {
File hotspotCompilerFile = new File(".hotspot_compiler");
if (hotspotCompilerFile.exists()) {
hintFiles.add(hotspotCompilerFile.getAbsolutePath());
}
}
command.add(CompilerHints.XX_COMPILE_COMMAND_FILE + mergeHintFiles(hintFiles));
}
/**
* @param command the compile command file options will be removed from this command
* @param compileCommandFiles the compiler hint files specified by the command will be added to this list
*/
private static void removeCompileCommandFiles(List command, List compileCommandFiles){
Iterator iterator = command.iterator();
while (iterator.hasNext()) {
String cmdLineWord = iterator.next();
if(cmdLineWord.startsWith(XX_COMPILE_COMMAND_FILE)) {
compileCommandFiles.add(cmdLineWord.substring(XX_COMPILE_COMMAND_FILE.length()));
iterator.remove();
}
}
}
private static String mergeHintFiles(List compileCommandFiles) {
if (compileCommandFiles.size() == 1) {
return compileCommandFiles.get(0);
}
try {
Set hints = new TreeSet<>();
for(String file : compileCommandFiles) {
hints.addAll(fromFile(file).get());
}
return FileUtils.createTempFileWithLines("compilecommand", hints);
} catch (IOException e) {
throw new IllegalStateException("Error merging compiler hints files", e);
}
}
}