< prev index next >
core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/latency/MethodProfilingRule.java
Print this page
*** 45,56 ****
--- 45,59 ----
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
+ import java.util.regex.Matcher;
+ import java.util.regex.Pattern;
import org.openjdk.jmc.common.IDisplayable;
+ import org.openjdk.jmc.common.IMCFrame;
import org.openjdk.jmc.common.IMCMethod;
import org.openjdk.jmc.common.IMCStackTrace;
import org.openjdk.jmc.common.item.Aggregators;
import org.openjdk.jmc.common.item.Aggregators.CountConsumer;
import org.openjdk.jmc.common.item.GroupingAggregator;
*** 68,77 ****
--- 71,81 ----
import org.openjdk.jmc.common.unit.QuantityConversionException;
import org.openjdk.jmc.common.unit.QuantityRange;
import org.openjdk.jmc.common.unit.UnitLookup;
import org.openjdk.jmc.common.util.FormatToolkit;
import org.openjdk.jmc.common.util.IPreferenceValueProvider;
+ import org.openjdk.jmc.common.util.MCStackTrace;
import org.openjdk.jmc.common.util.Pair;
import org.openjdk.jmc.common.util.TypedPreference;
import org.openjdk.jmc.flightrecorder.JfrAttributes;
import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
*** 83,93 ****
import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit.EventAvailability;
import org.openjdk.jmc.flightrecorder.rules.util.SlidingWindowToolkit;
import org.openjdk.jmc.flightrecorder.rules.util.SlidingWindowToolkit.IUnorderedWindowVisitor;
- import org.openjdk.jmc.flightrecorder.stacktrace.StacktraceModel;
/**
* Rule that calculates the top method balance in a sliding window throughout the recording with a
* relevance calculated by the ratio of samples to maximum samples for that period.
*/
--- 87,96 ----
*** 166,176 ****
public static final TypedPreference<IQuantity> WINDOW_SIZE = new TypedPreference<>(
"method.profiling.evaluation.window.size", //$NON-NLS-1$
Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE),
Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE_DESC), UnitLookup.TIMESPAN,
UnitLookup.SECOND.quantity(30));
! private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays.<TypedPreference<?>> asList(WINDOW_SIZE);
/**
* Private Callable implementation specifically used to avoid storing the FutureTask as a field.
*/
private class MethodProfilingCallable implements Callable<Result> {
--- 169,184 ----
public static final TypedPreference<IQuantity> WINDOW_SIZE = new TypedPreference<>(
"method.profiling.evaluation.window.size", //$NON-NLS-1$
Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE),
Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE_DESC), UnitLookup.TIMESPAN,
UnitLookup.SECOND.quantity(30));
! public static final TypedPreference<String> EXCLUDED_PACKAGE_REGEXP = new TypedPreference<>(
! "method.profiling.evaluation.excluded.package", //$NON-NLS-1$
! Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES),
! Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES_DESC),
! UnitLookup.PLAIN_TEXT.getPersister(), "");
! private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays.<TypedPreference<?>> asList(WINDOW_SIZE, EXCLUDED_PACKAGE_REGEXP);
/**
* Private Callable implementation specifically used to avoid storing the FutureTask as a field.
*/
private class MethodProfilingCallable implements Callable<Result> {
*** 215,228 ****
JdkTypeIDs.EXECUTION_SAMPLE);
populateSettingsMap(items.apply(settingsFilter), settings);
IQuantity windowSize = valueProvider.getPreferenceValue(WINDOW_SIZE);
IQuantity slideSize = UnitLookup.SECOND.quantity(windowSize.ratioTo(UnitLookup.SECOND.quantity(2)));
!
List<MethodProfilingWindowResult> windowResults = new ArrayList<>();
IUnorderedWindowVisitor visitor = createWindowVisitor(settings, settingsFilter, windowSize, windowResults,
! evaluationTask);
SlidingWindowToolkit.slidingWindowUnordered(visitor, items, windowSize, slideSize);
// If a window visitor over a non empty quantity of events is guaranteed to always generate at minimum one raw score, this can be removed.
if (windowResults.isEmpty()) {
return RulesToolkit.getNotApplicableResult(this,
Messages.getString(Messages.HotMethodsRuleFactory_NOT_ENOUGH_SAMPLES));
--- 223,243 ----
JdkTypeIDs.EXECUTION_SAMPLE);
populateSettingsMap(items.apply(settingsFilter), settings);
IQuantity windowSize = valueProvider.getPreferenceValue(WINDOW_SIZE);
IQuantity slideSize = UnitLookup.SECOND.quantity(windowSize.ratioTo(UnitLookup.SECOND.quantity(2)));
! String excludedPattern = valueProvider.getPreferenceValue(EXCLUDED_PACKAGE_REGEXP);
! Pattern excludes;
! try {
! excludes = Pattern.compile(excludedPattern);
! } catch (Exception e) {
! // Make sure we don't blow up on an invalid pattern.
! excludes = Pattern.compile("");
! }
List<MethodProfilingWindowResult> windowResults = new ArrayList<>();
IUnorderedWindowVisitor visitor = createWindowVisitor(settings, settingsFilter, windowSize, windowResults,
! evaluationTask, excludes);
SlidingWindowToolkit.slidingWindowUnordered(visitor, items, windowSize, slideSize);
// If a window visitor over a non empty quantity of events is guaranteed to always generate at minimum one raw score, this can be removed.
if (windowResults.isEmpty()) {
return RulesToolkit.getNotApplicableResult(this,
Messages.getString(Messages.HotMethodsRuleFactory_NOT_ENOUGH_SAMPLES));
*** 318,328 ****
* @return an IUnorderedWindowVisitor implementation that will populate the rawScores list with
* raw score values
*/
private IUnorderedWindowVisitor createWindowVisitor(
final PeriodRangeMap settings, final IItemFilter settingsFilter, final IQuantity windowSize,
! final List<MethodProfilingWindowResult> rawScores, final FutureTask<Result> evaluationTask) {
return new IUnorderedWindowVisitor() {
@Override
public void visitWindow(IItemCollection items, IQuantity startTime, IQuantity endTime) {
IRange<IQuantity> windowRange = QuantityRange.createWithEnd(startTime, endTime);
if (RulesToolkit.getSettingMaxPeriod(items, JdkTypeIDs.EXECUTION_SAMPLE) == null) {
--- 333,343 ----
* @return an IUnorderedWindowVisitor implementation that will populate the rawScores list with
* raw score values
*/
private IUnorderedWindowVisitor createWindowVisitor(
final PeriodRangeMap settings, final IItemFilter settingsFilter, final IQuantity windowSize,
! final List<MethodProfilingWindowResult> rawScores, final FutureTask<Result> evaluationTask, final Pattern excludes) {
return new IUnorderedWindowVisitor() {
@Override
public void visitWindow(IItemCollection items, IQuantity startTime, IQuantity endTime) {
IRange<IQuantity> windowRange = QuantityRange.createWithEnd(startTime, endTime);
if (RulesToolkit.getSettingMaxPeriod(items, JdkTypeIDs.EXECUTION_SAMPLE) == null) {
*** 401,420 ****
int total = 0;
// When we group by stack trace we can run into situations where the top frames are otherwise the same
// for our purposes (finding the hottest method), but they differ by BCI, throwing off the count.
// so we should collect further on the method for the top frame.
for (GroupEntry<IMCStackTrace, CountConsumer> group : groupEntries) {
total += group.getConsumer().getCount();
! IMCMethod topFrameMethod = group.getKey().getFrames().get(0).getMethod();
if (map.get(topFrameMethod) == null) {
map.put(topFrameMethod, UnitLookup.NUMBER_UNITY.quantity(group.getConsumer().getCount()));
! pathMap.put(topFrameMethod, group.getKey());
} else {
IQuantity old = map.get(topFrameMethod);
map.put(topFrameMethod, old.add(UnitLookup.NUMBER_UNITY.quantity(group.getConsumer().getCount())));
}
}
if (!pathMap.isEmpty() && !map.isEmpty()) {
Entry<IMCMethod, IQuantity> topEntry = Collections.max(map.entrySet(), new Comparator<Entry<IMCMethod, IQuantity>>() {
@Override
public int compare(Entry<IMCMethod, IQuantity> arg0,
Entry<IMCMethod, IQuantity> arg1) {
--- 416,438 ----
int total = 0;
// When we group by stack trace we can run into situations where the top frames are otherwise the same
// for our purposes (finding the hottest method), but they differ by BCI, throwing off the count.
// so we should collect further on the method for the top frame.
for (GroupEntry<IMCStackTrace, CountConsumer> group : groupEntries) {
+ IMCStackTrace trace = processPath(group.getKey());
total += group.getConsumer().getCount();
! if (!trace.getFrames().isEmpty()) {
! IMCMethod topFrameMethod = trace.getFrames().get(0).getMethod();
if (map.get(topFrameMethod) == null) {
map.put(topFrameMethod, UnitLookup.NUMBER_UNITY.quantity(group.getConsumer().getCount()));
! pathMap.put(topFrameMethod, trace);
} else {
IQuantity old = map.get(topFrameMethod);
map.put(topFrameMethod, old.add(UnitLookup.NUMBER_UNITY.quantity(group.getConsumer().getCount())));
}
}
+ }
if (!pathMap.isEmpty() && !map.isEmpty()) {
Entry<IMCMethod, IQuantity> topEntry = Collections.max(map.entrySet(), new Comparator<Entry<IMCMethod, IQuantity>>() {
@Override
public int compare(Entry<IMCMethod, IQuantity> arg0,
Entry<IMCMethod, IQuantity> arg1) {
*** 425,434 ****
--- 443,468 ----
maxMethod[0] = topEntry.getKey();
return topEntry.getValue().multiply(1d/total);
}
return UnitLookup.NUMBER_UNITY.quantity(0);
}
+
+ private IMCStackTrace processPath(IMCStackTrace path) {
+ List<IMCFrame> frames = new ArrayList<>(path.getFrames());
+ List<IMCFrame> framesToDrop = new ArrayList<IMCFrame>();
+ // Drop any frames that match the excluded pattern, thereby treating the first non-matching frame that we encounter as the hot one.
+ for (IMCFrame frame : frames) {
+ Matcher m = excludes.matcher(FormatToolkit.getHumanReadable(frame.getMethod(), false, false, true, true, false, false));
+ if (m.matches()) {
+ framesToDrop.add(frame);
+ } else {
+ break;
+ }
+ }
+ frames.removeAll(framesToDrop);
+ return new MCStackTrace(frames, path.getTruncationState());
+ }
});
IQuantity maxRatio = filteredItems.getAggregate(aggregator);
Pair<IQuantity, IMCStackTrace> result = null;
if (maxMethod[0] != null && maxRatio != null && period != null) { // ignoring if there are no samples or if we don't yet know the periodicity
< prev index next >