1 /* 2 * Copyright (c) 2014, 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 java.util.EnumMap; 28 import java.util.LinkedList; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 34 /** 35 * Wrapper for +UsePreciseRTMLockingStatistics output. 36 * 37 * Example of locking statistics: 38 * 39 * java/lang/ClassLoader.loadClass@7 40 * # rtm locks total (estimated): 0 41 * # rtm lock aborts : 13 42 * # rtm lock aborts 0: 12 43 * # rtm lock aborts 1: 0 44 * # rtm lock aborts 2: 0 45 * # rtm lock aborts 3: 0 46 * # rtm lock aborts 4: 0 47 * # rtm lock aborts 5: 0 48 */ 49 public class RTMLockingStatistics { 50 /** 51 * Pattern for aborts per abort type entries. 52 */ 53 private static final Pattern ABORT_PATTERN; 54 55 /** 56 * Pattern for whole statistics. 57 */ 58 private static final Pattern RTM_LOCKING_STATISTICS_PATTERN; 59 60 static { 61 String abortRe 62 = "# rtm lock aborts\\s+(?<type>[0-9]+):\\s(?<count>[0-9]+)"; 63 64 ABORT_PATTERN = Pattern.compile(abortRe); 65 RTM_LOCKING_STATISTICS_PATTERN = Pattern.compile( 66 "(?<className>[^.\n]+)\\." + 67 "(?<methodName>[^@\n]+)@(?<bci>[0-9]+)\n" + 68 "# rtm locks total \\(estimated\\):\\s*" + 69 "(?<totalLocks>[0-9]+)\n" + 70 "# rtm lock aborts\\s+:\\s*(?<totalAborts>[0-9]+)\n" + 71 "(?<abortStats>(" + abortRe + "\n)+)"); 72 } 73 74 private final long totalLocks; 75 private final long totalAborts; 76 private final String className; 77 private final String methodName; 78 private final int bci; 79 private final Map<AbortType, Long> aborts = new EnumMap<>(AbortType.class); 80 81 /** 82 * Constructs RTMLockingStatistics from matcher captured statistics entry. 83 * @param matcher Matcher captured statistics entry. 84 */ 85 private RTMLockingStatistics(Matcher matcher) { 86 className = matcher.group("className"); 87 methodName = matcher.group("methodName"); 88 bci = Integer.valueOf(matcher.group("bci")); 89 totalLocks = Long.valueOf(matcher.group("totalLocks")); 90 totalAborts = Long.valueOf(matcher.group("totalAborts")); 91 92 Matcher abortMatcher = ABORT_PATTERN.matcher(matcher. 93 group("abortStats")); 94 95 while (abortMatcher.find()) { 96 int type = Integer.valueOf(abortMatcher.group("type")); 97 long count = Long.valueOf(abortMatcher.group("count")); 98 setAborts(AbortType.lookup(type), count); 99 } 100 } 101 102 103 /** 104 * Parses string and return all founded RTM locking statistics entries. 105 * 106 * @param str the string to be parsed. 107 * @return list with all founded RTM locking statistics entries or 108 * empty list if nothing was found. 109 */ 110 public static List<RTMLockingStatistics> fromString(String str) { 111 List<RTMLockingStatistics> statistics = new LinkedList<>(); 112 Matcher matcher = RTM_LOCKING_STATISTICS_PATTERN.matcher(str); 113 114 while (matcher.find()) { 115 RTMLockingStatistics lock = new RTMLockingStatistics(matcher); 116 statistics.add(lock); 117 } 118 119 return statistics; 120 } 121 122 /** 123 * Parses string and return all founded RTM locking statistics entries 124 * for locks in method {@code methodName}. 125 * 126 * @param methodName a name of the method for locks from which statistics 127 * should be gathered. 128 * @param str the string to be parsed. 129 * @return list with all founded RTM locking statistics entries or 130 * empty list if nothing was found. 131 */ 132 public static List<RTMLockingStatistics> fromString(String methodName, 133 String str) { 134 String formattedMethodName = formatMethodName(methodName); 135 136 List<RTMLockingStatistics> statisticsForMethod = new LinkedList<>(); 137 for (RTMLockingStatistics statistics : fromString(str)) { 138 if (statistics.getLockName().startsWith(formattedMethodName)) { 139 statisticsForMethod.add(statistics); 140 } 141 } 142 return statisticsForMethod; 143 } 144 145 /** 146 * Formats method's name so it will have the same format as 147 * in rtm locking statistics. 148 * 149 * <pre> 150 * Example: 151 * com/example/Klass::method => com/example/Klass.method 152 * com/example/Klass.method => com/example/Klass.method 153 * com.example.Klass::method => com/example/Klass.method 154 * com.example.Klass.method => com/example/Klass.method 155 * </pre> 156 * 157 * @param methodName method's name that should be formatted. 158 * @return formatted method's name. 159 */ 160 private static String formatMethodName(String methodName) { 161 String m[]; 162 if (methodName.contains("::")) { 163 m = methodName.split("::"); 164 } else { 165 int splitAt = methodName.lastIndexOf('.'); 166 m = new String[2]; 167 m[0] = methodName.substring(0, splitAt); 168 m[1] = methodName.substring(splitAt + 1); 169 } 170 return String.format("%s.%s", m[0].replaceAll("\\.", "/"), m[1]); 171 } 172 173 /** 174 * Returns name of lock for which this statistics was collected. 175 * Lock name has following format: 176 * <class name>.<method name>@<bci> 177 * 178 * @return name of lock. 179 */ 180 public String getLockName() { 181 return String.format("%s.%s@%d", className, methodName, bci); 182 } 183 184 /** 185 * Returns aborts count for specified abort type. 186 * 187 * @param type an abort type. 188 * @return count of aborts. 189 */ 190 public long getAborts(AbortType type) { 191 return aborts.getOrDefault(type, 0L); 192 } 193 194 /** 195 * Sets aborts count for specified abort type. 196 * 197 * @param type an abort type. 198 * @param count count of aborts. 199 */ 200 public void setAborts(AbortType type, long count) { 201 aborts.put(type, count); 202 } 203 204 public long getTotalLocks() { 205 return totalLocks; 206 } 207 208 public long getTotalAborts() { 209 return totalAborts; 210 } 211 212 @Override 213 public String toString() { 214 StringBuilder builder = new StringBuilder(); 215 builder.append(getLockName()).append('\n'); 216 builder.append(String.format("# rtm locks total (estimated): %d\n", 217 getTotalLocks())); 218 builder.append(String.format("# rtm lock aborts: %d\n", 219 getTotalLocks())); 220 221 for (AbortType type : AbortType.values()) { 222 builder.append(String.format("# rtm lock aborts %s %d\n", 223 type.toString(), getAborts(type))); 224 } 225 return builder.toString(); 226 } 227 }