1 /*
   2  * Copyright (c) 2016, 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.Paths;
  28 import java.nio.file.StandardOpenOption;
  29 import java.util.ArrayList;
  30 import java.util.HashMap;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.concurrent.Callable;
  34 import java.util.regex.Matcher;
  35 import java.util.regex.Pattern;
  36 
  37 import sun.hotspot.cpuinfo.CPUInfo;
  38 import sun.hotspot.gc.GC;
  39 import sun.hotspot.WhiteBox;
  40 
  41 /**
  42  * The Class to be invoked by jtreg prior Test Suite execution to
  43  * collect information about VM.
  44  * Do not use any API's that may not be available in all target VMs.
  45  * Properties set by this Class will be available in the @requires expressions.
  46  */
  47 public class VMProps implements Callable<Map<String, String>> {
  48 
  49     private static final WhiteBox WB = WhiteBox.getWhiteBox();
  50 
  51     /**
  52      * Collects information about VM properties.
  53      * This method will be invoked by jtreg.
  54      *
  55      * @return Map of property-value pairs.
  56      */
  57     @Override
  58     public Map<String, String> call() {
  59         Map<String, String> map = new HashMap<>();
  60         map.put("vm.flavor", vmFlavor());
  61         map.put("vm.compMode", vmCompMode());
  62         map.put("vm.bits", vmBits());
  63         map.put("vm.flightRecorder", vmFlightRecorder());
  64         map.put("vm.simpleArch", vmArch());
  65         map.put("vm.debug", vmDebug());
  66         map.put("vm.jvmci", vmJvmci());
  67         map.put("vm.emulatedClient", vmEmulatedClient());
  68         map.put("vm.cpu.features", cpuFeatures());
  69         vmGC(map); // vm.gc.X = true/false
  70 
  71         VMProps.dump(map);
  72         return map;
  73     }
  74 
  75     /**
  76      * @return vm.simpleArch value of "os.simpleArch" property of tested JDK.
  77      */
  78     protected String vmArch() {
  79         String arch = System.getProperty("os.arch");
  80         if (arch.equals("x86_64") || arch.equals("amd64")) {
  81             return "x64";
  82         }
  83         else if (arch.contains("86")) {
  84             return "x86";
  85         } else {
  86             return arch;
  87         }
  88     }
  89 
  90 
  91 
  92     /**
  93      * @return VM type value extracted from the "java.vm.name" property.
  94      */
  95     protected String vmFlavor() {
  96         // E.g. "Java HotSpot(TM) 64-Bit Server VM"
  97         String vmName = System.getProperty("java.vm.name");
  98         if (vmName == null) {
  99             return null;
 100         }
 101 
 102         Pattern startP = Pattern.compile(".* (\\S+) VM");
 103         Matcher m = startP.matcher(vmName);
 104         if (m.matches()) {
 105             return m.group(1).toLowerCase();
 106         }
 107         return null;
 108     }
 109 
 110     /**
 111      * @return VM compilation mode extracted from the "java.vm.info" property.
 112      */
 113     protected String vmCompMode() {
 114         // E.g. "mixed mode"
 115         String vmInfo = System.getProperty("java.vm.info");
 116         if (vmInfo == null) {
 117             return null;
 118         }
 119         int k = vmInfo.toLowerCase().indexOf(" mode");
 120         if (k < 0) {
 121             return null;
 122         }
 123         vmInfo = vmInfo.substring(0, k);
 124         switch (vmInfo) {
 125             case "mixed" : return "Xmixed";
 126             case "compiled" : return "Xcomp";
 127             case "interpreted" : return "Xint";
 128             default: return null;
 129         }
 130     }
 131 
 132     /**
 133      * @return VM bitness, the value of the "sun.arch.data.model" property.
 134      */
 135     protected String vmBits() {
 136         return System.getProperty("sun.arch.data.model");
 137     }
 138 
 139     /**
 140      * @return "true" if Flight Recorder is enabled, "false" if is disabled.
 141      */
 142     protected String vmFlightRecorder() {
 143         Boolean isUnlockedCommercialFatures = WB.getBooleanVMFlag("UnlockCommercialFeatures");
 144         Boolean isFlightRecorder = WB.getBooleanVMFlag("FlightRecorder");
 145         String startFROptions = WB.getStringVMFlag("StartFlightRecording");
 146         if (isUnlockedCommercialFatures != null && isUnlockedCommercialFatures) {
 147             if (isFlightRecorder != null && isFlightRecorder) {
 148                 return "true";
 149             }
 150             if (startFROptions != null && !startFROptions.isEmpty()) {
 151                 return "true";
 152             }
 153         }
 154         return "false";
 155     }
 156 
 157     /**
 158      * @return debug level value extracted from the "jdk.debug" property.
 159      */
 160     protected String vmDebug() {
 161         return "" + System.getProperty("jdk.debug").contains("debug");
 162     }
 163 
 164     /**
 165      * @return true if VM supports JVMCI and false otherwise
 166      */
 167     protected String vmJvmci() {
 168         // builds with jvmci have this flag
 169         return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null);
 170     }
 171 
 172     /**
 173      * @return true if VM runs in emulated-client mode and false otherwise.
 174      */
 175     protected String vmEmulatedClient() {
 176         String vmInfo = System.getProperty("java.vm.info");
 177         if (vmInfo == null) {
 178             return "false";
 179         }
 180         return "" + vmInfo.contains(" emulated-client");
 181     }
 182 
 183     /**
 184      * @return supported CPU features
 185      */
 186     protected String cpuFeatures() {
 187         return CPUInfo.getFeatures().toString();
 188     }
 189 
 190     /**
 191      * For all existing GC sets vm.gc.X property.
 192      * Example vm.gc.G1=true means:
 193      *    VM supports G1
 194      *    User either set G1 explicitely (-XX:+UseG1GC) or did not set any GC
 195      * @param map - property-value pairs
 196      */
 197     protected void vmGC(Map<String, String> map){
 198         GC currentGC = GC.current();
 199         boolean isByErgo = GC.currentSetByErgo();
 200         List<GC> supportedGC = GC.allSupported();
 201         for (GC gc: GC.values()) {
 202             boolean isSupported = supportedGC.contains(gc);
 203             boolean isAcceptable = isSupported && (gc == currentGC || isByErgo);
 204             map.put("vm.gc." + gc.name(), "" + isAcceptable);
 205         }
 206     }
 207 
 208     /**
 209      * Dumps the map to the file if the file name is given as the property.
 210      * This functionality could be helpful to know context in the real
 211      * execution.
 212      *
 213      * @param map
 214      */
 215     protected static void dump(Map<String, String> map) {
 216         String dumpFileName = System.getProperty("vmprops.dump");
 217         if (dumpFileName == null) {
 218             return;
 219         }
 220         List<String> lines = new ArrayList<>();
 221         map.forEach((k, v) -> lines.add(k + ":" + v));
 222         try {
 223             Files.write(Paths.get(dumpFileName), lines, StandardOpenOption.APPEND);
 224         } catch (IOException e) {
 225             throw new RuntimeException("Failed to dump properties into '"
 226                     + dumpFileName + "'", e);
 227         }
 228     }
 229 
 230     /**
 231      * This method is for the testing purpose only.
 232      * @param args
 233      */
 234     public static void main(String args[]) {
 235         Map<String, String> map = new VMProps().call();
 236         map.forEach((k, v) -> System.out.println(k + ": '" + v + "'"));
 237     }
 238 }