< 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




 159                 }
 160 
 161                 @Override
 162                 public String toString() {
 163                         return FormatToolkit.getHumanReadable(method, false, false, true, true, true, false) + " (" //$NON-NLS-1$
 164                                         + ratioOfAllPossibleSamples.displayUsing(IDisplayable.AUTO) + ") " //$NON-NLS-1$
 165                                         + window.displayUsing(IDisplayable.AUTO);
 166                 }
 167         }
 168 
 169         private static final String RESULT_ID = "MethodProfiling"; //$NON-NLS-1$
 170         public static final TypedPreference<IQuantity> WINDOW_SIZE = new TypedPreference<>(
 171                         "method.profiling.evaluation.window.size", //$NON-NLS-1$
 172                         Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE),
 173                         Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE_DESC), UnitLookup.TIMESPAN,
 174                         UnitLookup.SECOND.quantity(30));
 175         public static final TypedPreference<String> EXCLUDED_PACKAGE_REGEXP = new TypedPreference<>(
 176                         "method.profiling.evaluation.excluded.package", //$NON-NLS-1$
 177                         Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES),
 178                         Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES_DESC),
 179                         UnitLookup.PLAIN_TEXT.getPersister(), "java\\.(lang|util)");
 180         private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays.<TypedPreference<?>> asList(WINDOW_SIZE, EXCLUDED_PACKAGE_REGEXP);
 181 
 182         /**
 183          * Private Callable implementation specifically used to avoid storing the FutureTask as a field.
 184          */
 185         private class MethodProfilingCallable implements Callable<Result> {
 186                 private FutureTask<Result> evaluationTask = null;
 187                 private IItemCollection items;
 188                 private IPreferenceValueProvider valueProvider;
 189 
 190                 private MethodProfilingCallable(IItemCollection items, IPreferenceValueProvider valueProvider) {
 191                         this.items = items;
 192                         this.valueProvider = valueProvider;
 193                 }
 194 
 195                 @Override
 196                 public Result call() throws Exception {
 197                         return getResult(items, valueProvider, evaluationTask);
 198                 }
 199 


 215                 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JdkTypeIDs.EXECUTION_SAMPLE,
 216                                 JdkTypeIDs.RECORDING_SETTING);
 217                 if (eventAvailability != EventAvailability.AVAILABLE) {
 218                         return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.EXECUTION_SAMPLE,
 219                                         JdkTypeIDs.RECORDING_SETTING);
 220                 }
 221 
 222                 PeriodRangeMap settings = new PeriodRangeMap();
 223                 IItemFilter settingsFilter = RulesToolkit.getSettingsFilter(RulesToolkit.REC_SETTING_NAME_PERIOD,
 224                                 JdkTypeIDs.EXECUTION_SAMPLE);
 225                 populateSettingsMap(items.apply(settingsFilter), settings);
 226 
 227                 IQuantity windowSize = valueProvider.getPreferenceValue(WINDOW_SIZE);
 228                 IQuantity slideSize = UnitLookup.SECOND.quantity(windowSize.ratioTo(UnitLookup.SECOND.quantity(2)));
 229                 String excludedPattern = valueProvider.getPreferenceValue(EXCLUDED_PACKAGE_REGEXP);
 230                 Pattern excludes;
 231                 try {
 232                         excludes = Pattern.compile(excludedPattern);
 233                 } catch (Exception e) {
 234                         // Make sure we don't blow up on an invalid pattern.
 235                         excludes = Pattern.compile("");
 236                 }
 237                 List<MethodProfilingWindowResult> windowResults = new ArrayList<>();
 238                 IUnorderedWindowVisitor visitor = createWindowVisitor(settings, settingsFilter, windowSize, windowResults,
 239                                 evaluationTask, excludes);
 240                 SlidingWindowToolkit.slidingWindowUnordered(visitor, items, windowSize, slideSize);
 241                 // 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.
 242                 if (windowResults.isEmpty()) {
 243                         return RulesToolkit.getNotApplicableResult(this,
 244                                         Messages.getString(Messages.HotMethodsRuleFactory_NOT_ENOUGH_SAMPLES));
 245                 }
 246                 Pair<MethodProfilingWindowResult, Map<IMCStackTrace, MethodProfilingWindowResult>> interestingMethods = getInterestingMethods(
 247                                 windowResults);
 248                 Map<IMCStackTrace, MethodProfilingWindowResult> percentByMethod = interestingMethods.right;
 249                 MethodProfilingWindowResult mostInterestingResult = interestingMethods.left;
 250                 if (mostInterestingResult == null) { // Couldn't find any interesting methods
 251                         return new Result(this, 0, Messages.getString(Messages.HotMethodsRuleFactory_TEXT_OK));
 252                 }
 253                 double mappedScore = performSigmoidMap(
 254                                 mostInterestingResult.ratioOfAllPossibleSamples.doubleValueIn(UnitLookup.PERCENT_UNITY));
 255 


 384                         @Override
 385                         public boolean shouldContinue() {
 386                                 return evaluationTask != null && !evaluationTask.isCancelled();
 387                         }
 388 
 389                         /**
 390                          * Performs the actual calculation of the score for the given period of the recording.
 391                          *
 392                          * @param items
 393                          *            the items to base the score on
 394                          * @param period
 395                          *            the periodicity to base the relevancy calculation on
 396                          * @return a double value in the interval [0,1] with 1 being a system in completely
 397                          *         saturated load with only one method called
 398                          */
 399                         private Pair<IQuantity, IMCStackTrace> performCalculation(IItemCollection items, IQuantity period) {
 400                                 IItemCollection filteredItems = items.apply(JdkFilters.EXECUTION_SAMPLE);
 401                                 final IMCMethod[] maxMethod = new IMCMethod[1];
 402                                 final IMCStackTrace[] maxPath = new IMCStackTrace[1];
 403                                 // Using this GroupingAggregator because it's the only way to extract the keys from the aggregation along with values
 404                                 IAggregator<IQuantity, ?> aggregator = GroupingAggregator.build("", "", //$NON-NLS-1$ //$NON_NLS_2$
 405                                                 MethodProfilingDataProvider.PATH_ACCESSOR_FACTORY, Aggregators.count(),
 406                                                 new GroupingAggregator.IGroupsFinisher<IQuantity, IMCStackTrace, CountConsumer>() {
 407 
 408                                                         @Override
 409                                                         public IType<IQuantity> getValueType() {
 410                                                                 return UnitLookup.NUMBER;
 411                                                         }
 412 
 413                                                         @Override
 414                                                         public IQuantity getValue(Iterable<? extends GroupEntry<IMCStackTrace, CountConsumer>> groupEntries) {
 415                                                                 HashMap<IMCMethod, IQuantity> map = new HashMap<>();
 416                                                                 HashMap<IMCMethod, IMCStackTrace> pathMap = new HashMap<>();
 417                                                                 int total = 0;
 418                                                                 // When we group by stack trace we can run into situations where the top frames are otherwise the same
 419                                                                 // for our purposes (finding the hottest method), but they differ by BCI, throwing off the count.
 420                                                                 // so we should collect further on the method for the top frame.
 421                                                                 for (GroupEntry<IMCStackTrace, CountConsumer> group : groupEntries) {
 422                                                                         IMCStackTrace trace = processPath(group.getKey());
 423                                                                         total += group.getConsumer().getCount();
 424                                                                         if (!trace.getFrames().isEmpty()) {


 437                                                                                 @Override
 438                                                                                 public int compare(Entry<IMCMethod, IQuantity> arg0,
 439                                                                                                 Entry<IMCMethod, IQuantity> arg1) {
 440                                                                                         return arg0.getValue().compareTo(arg1.getValue());
 441                                                                                 }
 442                                                                         });
 443                                                                         maxPath[0] = pathMap.get(topEntry.getKey());
 444                                                                         maxMethod[0] = topEntry.getKey();
 445                                                                         return topEntry.getValue().multiply(1d/total);
 446                                                                 }
 447                                                                 return UnitLookup.NUMBER_UNITY.quantity(0);
 448                                                         }
 449 
 450                                                         private IMCStackTrace processPath(IMCStackTrace path) {
 451                                                                 List<IMCFrame> frames = new ArrayList<>(path.getFrames());
 452                                                                 List<IMCFrame> framesToDrop = new ArrayList<IMCFrame>();
 453                                                                 // Drop any frames that match the excluded pattern, thereby treating the first non-matching frame that we encounter as the hot one.
 454                                                                 for (IMCFrame frame : frames) {
 455                                                                         IMCPackage p = frame.getMethod().getType().getPackage();
 456                                                                         // Under some circumstances p.getName() will return a raw null, we need to handle this case.
 457                                                                         Matcher m = excludes.matcher(p.getName() == null ? "" : p.getName());
 458                                                                         if (m.matches()) {
 459                                                                                 framesToDrop.add(frame);
 460                                                                         } else {
 461                                                                                 break;
 462                                                                         }
 463                                                                 }
 464                                                                 frames.removeAll(framesToDrop);
 465                                                                 return new MCStackTrace(frames, path.getTruncationState());
 466                                                         }
 467                                 });
 468 
 469                                 IQuantity maxRatio = filteredItems.getAggregate(aggregator);
 470                                 Pair<IQuantity, IMCStackTrace> result = null;
 471                                 if (maxMethod[0] != null && maxRatio != null && period != null) { // ignoring if there are no samples or if we don't yet know the periodicity
 472                                         double periodsPerSecond = 1 / period.doubleValueIn(UnitLookup.SECOND);
 473                                         double maxSamplesPerSecond = SAMPLES_PER_PERIOD * periodsPerSecond;
 474                                         double samplesInPeriod = items
 475                                                         .getAggregate(Aggregators.count(ItemFilters.type(JdkTypeIDs.EXECUTION_SAMPLE)))
 476                                                         .doubleValueIn(UnitLookup.NUMBER_UNITY);
 477                                         double maxSamplesInPeriod = maxSamplesPerSecond * windowSize.doubleValueIn(UnitLookup.SECOND);




 159                 }
 160 
 161                 @Override
 162                 public String toString() {
 163                         return FormatToolkit.getHumanReadable(method, false, false, true, true, true, false) + " (" //$NON-NLS-1$
 164                                         + ratioOfAllPossibleSamples.displayUsing(IDisplayable.AUTO) + ") " //$NON-NLS-1$
 165                                         + window.displayUsing(IDisplayable.AUTO);
 166                 }
 167         }
 168 
 169         private static final String RESULT_ID = "MethodProfiling"; //$NON-NLS-1$
 170         public static final TypedPreference<IQuantity> WINDOW_SIZE = new TypedPreference<>(
 171                         "method.profiling.evaluation.window.size", //$NON-NLS-1$
 172                         Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE),
 173                         Messages.getString(Messages.MethodProfilingRule_WINDOW_SIZE_DESC), UnitLookup.TIMESPAN,
 174                         UnitLookup.SECOND.quantity(30));
 175         public static final TypedPreference<String> EXCLUDED_PACKAGE_REGEXP = new TypedPreference<>(
 176                         "method.profiling.evaluation.excluded.package", //$NON-NLS-1$
 177                         Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES),
 178                         Messages.getString(Messages.MethodProfilingRule_EXCLUDED_PACKAGES_DESC),
 179                         UnitLookup.PLAIN_TEXT.getPersister(), "java\\.(lang|util)"); //$NON-NLS-1$
 180         private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays.<TypedPreference<?>> asList(WINDOW_SIZE, EXCLUDED_PACKAGE_REGEXP);
 181 
 182         /**
 183          * Private Callable implementation specifically used to avoid storing the FutureTask as a field.
 184          */
 185         private class MethodProfilingCallable implements Callable<Result> {
 186                 private FutureTask<Result> evaluationTask = null;
 187                 private IItemCollection items;
 188                 private IPreferenceValueProvider valueProvider;
 189 
 190                 private MethodProfilingCallable(IItemCollection items, IPreferenceValueProvider valueProvider) {
 191                         this.items = items;
 192                         this.valueProvider = valueProvider;
 193                 }
 194 
 195                 @Override
 196                 public Result call() throws Exception {
 197                         return getResult(items, valueProvider, evaluationTask);
 198                 }
 199 


 215                 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JdkTypeIDs.EXECUTION_SAMPLE,
 216                                 JdkTypeIDs.RECORDING_SETTING);
 217                 if (eventAvailability != EventAvailability.AVAILABLE) {
 218                         return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.EXECUTION_SAMPLE,
 219                                         JdkTypeIDs.RECORDING_SETTING);
 220                 }
 221 
 222                 PeriodRangeMap settings = new PeriodRangeMap();
 223                 IItemFilter settingsFilter = RulesToolkit.getSettingsFilter(RulesToolkit.REC_SETTING_NAME_PERIOD,
 224                                 JdkTypeIDs.EXECUTION_SAMPLE);
 225                 populateSettingsMap(items.apply(settingsFilter), settings);
 226 
 227                 IQuantity windowSize = valueProvider.getPreferenceValue(WINDOW_SIZE);
 228                 IQuantity slideSize = UnitLookup.SECOND.quantity(windowSize.ratioTo(UnitLookup.SECOND.quantity(2)));
 229                 String excludedPattern = valueProvider.getPreferenceValue(EXCLUDED_PACKAGE_REGEXP);
 230                 Pattern excludes;
 231                 try {
 232                         excludes = Pattern.compile(excludedPattern);
 233                 } catch (Exception e) {
 234                         // Make sure we don't blow up on an invalid pattern.
 235                         excludes = Pattern.compile(""); //$NON-NLS-1$
 236                 }
 237                 List<MethodProfilingWindowResult> windowResults = new ArrayList<>();
 238                 IUnorderedWindowVisitor visitor = createWindowVisitor(settings, settingsFilter, windowSize, windowResults,
 239                                 evaluationTask, excludes);
 240                 SlidingWindowToolkit.slidingWindowUnordered(visitor, items, windowSize, slideSize);
 241                 // 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.
 242                 if (windowResults.isEmpty()) {
 243                         return RulesToolkit.getNotApplicableResult(this,
 244                                         Messages.getString(Messages.HotMethodsRuleFactory_NOT_ENOUGH_SAMPLES));
 245                 }
 246                 Pair<MethodProfilingWindowResult, Map<IMCStackTrace, MethodProfilingWindowResult>> interestingMethods = getInterestingMethods(
 247                                 windowResults);
 248                 Map<IMCStackTrace, MethodProfilingWindowResult> percentByMethod = interestingMethods.right;
 249                 MethodProfilingWindowResult mostInterestingResult = interestingMethods.left;
 250                 if (mostInterestingResult == null) { // Couldn't find any interesting methods
 251                         return new Result(this, 0, Messages.getString(Messages.HotMethodsRuleFactory_TEXT_OK));
 252                 }
 253                 double mappedScore = performSigmoidMap(
 254                                 mostInterestingResult.ratioOfAllPossibleSamples.doubleValueIn(UnitLookup.PERCENT_UNITY));
 255 


 384                         @Override
 385                         public boolean shouldContinue() {
 386                                 return evaluationTask != null && !evaluationTask.isCancelled();
 387                         }
 388 
 389                         /**
 390                          * Performs the actual calculation of the score for the given period of the recording.
 391                          *
 392                          * @param items
 393                          *            the items to base the score on
 394                          * @param period
 395                          *            the periodicity to base the relevancy calculation on
 396                          * @return a double value in the interval [0,1] with 1 being a system in completely
 397                          *         saturated load with only one method called
 398                          */
 399                         private Pair<IQuantity, IMCStackTrace> performCalculation(IItemCollection items, IQuantity period) {
 400                                 IItemCollection filteredItems = items.apply(JdkFilters.EXECUTION_SAMPLE);
 401                                 final IMCMethod[] maxMethod = new IMCMethod[1];
 402                                 final IMCStackTrace[] maxPath = new IMCStackTrace[1];
 403                                 // Using this GroupingAggregator because it's the only way to extract the keys from the aggregation along with values
 404                                 IAggregator<IQuantity, ?> aggregator = GroupingAggregator.build("", "", //$NON-NLS-1$ //$NON-NLS-2$
 405                                                 MethodProfilingDataProvider.PATH_ACCESSOR_FACTORY, Aggregators.count(),
 406                                                 new GroupingAggregator.IGroupsFinisher<IQuantity, IMCStackTrace, CountConsumer>() {
 407 
 408                                                         @Override
 409                                                         public IType<IQuantity> getValueType() {
 410                                                                 return UnitLookup.NUMBER;
 411                                                         }
 412 
 413                                                         @Override
 414                                                         public IQuantity getValue(Iterable<? extends GroupEntry<IMCStackTrace, CountConsumer>> groupEntries) {
 415                                                                 HashMap<IMCMethod, IQuantity> map = new HashMap<>();
 416                                                                 HashMap<IMCMethod, IMCStackTrace> pathMap = new HashMap<>();
 417                                                                 int total = 0;
 418                                                                 // When we group by stack trace we can run into situations where the top frames are otherwise the same
 419                                                                 // for our purposes (finding the hottest method), but they differ by BCI, throwing off the count.
 420                                                                 // so we should collect further on the method for the top frame.
 421                                                                 for (GroupEntry<IMCStackTrace, CountConsumer> group : groupEntries) {
 422                                                                         IMCStackTrace trace = processPath(group.getKey());
 423                                                                         total += group.getConsumer().getCount();
 424                                                                         if (!trace.getFrames().isEmpty()) {


 437                                                                                 @Override
 438                                                                                 public int compare(Entry<IMCMethod, IQuantity> arg0,
 439                                                                                                 Entry<IMCMethod, IQuantity> arg1) {
 440                                                                                         return arg0.getValue().compareTo(arg1.getValue());
 441                                                                                 }
 442                                                                         });
 443                                                                         maxPath[0] = pathMap.get(topEntry.getKey());
 444                                                                         maxMethod[0] = topEntry.getKey();
 445                                                                         return topEntry.getValue().multiply(1d/total);
 446                                                                 }
 447                                                                 return UnitLookup.NUMBER_UNITY.quantity(0);
 448                                                         }
 449 
 450                                                         private IMCStackTrace processPath(IMCStackTrace path) {
 451                                                                 List<IMCFrame> frames = new ArrayList<>(path.getFrames());
 452                                                                 List<IMCFrame> framesToDrop = new ArrayList<IMCFrame>();
 453                                                                 // Drop any frames that match the excluded pattern, thereby treating the first non-matching frame that we encounter as the hot one.
 454                                                                 for (IMCFrame frame : frames) {
 455                                                                         IMCPackage p = frame.getMethod().getType().getPackage();
 456                                                                         // Under some circumstances p.getName() will return a raw null, we need to handle this case.
 457                                                                         Matcher m = excludes.matcher(p.getName() == null ? "" : p.getName()); //$NON-NLS-1$
 458                                                                         if (m.matches()) {
 459                                                                                 framesToDrop.add(frame);
 460                                                                         } else {
 461                                                                                 break;
 462                                                                         }
 463                                                                 }
 464                                                                 frames.removeAll(framesToDrop);
 465                                                                 return new MCStackTrace(frames, path.getTruncationState());
 466                                                         }
 467                                 });
 468 
 469                                 IQuantity maxRatio = filteredItems.getAggregate(aggregator);
 470                                 Pair<IQuantity, IMCStackTrace> result = null;
 471                                 if (maxMethod[0] != null && maxRatio != null && period != null) { // ignoring if there are no samples or if we don't yet know the periodicity
 472                                         double periodsPerSecond = 1 / period.doubleValueIn(UnitLookup.SECOND);
 473                                         double maxSamplesPerSecond = SAMPLES_PER_PERIOD * periodsPerSecond;
 474                                         double samplesInPeriod = items
 475                                                         .getAggregate(Aggregators.count(ItemFilters.type(JdkTypeIDs.EXECUTION_SAMPLE)))
 476                                                         .doubleValueIn(UnitLookup.NUMBER_UNITY);
 477                                         double maxSamplesInPeriod = maxSamplesPerSecond * windowSize.doubleValueIn(UnitLookup.SECOND);


< prev index next >