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