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