1 /* 2 * Copyright (c) 2016, 2019, 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.BufferedInputStream; 26 import java.io.FileInputStream; 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.nio.file.Files; 30 import java.nio.file.Path; 31 import java.nio.file.Paths; 32 import java.nio.file.StandardOpenOption; 33 import java.util.ArrayList; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.Properties; 38 import java.util.concurrent.Callable; 39 import java.util.concurrent.TimeUnit; 40 import java.util.regex.Matcher; 41 import java.util.regex.Pattern; 42 43 import sun.hotspot.code.Compiler; 44 import sun.hotspot.cpuinfo.CPUInfo; 45 import sun.hotspot.gc.GC; 46 import sun.hotspot.WhiteBox; 47 import jdk.test.lib.Platform; 48 49 /** 50 * The Class to be invoked by jtreg prior Test Suite execution to 51 * collect information about VM. 52 * Do not use any API's that may not be available in all target VMs. 53 * Properties set by this Class will be available in the @requires expressions. 54 */ 55 public class VMProps implements Callable<Map<String, String>> { 56 57 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 58 59 /** 60 * Collects information about VM properties. 61 * This method will be invoked by jtreg. 62 * 63 * @return Map of property-value pairs. 64 */ 65 @Override 66 public Map<String, String> call() { 67 Map<String, String> map = new HashMap<>(); 68 map.put("vm.flavor", vmFlavor()); 69 map.put("vm.compMode", vmCompMode()); 70 map.put("vm.bits", vmBits()); 71 map.put("vm.flightRecorder", vmFlightRecorder()); 72 map.put("vm.simpleArch", vmArch()); 73 map.put("vm.debug", vmDebug()); 74 map.put("vm.jvmci", vmJvmci()); 75 map.put("vm.emulatedClient", vmEmulatedClient()); 76 // vm.hasSA is "true" if the VM contains the serviceability agent 77 // and jhsdb. 78 map.put("vm.hasSA", vmHasSA()); 79 // vm.hasSAandCanAttach is "true" if the VM contains the serviceability agent 80 // and jhsdb and it can attach to the VM. 81 map.put("vm.hasSAandCanAttach", vmHasSAandCanAttach()); 82 // vm.hasJFR is "true" if JFR is included in the build of the VM and 83 // so tests can be executed. 84 map.put("vm.hasJFR", vmHasJFR()); 85 map.put("vm.cpu.features", cpuFeatures()); 86 map.put("vm.rtm.cpu", vmRTMCPU()); 87 map.put("vm.rtm.compiler", vmRTMCompiler()); 88 map.put("vm.aot", vmAOT()); 89 map.put("vm.aot.enabled", vmAotEnabled()); 90 // vm.cds is true if the VM is compiled with cds support. 91 map.put("vm.cds", vmCDS()); 92 map.put("vm.cds.custom.loaders", vmCDSForCustomLoaders()); 93 map.put("vm.cds.archived.java.heap", vmCDSForArchivedJavaHeap()); 94 // vm.graal.enabled is true if Graal is used as JIT 95 map.put("vm.graal.enabled", isGraalEnabled()); 96 map.put("vm.compiler1.enabled", isCompiler1Enabled()); 97 map.put("vm.compiler2.enabled", isCompiler2Enabled()); 98 map.put("docker.support", dockerSupport()); 99 map.put("release.implementor", implementor()); 100 map.put("test.vm.gc.nvdimm", isNvdimmTestEnabled()); 101 vmGC(map); // vm.gc.X = true/false 102 vmOptFinalFlags(map); 103 104 VMProps.dump(map); 105 return map; 106 } 107 108 /** 109 * Prints a stack trace before returning null. 110 * Used by the various helper functions which parse information from 111 * VM properties in the case where they don't find an expected property 112 * or a propoerty doesn't conform to an expected format. 113 * 114 * @return null 115 */ 116 private String nullWithException(String message) { 117 new Exception(message).printStackTrace(); 118 return null; 119 } 120 121 /** 122 * @return vm.simpleArch value of "os.simpleArch" property of tested JDK. 123 */ 124 protected String vmArch() { 125 String arch = System.getProperty("os.arch"); 126 if (arch.equals("x86_64") || arch.equals("amd64")) { 127 return "x64"; 128 } 129 else if (arch.contains("86")) { 130 return "x86"; 131 } else { 132 return arch; 133 } 134 } 135 136 /** 137 * @return VM type value extracted from the "java.vm.name" property. 138 */ 139 protected String vmFlavor() { 140 // E.g. "Java HotSpot(TM) 64-Bit Server VM" 141 String vmName = System.getProperty("java.vm.name"); 142 if (vmName == null) { 143 return nullWithException("Can't get 'java.vm.name' property"); 144 } 145 146 Pattern startP = Pattern.compile(".* (\\S+) VM"); 147 Matcher m = startP.matcher(vmName); 148 if (m.matches()) { 149 return m.group(1).toLowerCase(); 150 } 151 return nullWithException("Can't get VM flavor from 'java.vm.name'"); 152 } 153 154 /** 155 * @return VM compilation mode extracted from the "java.vm.info" property. 156 */ 157 protected String vmCompMode() { 158 // E.g. "mixed mode" 159 String vmInfo = System.getProperty("java.vm.info"); 160 if (vmInfo == null) { 161 return nullWithException("Can't get 'java.vm.info' property"); 162 } 163 if (vmInfo.toLowerCase().indexOf("mixed mode") != -1) { 164 return "Xmixed"; 165 } else if (vmInfo.toLowerCase().indexOf("compiled mode") != -1) { 166 return "Xcomp"; 167 } else if (vmInfo.toLowerCase().indexOf("interpreted mode") != -1) { 168 return "Xint"; 169 } else { 170 return nullWithException("Can't get compilation mode from 'java.vm.info'"); 171 } 172 } 173 174 /** 175 * @return VM bitness, the value of the "sun.arch.data.model" property. 176 */ 177 protected String vmBits() { 178 String dataModel = System.getProperty("sun.arch.data.model"); 179 if (dataModel != null) { 180 return dataModel; 181 } else { 182 return nullWithException("Can't get 'sun.arch.data.model' property"); 183 } 184 } 185 186 /** 187 * @return "true" if Flight Recorder is enabled, "false" if is disabled. 188 */ 189 protected String vmFlightRecorder() { 190 Boolean isFlightRecorder = WB.getBooleanVMFlag("FlightRecorder"); 191 String startFROptions = WB.getStringVMFlag("StartFlightRecording"); 192 if (isFlightRecorder != null && isFlightRecorder) { 193 return "true"; 194 } 195 if (startFROptions != null && !startFROptions.isEmpty()) { 196 return "true"; 197 } 198 return "false"; 199 } 200 201 /** 202 * @return debug level value extracted from the "jdk.debug" property. 203 */ 204 protected String vmDebug() { 205 String debug = System.getProperty("jdk.debug"); 206 if (debug != null) { 207 return "" + debug.contains("debug"); 208 } else { 209 return nullWithException("Can't get 'jdk.debug' property"); 210 } 211 } 212 213 /** 214 * @return true if VM supports JVMCI and false otherwise 215 */ 216 protected String vmJvmci() { 217 // builds with jvmci have this flag 218 return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); 219 } 220 221 /** 222 * @return true if VM runs in emulated-client mode and false otherwise. 223 */ 224 protected String vmEmulatedClient() { 225 String vmInfo = System.getProperty("java.vm.info"); 226 if (vmInfo == null) { 227 return "false"; 228 } 229 return "" + vmInfo.contains(" emulated-client"); 230 } 231 232 /** 233 * @return supported CPU features 234 */ 235 protected String cpuFeatures() { 236 return CPUInfo.getFeatures().toString(); 237 } 238 239 /** 240 * For all existing GC sets vm.gc.X property. 241 * Example vm.gc.G1=true means: 242 * VM supports G1 243 * User either set G1 explicitely (-XX:+UseG1GC) or did not set any GC 244 * @param map - property-value pairs 245 */ 246 protected void vmGC(Map<String, String> map) { 247 for (GC gc: GC.values()) { 248 boolean isAcceptable = gc.isSupported() && (gc.isSelected() || GC.isSelectedErgonomically()); 249 map.put("vm.gc." + gc.name(), "" + isAcceptable); 250 } 251 } 252 253 /** 254 * Selected final flag. 255 * @param map - property-value pairs 256 * @param flagName - flag name 257 */ 258 private void vmOptFinalFlag(Map<String, String> map, String flagName) { 259 String value = String.valueOf(WB.getBooleanVMFlag(flagName)); 260 map.put("vm.opt.final." + flagName, value); 261 } 262 263 /** 264 * Selected sets of final flags. 265 * @param map - property-value pairs 266 */ 267 protected void vmOptFinalFlags(Map<String, String> map) { 268 vmOptFinalFlag(map, "ClassUnloading"); 269 vmOptFinalFlag(map, "UseCompressedOops"); 270 vmOptFinalFlag(map, "EnableJVMCI"); 271 vmOptFinalFlag(map, "EliminateAllocations"); 272 } 273 274 /** 275 * @return "true" if VM has a serviceability agent. 276 */ 277 protected String vmHasSA() { 278 return "" + Platform.hasSA(); 279 } 280 281 /** 282 * @return "true" if VM has a serviceability agent and it can 283 * attach to the VM. 284 */ 285 protected String vmHasSAandCanAttach() { 286 try { 287 return "" + Platform.shouldSAAttach(); 288 } catch (IOException e) { 289 System.out.println("Checking whether SA can attach to the VM failed."); 290 e.printStackTrace(); 291 // Run the tests anyways. 292 return "true"; 293 } 294 } 295 296 /** 297 * @return "true" if the VM is compiled with Java Flight Recorder (JFR) 298 * support. 299 */ 300 protected String vmHasJFR() { 301 return "" + WB.isJFRIncludedInVmBuild(); 302 } 303 304 /** 305 * @return true if compiler in use supports RTM and false otherwise. 306 */ 307 protected String vmRTMCompiler() { 308 boolean isRTMCompiler = false; 309 310 if (Compiler.isC2Enabled() && 311 (Platform.isX86() || Platform.isX64() || Platform.isPPC())) { 312 isRTMCompiler = true; 313 } 314 return "" + isRTMCompiler; 315 } 316 317 /** 318 * @return true if VM runs RTM supported CPU and false otherwise. 319 */ 320 protected String vmRTMCPU() { 321 return "" + CPUInfo.hasFeature("rtm"); 322 } 323 324 /** 325 * @return true if VM supports AOT and false otherwise 326 */ 327 protected String vmAOT() { 328 // builds with aot have jaotc in <JDK>/bin 329 Path bin = Paths.get(System.getProperty("java.home")) 330 .resolve("bin"); 331 Path jaotc; 332 if (Platform.isWindows()) { 333 jaotc = bin.resolve("jaotc.exe"); 334 } else { 335 jaotc = bin.resolve("jaotc"); 336 } 337 return "" + Files.exists(jaotc); 338 } 339 340 /* 341 * @return true if there is at least one loaded AOT'ed library. 342 */ 343 protected String vmAotEnabled() { 344 return "" + (WB.aotLibrariesCount() > 0); 345 } 346 347 /** 348 * Check for CDS support. 349 * 350 * @return true if CDS is supported by the VM to be tested. 351 */ 352 protected String vmCDS() { 353 if (WB.isCDSIncludedInVmBuild()) { 354 return "true"; 355 } else { 356 return "false"; 357 } 358 } 359 360 /** 361 * Check for CDS support for custom loaders. 362 * 363 * @return true if CDS provides support for customer loader in the VM to be tested. 364 */ 365 protected String vmCDSForCustomLoaders() { 366 if (vmCDS().equals("true") && Platform.areCustomLoadersSupportedForCDS()) { 367 return "true"; 368 } else { 369 return "false"; 370 } 371 } 372 373 /** 374 * Check for CDS support for archived Java heap regions. 375 * 376 * @return true if CDS provides support for archive Java heap regions in the VM to be tested. 377 */ 378 protected String vmCDSForArchivedJavaHeap() { 379 if (vmCDS().equals("true") && WB.isJavaHeapArchiveSupported()) { 380 return "true"; 381 } else { 382 return "false"; 383 } 384 } 385 386 /** 387 * Check if Graal is used as JIT compiler. 388 * 389 * @return true if Graal is used as JIT compiler. 390 */ 391 protected String isGraalEnabled() { 392 return Compiler.isGraalEnabled() ? "true" : "false"; 393 } 394 395 /** 396 * Check if Compiler1 is present. 397 * 398 * @return true if Compiler1 is used as JIT compiler, either alone or as part of the tiered system. 399 */ 400 protected String isCompiler1Enabled() { 401 return Compiler.isC1Enabled() ? "true" : "false"; 402 } 403 404 /** 405 * Check if Compiler2 is present. 406 * 407 * @return true if Compiler2 is used as JIT compiler, either alone or as part of the tiered system. 408 */ 409 protected String isCompiler2Enabled() { 410 return Compiler.isC2Enabled() ? "true" : "false"; 411 } 412 413 /** 414 * A simple check for docker support 415 * 416 * @return true if docker is supported in a given environment 417 */ 418 protected String dockerSupport() { 419 boolean isSupported = false; 420 if (Platform.isLinux()) { 421 // currently docker testing is only supported for Linux, 422 // on certain platforms 423 424 String arch = System.getProperty("os.arch"); 425 426 if (Platform.isX64()) { 427 isSupported = true; 428 } 429 else if (Platform.isAArch64()) { 430 isSupported = true; 431 } 432 else if (Platform.isS390x()) { 433 isSupported = true; 434 } 435 else if (arch.equals("ppc64le")) { 436 isSupported = true; 437 } 438 } 439 440 if (isSupported) { 441 try { 442 isSupported = checkDockerSupport(); 443 } catch (Exception e) { 444 isSupported = false; 445 } 446 } 447 448 return (isSupported) ? "true" : "false"; 449 } 450 451 private boolean checkDockerSupport() throws IOException, InterruptedException { 452 ProcessBuilder pb = new ProcessBuilder("docker", "ps"); 453 Process p = pb.start(); 454 p.waitFor(10, TimeUnit.SECONDS); 455 456 return (p.exitValue() == 0); 457 } 458 459 460 private String implementor() { 461 try (InputStream in = new BufferedInputStream(new FileInputStream( 462 System.getProperty("java.home") + "/release"))) { 463 Properties properties = new Properties(); 464 properties.load(in); 465 String implementorProperty = properties.getProperty("IMPLEMENTOR"); 466 return (implementorProperty == null) ? "null" : implementorProperty.replace("\"", ""); 467 } catch (IOException e) { 468 e.printStackTrace(); 469 } 470 return null; 471 } 472 473 private String isNvdimmTestEnabled() { 474 String isEnbled = System.getenv("TEST_VM_GC_NVDIMM"); 475 if (isEnbled != null && isEnbled.toLowerCase().equals("true")) { 476 return "true"; 477 } 478 return "false"; 479 } 480 481 482 483 /** 484 * Dumps the map to the file if the file name is given as the property. 485 * This functionality could be helpful to know context in the real 486 * execution. 487 * 488 * @param map 489 */ 490 protected static void dump(Map<String, String> map) { 491 String dumpFileName = System.getProperty("vmprops.dump"); 492 if (dumpFileName == null) { 493 return; 494 } 495 List<String> lines = new ArrayList<>(); 496 map.forEach((k, v) -> lines.add(k + ":" + v)); 497 try { 498 Files.write(Paths.get(dumpFileName), lines, StandardOpenOption.APPEND); 499 } catch (IOException e) { 500 throw new RuntimeException("Failed to dump properties into '" 501 + dumpFileName + "'", e); 502 } 503 } 504 505 /** 506 * This method is for the testing purpose only. 507 * @param args 508 */ 509 public static void main(String args[]) { 510 Map<String, String> map = new VMProps().call(); 511 map.forEach((k, v) -> System.out.println(k + ": '" + v + "'")); 512 } 513 }