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