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