# HG changeset patch # User jmatsuoka # Date 1544023607 18000 # Wed Dec 05 10:26:47 2018 -0500 # Node ID ab0e1637009b1dd1daa080761d7fa9b78cd20021 # Parent 96ff10493237812206fb941bb1d85857f379295a JMC-6222: Allow filtering by package for the Method Profiling Rule Summary: Add functionality to allow for filtering of certain packages in the stack trace used by the method profiling rule. Reviewed-by: hirt diff -r 96ff10493237 -r ab0e1637009b core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/latency/MethodProfilingRule.java --- a/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/latency/MethodProfilingRule.java Tue Dec 04 08:43:40 2018 +0100 +++ b/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/latency/MethodProfilingRule.java Wed Dec 05 10:26:47 2018 -0500 @@ -47,9 +47,13 @@ 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.IMCPackage; import org.openjdk.jmc.common.IMCStackTrace; import org.openjdk.jmc.common.item.Aggregators; import org.openjdk.jmc.common.item.Aggregators.CountConsumer; @@ -70,6 +74,7 @@ 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; @@ -85,7 +90,6 @@ 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 @@ -168,7 +172,12 @@ Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE), Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE_DESC), UnitLookup.TIMESPAN, UnitLookup.SECOND.quantity(30)); - private static final List> CONFIG_ATTRIBUTES = Arrays.> asList(WINDOW_SIZE); + public static final TypedPreference 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(), "java\\.(lang|util)"); + private static final List> CONFIG_ATTRIBUTES = Arrays.> asList(WINDOW_SIZE, EXCLUDED_PACKAGE_REGEXP); /** * Private Callable implementation specifically used to avoid storing the FutureTask as a field. @@ -217,10 +226,17 @@ 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 windowResults = new ArrayList<>(); IUnorderedWindowVisitor visitor = createWindowVisitor(settings, settingsFilter, windowSize, windowResults, - evaluationTask); + 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()) { @@ -320,7 +336,7 @@ */ private IUnorderedWindowVisitor createWindowVisitor( final PeriodRangeMap settings, final IItemFilter settingsFilter, final IQuantity windowSize, - final List rawScores, final FutureTask evaluationTask) { + final List rawScores, final FutureTask evaluationTask, final Pattern excludes) { return new IUnorderedWindowVisitor() { @Override public void visitWindow(IItemCollection items, IQuantity startTime, IQuantity endTime) { @@ -403,14 +419,17 @@ // 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 group : groupEntries) { + IMCStackTrace trace = processPath(group.getKey()); 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 (!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()) { @@ -427,6 +446,24 @@ } return UnitLookup.NUMBER_UNITY.quantity(0); } + + private IMCStackTrace processPath(IMCStackTrace path) { + List frames = new ArrayList<>(path.getFrames()); + List framesToDrop = new ArrayList(); + // 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) { + IMCPackage p = frame.getMethod().getType().getPackage(); + // Under some circumstances p.getName() will return a raw null, we need to handle this case. + Matcher m = excludes.matcher(p.getName() == null ? "" : p.getName()); + if (m.matches()) { + framesToDrop.add(frame); + } else { + break; + } + } + frames.removeAll(framesToDrop); + return new MCStackTrace(frames, path.getTruncationState()); + } }); IQuantity maxRatio = filteredItems.getAggregate(aggregator); diff -r 96ff10493237 -r ab0e1637009b core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/Messages.java --- a/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/Messages.java Tue Dec 04 08:43:40 2018 +0100 +++ b/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/Messages.java Wed Dec 05 10:26:47 2018 -0500 @@ -396,6 +396,8 @@ public static final String MethodProfilingRule_RULE_NAME = "MethodProfilingRule_RULE_NAME"; //$NON-NLS-1$ public static final String MethodProfilingRule_WINDOW_SIZE = "MethodProfilingRule_WINDOW_SIZE"; //$NON-NLS-1$ public static final String MethodProfilingRule_WINDOW_SIZE_DESC = "MethodProfilingRule_WINDOW_SIZE_DESC"; //$NON-NLS-1$ + public static final String MethodProfilingRule_EXCLUDED_PACKAGES = "MethodProfilingRule_EXCLUDED_PACKAGES"; //$NON-NLS-1$ + public static final String MethodProfilingRule_EXCLUDED_PACKAGES_DESC = "MethodProfilingRule_EXCLUDED_PACKAGES_DESC"; //$NON-NLS-1$ public static final String NumberOfGcThreadsRuleFactory_TEXT_INFO = "NumberOfGcThreadsRuleFactory_TEXT_INFO"; //$NON-NLS-1$ public static final String NumberOfGcThreadsRuleFactory_TEXT_INFO_LONG = "NumberOfGcThreadsRuleFactory_TEXT_INFO_LONG"; //$NON-NLS-1$ public static final String ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE = "ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE"; //$NON-NLS-1$ diff -r 96ff10493237 -r ab0e1637009b core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/resources/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/messages.properties --- a/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/resources/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/messages.properties Tue Dec 04 08:43:40 2018 +0100 +++ b/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/resources/org/openjdk/jmc/flightrecorder/rules/jdk/messages/internal/messages.properties Wed Dec 05 10:26:47 2018 -0500 @@ -437,6 +437,8 @@ MethodProfilingRule_RULE_NAME=Method Profiling MethodProfilingRule_WINDOW_SIZE=Method profiling window size MethodProfilingRule_WINDOW_SIZE_DESC=The size of the sliding window to use for evaluating the method profiling samples in this recording. If the evaluation of this rule takes a long time, consider increasing this parameter. Note an increased window size may reduce the accuracy of the rule. +MethodProfilingRule_EXCLUDED_PACKAGES=Packages to exclude from the stack trace +MethodProfilingRule_EXCLUDED_PACKAGES_DESC=The packages to exclude when traversing stack traces. Drop all frames matching the pattern until reaching the first frame not belonging to either. Count the first encountered frame instead as the hot one. # {0} is a number, {1} is a number NumberOfGcThreadsRuleFactory_TEXT_INFO=The runtime used {0} GC threads on a machine with {1} CPU cores. NumberOfGcThreadsRuleFactory_TEXT_INFO_LONG=It is not optimal to use more GC threads than available cores. Removing the '-XX:ParallelGCThreads' flag will allow the JVM to set the number of GC threads automatically. diff -r 96ff10493237 -r ab0e1637009b core/tests/org.openjdk.jmc.flightrecorder.rules.jdk.test/src/test/resources/baseline/JfrRuleBaseline.xml --- a/core/tests/org.openjdk.jmc.flightrecorder.rules.jdk.test/src/test/resources/baseline/JfrRuleBaseline.xml Tue Dec 04 08:43:40 2018 +0100 +++ b/core/tests/org.openjdk.jmc.flightrecorder.rules.jdk.test/src/test/resources/baseline/JfrRuleBaseline.xml Wed Dec 05 10:26:47 2018 -0500 @@ -3082,7 +3082,7 @@ MethodProfiling OK -1.0227792539479768 +0.8005001984324781 No methods where optimization would be particularly efficient could be detected. No methods where optimization would be particularly efficient could be detected.