blob: 4c354bf5a49f576553fe4abbeaa868458b8c4e64 [file] [log] [blame]
/*
* 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 rtm;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* 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 =&gt; com/example/Klass.method
* com/example/Klass.method =&gt; com/example/Klass.method
* com.example.Klass::method =&gt; com/example/Klass.method
* com.example.Klass.method =&gt; 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:
* &lt;class name&gt;.&lt;method name&gt;@&lt;bci&gt;
*
* @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();
}
}