1 /* 2 * Copyright (c) 2016, 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 package requires; 24 25 import java.io.IOException; 26 import java.nio.file.Files; 27 import java.nio.file.Path; 28 import java.nio.file.Paths; 29 import java.nio.file.StandardOpenOption; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.concurrent.Callable; 35 import java.util.concurrent.TimeUnit; 36 import java.util.regex.Matcher; 37 import java.util.regex.Pattern; 38 39 import sun.hotspot.cpuinfo.CPUInfo; 40 import sun.hotspot.gc.GC; 41 import sun.hotspot.WhiteBox; 42 import jdk.test.lib.Platform; 43 44 /** 45 * The Class to be invoked by jtreg prior Test Suite execution to 46 * collect information about VM. 47 * Do not use any API's that may not be available in all target VMs. 48 * Properties set by this Class will be available in the @requires expressions. 49 */ 50 public class VMProps implements Callable<Map<String, String>> { 51 52 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 53 54 /** 55 * Collects information about VM properties. 56 * This method will be invoked by jtreg. 57 * 58 * @return Map of property-value pairs. 59 */ 60 @Override 61 public Map<String, String> call() { 62 Map<String, String> map = new HashMap<>(); 63 map.put("vm.flavor", vmFlavor()); 64 map.put("vm.compMode", vmCompMode()); 65 map.put("vm.bits", vmBits()); 66 map.put("vm.flightRecorder", vmFlightRecorder()); 67 map.put("vm.simpleArch", vmArch()); 68 map.put("vm.debug", vmDebug()); 69 map.put("vm.jvmci", vmJvmci()); 70 map.put("vm.emulatedClient", vmEmulatedClient()); 71 map.put("vm.cpu.features", cpuFeatures()); 72 map.put("vm.rtm.cpu", vmRTMCPU()); 73 map.put("vm.rtm.os", vmRTMOS()); 74 map.put("vm.aot", vmAOT()); 75 // vm.cds is true if the VM is compiled with cds support. 76 map.put("vm.cds", vmCDS()); 77 map.put("vm.cds.custom.loaders", vmCDSForCustomLoaders()); 78 map.put("vm.cds.archived.java.heap", vmCDSForArchivedJavaHeap()); 79 // vm.graal.enabled is true if Graal is used as JIT 80 map.put("vm.graal.enabled", isGraalEnabled()); 81 map.put("docker.support", dockerSupport()); 82 vmGC(map); // vm.gc.X = true/false 83 84 VMProps.dump(map); 85 return map; 86 } 87 88 /** 89 * Prints a stack trace before returning null. 90 * Used by the various helper functions which parse information from 91 * VM properties in the case where they don't find an expected property 92 * or a propoerty doesn't conform to an expected format. 93 * 94 * @return null 95 */ 96 private String nullWithException(String message) { 97 new Exception(message).printStackTrace(); 98 return null; 99 } 100 101 /** 102 * @return vm.simpleArch value of "os.simpleArch" property of tested JDK. 103 */ 104 protected String vmArch() { 105 String arch = System.getProperty("os.arch"); 106 if (arch.equals("x86_64") || arch.equals("amd64")) { 107 return "x64"; 108 } 109 else if (arch.contains("86")) { 110 return "x86"; 111 } else { 112 return arch; 113 } 114 } 115 116 117 118 /** 119 * @return VM type value extracted from the "java.vm.name" property. 120 */ 121 protected String vmFlavor() { 122 // E.g. "Java HotSpot(TM) 64-Bit Server VM" 123 String vmName = System.getProperty("java.vm.name"); 124 if (vmName == null) { 125 return nullWithException("Can't get 'java.vm.name' property"); 126 } 127 128 Pattern startP = Pattern.compile(".* (\\S+) VM"); 129 Matcher m = startP.matcher(vmName); 130 if (m.matches()) { 131 return m.group(1).toLowerCase(); 132 } 133 return nullWithException("Can't get VM flavor from 'java.vm.name'"); 134 } 135 136 /** 137 * @return VM compilation mode extracted from the "java.vm.info" property. 138 */ 139 protected String vmCompMode() { 140 // E.g. "mixed mode" 141 String vmInfo = System.getProperty("java.vm.info"); 142 if (vmInfo == null) { 143 return nullWithException("Can't get 'java.vm.info' property"); 144 } 145 if (vmInfo.toLowerCase().indexOf("mixed mode") != -1) { 146 return "Xmixed"; 147 } else if (vmInfo.toLowerCase().indexOf("compiled mode") != -1) { 148 return "Xcomp"; 149 } else if (vmInfo.toLowerCase().indexOf("interpreted mode") != -1) { 150 return "Xint"; 151 } else { 152 return nullWithException("Can't get compilation mode from 'java.vm.info'"); 153 } 154 } 155 156 /** 157 * @return VM bitness, the value of the "sun.arch.data.model" property. 158 */ 159 protected String vmBits() { 160 String dataModel = System.getProperty("sun.arch.data.model"); 161 if (dataModel != null) { 162 return dataModel; 163 } else { 164 return nullWithException("Can't get 'sun.arch.data.model' property"); 165 } 166 } 167 168 /** 169 * @return "true" if Flight Recorder is enabled, "false" if is disabled. 170 */ 171 protected String vmFlightRecorder() { 172 Boolean isUnlockedCommercialFatures = WB.getBooleanVMFlag("UnlockCommercialFeatures"); 173 Boolean isFlightRecorder = WB.getBooleanVMFlag("FlightRecorder"); 174 String startFROptions = WB.getStringVMFlag("StartFlightRecording"); 175 if (isUnlockedCommercialFatures != null && isUnlockedCommercialFatures) { 176 if (isFlightRecorder != null && isFlightRecorder) { 177 return "true"; 178 } 179 if (startFROptions != null && !startFROptions.isEmpty()) { 180 return "true"; 181 } 182 } 183 return "false"; 184 } 185 186 /** 187 * @return debug level value extracted from the "jdk.debug" property. 188 */ 189 protected String vmDebug() { 190 String debug = System.getProperty("jdk.debug"); 191 if (debug != null) { 192 return "" + debug.contains("debug"); 193 } else { 194 return nullWithException("Can't get 'jdk.debug' property"); 195 } 196 } 197 198 /** 199 * @return true if VM supports JVMCI and false otherwise 200 */ 201 protected String vmJvmci() { 202 // builds with jvmci have this flag 203 return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); 204 } 205 206 /** 207 * @return true if VM runs in emulated-client mode and false otherwise. 208 */ 209 protected String vmEmulatedClient() { 210 String vmInfo = System.getProperty("java.vm.info"); 211 if (vmInfo == null) { 212 return "false"; 213 } 214 return "" + vmInfo.contains(" emulated-client"); 215 } 216 217 /** 218 * @return supported CPU features 219 */ 220 protected String cpuFeatures() { 221 return CPUInfo.getFeatures().toString(); 222 } 223 224 /** 225 * For all existing GC sets vm.gc.X property. 226 * Example vm.gc.G1=true means: 227 * VM supports G1 228 * User either set G1 explicitely (-XX:+UseG1GC) or did not set any GC 229 * @param map - property-value pairs 230 */ 231 protected void vmGC(Map<String, String> map){ 232 GC currentGC = GC.current(); 233 boolean isByErgo = GC.currentSetByErgo(); 234 List<GC> supportedGC = GC.allSupported(); 235 for (GC gc: GC.values()) { 236 boolean isSupported = supportedGC.contains(gc); 237 boolean isAcceptable = isSupported && (gc == currentGC || isByErgo); 238 map.put("vm.gc." + gc.name(), "" + isAcceptable); 239 } 240 } 241 242 /** 243 * @return true if VM runs RTM supported OS and false otherwise. 244 */ 245 protected String vmRTMOS() { 246 boolean isRTMOS = true; 247 248 if (Platform.isAix()) { 249 // Actually, this works since AIX 7.1.3.30, but os.version property 250 // is set to 7.1. 251 isRTMOS = (Platform.getOsVersionMajor() > 7) || 252 (Platform.getOsVersionMajor() == 7 && Platform.getOsVersionMinor() > 1); 253 254 } else if (Platform.isLinux()) { 255 if (Platform.isPPC()) { 256 isRTMOS = (Platform.getOsVersionMajor() > 4) || 257 (Platform.getOsVersionMajor() == 4 && Platform.getOsVersionMinor() > 1); 258 } 259 } 260 return "" + isRTMOS; 261 } 262 263 /** 264 * @return true if VM runs RTM supported CPU and false otherwise. 265 */ 266 protected String vmRTMCPU() { 267 boolean vmRTMCPU = (Platform.isPPC() ? CPUInfo.hasFeature("tcheck") : CPUInfo.hasFeature("rtm")); 268 269 return "" + vmRTMCPU; 270 } 271 272 /** 273 * @return true if VM supports AOT and false otherwise 274 */ 275 protected String vmAOT() { 276 // builds with aot have jaotc in <JDK>/bin 277 Path bin = Paths.get(System.getProperty("java.home")) 278 .resolve("bin"); 279 Path jaotc; 280 if (Platform.isWindows()) { 281 jaotc = bin.resolve("jaotc.exe"); 282 } else { 283 jaotc = bin.resolve("jaotc"); 284 } 285 return "" + Files.exists(jaotc); 286 } 287 288 /** 289 * Check for CDS support. 290 * 291 * @return true if CDS is supported by the VM to be tested. 292 */ 293 protected String vmCDS() { 294 if (WB.isCDSIncludedInVmBuild()) { 295 return "true"; 296 } else { 297 return "false"; 298 } 299 } 300 301 /** 302 * Check for CDS support for custom loaders. 303 * 304 * @return true if CDS provides support for customer loader in the VM to be tested. 305 */ 306 protected String vmCDSForCustomLoaders() { 307 if (vmCDS().equals("true") && Platform.areCustomLoadersSupportedForCDS()) { 308 return "true"; 309 } else { 310 return "false"; 311 } 312 } 313 314 /** 315 * Check for CDS support for archived Java heap regions. 316 * 317 * @return true if CDS provides support for archive Java heap regions in the VM to be tested. 318 */ 319 protected String vmCDSForArchivedJavaHeap() { 320 if (vmCDS().equals("true") && WB.isJavaHeapArchiveSupported()) { 321 return "true"; 322 } else { 323 return "false"; 324 } 325 } 326 327 /** 328 * Check if Graal is used as JIT compiler. 329 * 330 * @return true if Graal is used as JIT compiler. 331 */ 332 protected String isGraalEnabled() { 333 // Graal is enabled if following conditions are true: 334 // - we are not in Interpreter mode 335 // - UseJVMCICompiler flag is true 336 // - jvmci.Compiler variable is equal to 'graal' 337 // - TieredCompilation is not used or TieredStopAtLevel is greater than 3 338 339 Boolean useCompiler = WB.getBooleanVMFlag("UseCompiler"); 340 if (useCompiler == null || !useCompiler) 341 return "false"; 342 343 Boolean useJvmciComp = WB.getBooleanVMFlag("UseJVMCICompiler"); 344 if (useJvmciComp == null || !useJvmciComp) 345 return "false"; 346 347 // This check might be redundant but let's keep it for now. 348 String jvmciCompiler = System.getProperty("jvmci.Compiler"); 349 if (jvmciCompiler == null || !jvmciCompiler.equals("graal")) { 350 return "false"; 351 } 352 353 Boolean tieredCompilation = WB.getBooleanVMFlag("TieredCompilation"); 354 Long compLevel = WB.getIntxVMFlag("TieredStopAtLevel"); 355 // if TieredCompilation is enabled and compilation level is <= 3 then no Graal is used 356 if (tieredCompilation != null && tieredCompilation && compLevel != null && compLevel <= 3) 357 return "false"; 358 359 return "true"; 360 } 361 362 363 /** 364 * A simple check for docker support 365 * 366 * @return true if docker is supported in a given environment 367 */ 368 protected String dockerSupport() { 369 boolean isSupported = false; 370 if (Platform.isLinux()) { 371 // currently docker testing is only supported for Linux, 372 // on certain platforms 373 374 String arch = System.getProperty("os.arch"); 375 376 if (Platform.isX64()) { 377 isSupported = true; 378 } 379 else if (Platform.isAArch64()) { 380 isSupported = true; 381 } 382 else if (Platform.isS390x()) { 383 isSupported = true; 384 } 385 else if (arch.equals("ppc64le")) { 386 isSupported = true; 387 } 388 } 389 390 if (isSupported) { 391 try { 392 isSupported = checkDockerSupport(); 393 } catch (Exception e) { 394 isSupported = false; 395 } 396 } 397 398 return (isSupported) ? "true" : "false"; 399 } 400 401 private boolean checkDockerSupport() throws IOException, InterruptedException { 402 ProcessBuilder pb = new ProcessBuilder("docker", "ps"); 403 Process p = pb.start(); 404 p.waitFor(10, TimeUnit.SECONDS); 405 406 return (p.exitValue() == 0); 407 } 408 409 410 411 /** 412 * Dumps the map to the file if the file name is given as the property. 413 * This functionality could be helpful to know context in the real 414 * execution. 415 * 416 * @param map 417 */ 418 protected static void dump(Map<String, String> map) { 419 String dumpFileName = System.getProperty("vmprops.dump"); 420 if (dumpFileName == null) { 421 return; 422 } 423 List<String> lines = new ArrayList<>(); 424 map.forEach((k, v) -> lines.add(k + ":" + v)); 425 try { 426 Files.write(Paths.get(dumpFileName), lines, StandardOpenOption.APPEND); 427 } catch (IOException e) { 428 throw new RuntimeException("Failed to dump properties into '" 429 + dumpFileName + "'", e); 430 } 431 } 432 433 /** 434 * This method is for the testing purpose only. 435 * @param args 436 */ 437 public static void main(String args[]) { 438 Map<String, String> map = new VMProps().call(); 439 map.forEach((k, v) -> System.out.println(k + ": '" + v + "'")); 440 } 441 }