1 /* 2 * Copyright (c) 2014, 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 */ 24 25 package compiler.testlibrary.rtm; 26 27 import jdk.test.lib.process.OutputAnalyzer; 28 import jdk.test.lib.process.ProcessTools; 29 import jdk.test.lib.Utils; 30 import jdk.test.lib.cli.CommandLineOptionTest; 31 32 import java.io.IOException; 33 import java.nio.file.Files; 34 import java.nio.file.Paths; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.LinkedList; 38 import java.util.List; 39 import java.util.regex.Matcher; 40 import java.util.regex.Pattern; 41 42 /** 43 * Auxiliary methods used for RTM testing. 44 */ 45 public class RTMTestBase { 46 private static final String RTM_STATE_CHANGE_REASON = "rtm_state_change"; 47 /** 48 * We don't parse compilation log as XML-document and use regular 49 * expressions instead, because in some cases it could be 50 * malformed. 51 */ 52 private static final String FIRED_UNCOMMON_TRAP_PATTERN_TEMPLATE 53 = "<uncommon_trap thread='[0-9]+' reason='%s'"; 54 private static final String INSTALLED_UNCOMMON_TRAP_PATTERN_TEMPLATE 55 = "<uncommon_trap bci='[0-9]+' reason='%s'"; 56 57 /** 58 * Executes RTM test in a new JVM started with {@code options} cli options. 59 * 60 * @param test test case to execute. 61 * @param options additional options for VM 62 * @throws Exception when something went wrong. 63 */ 64 public static OutputAnalyzer executeRTMTest(CompilableTest test, 65 String... options) throws Exception { 66 ProcessBuilder processBuilder 67 = ProcessTools.createJavaProcessBuilder( 68 RTMTestBase.prepareTestOptions(test, options)); 69 OutputAnalyzer outputAnalyzer 70 = new OutputAnalyzer(processBuilder.start()); 71 System.out.println(outputAnalyzer.getOutput()); 72 return outputAnalyzer; 73 } 74 75 /** 76 * Executes test case and save compilation log to {@code logFileName}. 77 * 78 * @param logFileName a name of compilation log file 79 * @param test a test case to execute case to execute 80 * @param options additional options to VM 81 * @return OutputAnalyzer for started test case 82 * @throws Exception when something went wrong 83 */ 84 public static OutputAnalyzer executeRTMTest(String logFileName, 85 CompilableTest test, String... options) throws Exception { 86 ProcessBuilder processBuilder 87 = ProcessTools.createJavaProcessBuilder( 88 RTMTestBase.prepareTestOptions(logFileName, test, options)); 89 OutputAnalyzer outputAnalyzer 90 = new OutputAnalyzer(processBuilder.start()); 91 92 System.out.println(outputAnalyzer.getOutput()); 93 94 return outputAnalyzer; 95 } 96 97 /** 98 * Finds count of uncommon traps with reason {@code reason} installed 99 * during compilation. 100 * 101 * @param compilationLogFile a path to file with LogCompilation output. 102 * @param reason reason of installed uncommon traps. 103 * @return count of installed uncommon traps with reason {@code reason}. 104 * @throws IOException 105 */ 106 public static int installedUncommonTraps(String compilationLogFile, 107 String reason)throws IOException { 108 String pattern = String.format( 109 RTMTestBase.INSTALLED_UNCOMMON_TRAP_PATTERN_TEMPLATE, 110 reason); 111 return RTMTestBase.findTraps(compilationLogFile, pattern); 112 } 113 114 /** 115 * Finds count of uncommon traps with reason <i>rtm_state_change</i> 116 * installed during compilation. 117 * 118 * @param compilationLogFile a path to file with LogCompilation output. 119 * @return count of installed uncommon traps with reason 120 * <i>rtm_state_change</i>. 121 * @throws IOException 122 */ 123 public static int installedRTMStateChangeTraps(String compilationLogFile) 124 throws IOException { 125 return RTMTestBase.installedUncommonTraps(compilationLogFile, 126 RTMTestBase.RTM_STATE_CHANGE_REASON); 127 } 128 129 /** 130 * Finds count of fired uncommon traps with reason {@code reason}. 131 * 132 * @param compilationLogFile a path to file with LogCompilation output. 133 * @param reason a reason of fired uncommon traps. 134 * @return count of fired uncommon traps with reason {@code reason}. 135 * @throws IOException 136 */ 137 public static int firedUncommonTraps(String compilationLogFile, 138 String reason) throws IOException { 139 String pattern = String.format( 140 RTMTestBase.FIRED_UNCOMMON_TRAP_PATTERN_TEMPLATE, 141 reason); 142 return RTMTestBase.findTraps(compilationLogFile, pattern); 143 } 144 145 /** 146 * Finds count of fired uncommon traps with reason <i>rtm_state_change</i>. 147 * 148 * @param compilationLogFile a path to file with LogCompilation output. 149 * @return count of fired uncommon traps with reason 150 * <i>rtm_state_change</i>. 151 * @throws IOException 152 */ 153 public static int firedRTMStateChangeTraps(String compilationLogFile) 154 throws IOException { 155 return RTMTestBase.firedUncommonTraps(compilationLogFile, 156 RTMTestBase.RTM_STATE_CHANGE_REASON); 157 } 158 159 /** 160 * Finds count of uncommon traps that matches regular 161 * expression in {@code re}. 162 * 163 * @param compilationLogFile a path to file with LogCompilation output. 164 * @param re regular expression to match uncommon traps. 165 * @throws IOException 166 */ 167 private static int findTraps(String compilationLogFile, String re) 168 throws IOException { 169 String compilationLog = RTMTestBase.fileAsString(compilationLogFile); 170 Pattern pattern = Pattern.compile(re); 171 Matcher matcher = pattern.matcher(compilationLog); 172 int traps = 0; 173 while (matcher.find()) { 174 traps++; 175 } 176 return traps; 177 } 178 179 /** 180 * Returns file's content as a string. 181 * 182 * @param path a path to file to operate on. 183 * @return string with content of file. 184 * @throws IOException 185 */ 186 private static String fileAsString(String path) throws IOException { 187 byte[] fileAsBytes = Files.readAllBytes(Paths.get(path)); 188 return new String(fileAsBytes); 189 } 190 191 /** 192 * Prepares VM options for test execution. 193 * This method get test java options, filter out all RTM-related options, 194 * adds CompileCommand=compileonly,method_name options for each method 195 * from {@code methodToCompile} and finally appends all {@code vmOpts}. 196 * 197 * @param test test case whose methods that should be compiled. 198 * If {@code null} then no additional <i>compileonly</i> 199 * commands will be added to VM options. 200 * @param vmOpts additional options to pass to VM. 201 * @return Array with VM options. 202 */ 203 private static String[] prepareTestOptions(CompilableTest test, 204 String... vmOpts) { 205 return RTMTestBase.prepareFilteredTestOptions(test, null, vmOpts); 206 } 207 208 /** 209 * Prepares VM options for test execution. 210 * This method get test java options, filter out all RTM-related options 211 * and all options that matches regexps in {@code additionalFilters}, 212 * adds CompileCommand=compileonly,method_name options for each method 213 * from {@code methodToCompile} and finally appends all {@code vmOpts}. 214 * 215 * @param test test case whose methods that should be compiled. 216 * If {@code null} then no additional <i>compileonly</i> 217 * commands will be added to VM options. 218 * @param additionalFilters array with regular expression that will be 219 * used to filter out test java options. 220 * If {@code null} then no additional filters 221 * will be used. 222 * @param vmOpts additional options to pass to VM. 223 * @return array with VM options. 224 */ 225 private static String[] prepareFilteredTestOptions(CompilableTest test, 226 String[] additionalFilters, String... vmOpts) { 227 List<String> finalVMOpts = new LinkedList<>(); 228 String[] filters; 229 230 if (additionalFilters != null) { 231 filters = Arrays.copyOf(additionalFilters, 232 additionalFilters.length + 1); 233 } else { 234 filters = new String[1]; 235 } 236 237 filters[filters.length - 1] = "RTM"; 238 String[] filteredVMOpts = Utils.getFilteredTestJavaOpts(filters); 239 Collections.addAll(finalVMOpts, filteredVMOpts); 240 Collections.addAll(finalVMOpts, "-Xcomp", "-server", 241 "-XX:-TieredCompilation", "-XX:+UseRTMLocking", 242 CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS, 243 CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS, 244 "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI"); 245 246 if (test != null) { 247 for (String method : test.getMethodsToCompileNames()) { 248 finalVMOpts.add("-XX:CompileCommand=compileonly," + method); 249 } 250 } 251 Collections.addAll(finalVMOpts, vmOpts); 252 return finalVMOpts.toArray(new String[finalVMOpts.size()]); 253 } 254 255 /** 256 * Adds additional options for VM required for successful execution of test. 257 * 258 * @param logFileName a name of compilation log file 259 * @param test a test case to execute 260 * @param options additional options to VM 261 * @return an array with VM options 262 */ 263 private static String[] prepareTestOptions(String logFileName, 264 CompilableTest test, String... options) { 265 String[] preparedOptions = RTMTestBase.prepareFilteredTestOptions( 266 test, 267 new String[] { 268 "LogCompilation", 269 "LogFile" 270 }); 271 List<String> updatedOptions = new LinkedList<>(); 272 Collections.addAll(updatedOptions, preparedOptions); 273 Collections.addAll(updatedOptions, 274 "-XX:+LogCompilation", 275 "-XX:LogFile=" + logFileName); 276 Collections.addAll(updatedOptions, options); 277 278 return updatedOptions.toArray(new String[updatedOptions.size()]); 279 } 280 }