< 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 >