private GcInfoHolder getMaxFreedWindow()

in src/core/org.openjdk.jmc.flightrecorder.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/memory/GcFreedRatioRule.java [171:287]


	private GcInfoHolder getMaxFreedWindow(final IItemCollection allItems, IQuantity windowSize, IQuantity slideSize) {
		final GcInfoHolder maxFreedGcInfo = new GcInfoHolder();
		maxFreedGcInfo.freedPerSecondToLivesetRatio = UnitLookup.PERCENT.quantity(0);
		maxFreedGcInfo.freedPerSecond = UnitLookup.BYTE.quantity(0);
		maxFreedGcInfo.averageLiveset = UnitLookup.BYTE.quantity(0);
		maxFreedGcInfo.range = QuantityRange.createWithEnd(UnitLookup.EPOCH_MS.quantity(0),
				UnitLookup.EPOCH_MS.quantity(0));

		// FIXME: Check which of heapSummarySlide and normal sliding window that seems to give the best result

		SlidingWindowToolkit.slidingWindowUnordered(new IUnorderedWindowVisitor() {

			@Override
			public void visitWindow(IItemCollection windowItems, IQuantity startTime, IQuantity endTime) {
				Pair<IItemCollection, IRange<IQuantity>> windowRangePair = getWindowWithPairedHeapSummaryEvents(
						windowItems, startTime, endTime);
				windowItems = windowRangePair.left;
				IQuantity beforeGc = windowItems.getAggregate(JdkAggregators.SUM_HEAP_USED_BEFORE_GC);
				IQuantity afterGc = windowItems.getAggregate(JdkAggregators.SUM_HEAP_USED_AFTER_GC);
				IQuantity averageLiveset = windowItems.getAggregate(JdkAggregators.AVG_HEAP_USED_AFTER_GC);
				if (beforeGc == null || afterGc == null || averageLiveset == null) {
					return;
				}
				IQuantity totalFreed = beforeGc.subtract(afterGc);
				IRange<IQuantity> range = windowRangePair.right;

				double recordingLengthInSeconds = range.getExtent().in(UnitLookup.SECOND).doubleValue();
				IQuantity freedPerSecond = totalFreed.multiply(1 / recordingLengthInSeconds);
				IQuantity freedPerSecondToLivesetRatio = UnitLookup.PERCENT_UNITY
						.quantity(freedPerSecond.ratioTo(averageLiveset));
				if (freedPerSecondToLivesetRatio.compareTo(maxFreedGcInfo.freedPerSecondToLivesetRatio) > 0) {
					maxFreedGcInfo.freedPerSecondToLivesetRatio = freedPerSecondToLivesetRatio;
					maxFreedGcInfo.freedPerSecond = freedPerSecond;
					maxFreedGcInfo.averageLiveset = averageLiveset;
					maxFreedGcInfo.range = range;
				}
			}

			/**
			 * Fixes the item collection by including the potential orphan 'before' event in the
			 * beginning and 'after' event in the end, and after that removing any non-paired events
			 * in the whole item collection.
			 */
			private Pair<IItemCollection, IRange<IQuantity>> getWindowWithPairedHeapSummaryEvents(
				IItemCollection windowItems, IQuantity startTime, IQuantity endTime) {
				IQuantity newStartTime = null;
				IQuantity newEndTime = null;
				IItemCollection heapSummaryWindowItems = windowItems.apply(JdkFilters.HEAP_SUMMARY);
				IItemCollection heapSummaryAllItems = allItems.apply(JdkFilters.HEAP_SUMMARY);
				IQuantity lowestGcId = heapSummaryWindowItems
						.getAggregate((IAggregator<IQuantity, ?>) Aggregators.min(JdkAttributes.GC_ID));
				IItemCollection lowestGcIdWindowItems = heapSummaryWindowItems
						.apply(ItemFilters.equals(JdkAttributes.GC_ID, lowestGcId));
				IItemCollection lowestGcIdAllItems = heapSummaryAllItems
						.apply(ItemFilters.equals(JdkAttributes.GC_ID, lowestGcId));
				IItemCollection lowestGcIdBeforeWindowItems = lowestGcIdWindowItems
						.apply(JdkFilters.HEAP_SUMMARY_BEFORE_GC);
				IItemCollection lowestGcIdAfterWindowItems = lowestGcIdWindowItems
						.apply(JdkFilters.HEAP_SUMMARY_AFTER_GC);
				IItemCollection lowestGcIdBeforeAllItems = lowestGcIdAllItems.apply(JdkFilters.HEAP_SUMMARY_BEFORE_GC);
				// If the beginning of the window is between a 'before' and an 'after' event.
				if (lowestGcIdAfterWindowItems.hasItems() && !lowestGcIdBeforeWindowItems.hasItems()) {
					if (lowestGcIdBeforeAllItems.hasItems()) {
						newStartTime = RulesToolkit.getEarliestEndTime(lowestGcIdBeforeAllItems);
					}
				}
				IQuantity highestGcId = heapSummaryWindowItems
						.getAggregate((IAggregator<IQuantity, ?>) Aggregators.max(JdkAttributes.GC_ID));
				IItemCollection highestGcIdWindowItems = heapSummaryWindowItems
						.apply(ItemFilters.equals(JdkAttributes.GC_ID, highestGcId));
				IItemCollection highestGcIdAllItems = heapSummaryAllItems
						.apply(ItemFilters.equals(JdkAttributes.GC_ID, highestGcId));
				IItemCollection highestGcIdBeforeWindowItems = highestGcIdWindowItems
						.apply(JdkFilters.HEAP_SUMMARY_BEFORE_GC);
				IItemCollection highestGcIdAfterWindowItems = lowestGcIdWindowItems
						.apply(JdkFilters.HEAP_SUMMARY_AFTER_GC);
				IItemCollection highestGcIdAfterAllItems = highestGcIdAllItems.apply(JdkFilters.HEAP_SUMMARY_BEFORE_GC);
				if (highestGcIdBeforeWindowItems.hasItems() && !highestGcIdAfterWindowItems.hasItems()) {
					if (highestGcIdAfterAllItems.hasItems()) {
						newEndTime = RulesToolkit.getEarliestStartTime(highestGcIdAfterAllItems);
					}
				}

				if (newStartTime != null || newEndTime != null) {
					if (newStartTime != null) {
						startTime = newStartTime;
					}
					if (newEndTime != null) {
						endTime = newEndTime;
					}
					windowItems = allItems
							.apply(ItemFilters.interval(JfrAttributes.END_TIME, startTime, false, endTime, false));
				}

				// Filter out those that don't have matching before/after pairs
				Set<IQuantity> gcIds = windowItems.apply(JdkFilters.HEAP_SUMMARY)
						.getAggregate((IAggregator<Set<IQuantity>, ?>) Aggregators.distinct(JdkAttributes.GC_ID));
				for (Iterator<IQuantity> iterator = gcIds.iterator(); iterator.hasNext();) {
					IQuantity gcId = iterator.next();
					IItemCollection gcItems = windowItems.apply(ItemFilters.equals(JdkAttributes.GC_ID, gcId));
					if (!(gcItems.apply(JdkFilters.AFTER_GC).hasItems()
							&& gcItems.apply(JdkFilters.BEFORE_GC).hasItems())) {
						iterator.remove();
					}
				}
				return new Pair<>(windowItems.apply(ItemFilters.memberOf(JdkAttributes.GC_ID, gcIds)),
						QuantityRange.createWithEnd(startTime, endTime));
			}

			@Override
			public boolean shouldContinue() {
				return !evaluationTask.isCancelled();
			}

		}, allItems, windowSize, slideSize);
		return maxFreedGcInfo;
	}