/* * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package compiler.testlibrary.rtm; import java.util.EnumMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Wrapper for +UsePreciseRTMLockingStatistics output. * * Example of locking statistics: * * java/lang/ClassLoader.loadClass@7 * # rtm locks total (estimated): 0 * # rtm lock aborts : 13 * # rtm lock aborts 0: 12 * # rtm lock aborts 1: 0 * # rtm lock aborts 2: 0 * # rtm lock aborts 3: 0 * # rtm lock aborts 4: 0 * # rtm lock aborts 5: 0 */ public class RTMLockingStatistics { /** * Pattern for aborts per abort type entries. */ private static final Pattern ABORT_PATTERN; /** * Pattern for whole statistics. */ private static final Pattern RTM_LOCKING_STATISTICS_PATTERN; static { String abortRe = "# rtm lock aborts\\s+(?<type>[0-9]+):\\s(?<count>[0-9]+)"; ABORT_PATTERN = Pattern.compile(abortRe); RTM_LOCKING_STATISTICS_PATTERN = Pattern.compile( "(?<className>[^.\n]+)\\." + "(?<methodName>[^@\n]+)@(?<bci>[0-9]+)\n" + "# rtm locks total \\(estimated\\):\\s*" + "(?<totalLocks>[0-9]+)\n" + "# rtm lock aborts\\s+:\\s*(?<totalAborts>[0-9]+)\n" + "(?<abortStats>(" + abortRe + "\n)+)"); } private final long totalLocks; private final long totalAborts; private final String className; private final String methodName; private final int bci; private final Map<AbortType, Long> aborts = new EnumMap<>(AbortType.class); /** * Constructs RTMLockingStatistics from matcher captured statistics entry. * @param matcher Matcher captured statistics entry. */ private RTMLockingStatistics(Matcher matcher) { className = matcher.group("className"); methodName = matcher.group("methodName"); bci = Integer.valueOf(matcher.group("bci")); totalLocks = Long.valueOf(matcher.group("totalLocks")); totalAborts = Long.valueOf(matcher.group("totalAborts")); Matcher abortMatcher = ABORT_PATTERN.matcher(matcher. group("abortStats")); while (abortMatcher.find()) { int type = Integer.valueOf(abortMatcher.group("type")); long count = Long.valueOf(abortMatcher.group("count")); setAborts(AbortType.lookup(type), count); } } /** * Parses string and return all founded RTM locking statistics entries. * * @param str the string to be parsed. * @return list with all founded RTM locking statistics entries or * empty list if nothing was found. */ public static List<RTMLockingStatistics> fromString(String str) { List<RTMLockingStatistics> statistics = new LinkedList<>(); Matcher matcher = RTM_LOCKING_STATISTICS_PATTERN.matcher(str); while (matcher.find()) { RTMLockingStatistics lock = new RTMLockingStatistics(matcher); statistics.add(lock); } return statistics; } /** * Parses string and return all founded RTM locking statistics entries * for locks in method {@code methodName}. * * @param methodName a name of the method for locks from which statistics * should be gathered. * @param str the string to be parsed. * @return list with all founded RTM locking statistics entries or * empty list if nothing was found. */ public static List<RTMLockingStatistics> fromString(String methodName, String str) { String formattedMethodName = formatMethodName(methodName); List<RTMLockingStatistics> statisticsForMethod = new LinkedList<>(); for (RTMLockingStatistics statistics : fromString(str)) { if (statistics.getLockName().startsWith(formattedMethodName)) { statisticsForMethod.add(statistics); } } return statisticsForMethod; } /** * Formats method's name so it will have the same format as * in rtm locking statistics. * * <pre> * Example: * com/example/Klass::method => com/example/Klass.method * com/example/Klass.method => com/example/Klass.method * com.example.Klass::method => com/example/Klass.method * com.example.Klass.method => com/example/Klass.method * </pre> * * @param methodName method's name that should be formatted. * @return formatted method's name. */ private static String formatMethodName(String methodName) { String m[]; if (methodName.contains("::")) { m = methodName.split("::"); } else { int splitAt = methodName.lastIndexOf('.'); m = new String[2]; m[0] = methodName.substring(0, splitAt); m[1] = methodName.substring(splitAt + 1); } return String.format("%s.%s", m[0].replaceAll("\\.", "/"), m[1]); } /** * Returns name of lock for which this statistics was collected. * Lock name has following format: * <class name>.<method name>@<bci> * * @return name of lock. */ public String getLockName() { return String.format("%s.%s@%d", className, methodName, bci); } /** * Returns aborts count for specified abort type. * * @param type an abort type. * @return count of aborts. */ public long getAborts(AbortType type) { return aborts.getOrDefault(type, 0L); } /** * Sets aborts count for specified abort type. * * @param type an abort type. * @param count count of aborts. */ public void setAborts(AbortType type, long count) { aborts.put(type, count); } public long getTotalLocks() { return totalLocks; } public long getTotalAborts() { return totalAborts; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(getLockName()).append('\n'); builder.append(String.format("# rtm locks total (estimated): %d\n", getTotalLocks())); builder.append(String.format("# rtm lock aborts: %d\n", getTotalLocks())); for (AbortType type : AbortType.values()) { builder.append(String.format("# rtm lock aborts %s %d\n", type.toString(), getAborts(type))); } return builder.toString(); } }