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