Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6674: Optimize finding of first start time and first & last end times #31

Closed
wants to merge 8 commits into from
@@ -82,7 +82,6 @@
import org.openjdk.jmc.flightrecorder.ext.g1.visualizer.HeapRegionSelectionEvent;
import org.openjdk.jmc.flightrecorder.ext.g1.visualizer.HeapRegionView;
import org.openjdk.jmc.flightrecorder.ext.g1.visualizer.region.HeapRegion;
import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
@@ -261,13 +260,12 @@ public void keyPressed(KeyEvent e) {
.showGC(getDataSource().getItems().apply(ItemFilters.hasAttribute(JdkAttributes.GC_ID)));
if (heapDumps != null) {
gcTable.getManager().getViewer().addSelectionChangedListener(e -> {
IQuantity newTime = gcTable.getSelection().getItems()
.getAggregate(JdkAggregators.FIRST_ITEM_START);
IAggregator<IQuantity, ?> min = Aggregators.min(JfrAttributes.START_TIME);
IQuantity newTime = gcTable.getSelection().getItems().getAggregate(min);
if (newTime == null) {
regionVisualizer.showGC(
getDataSource().getItems().apply(ItemFilters.hasAttribute(JdkAttributes.GC_ID)));
time = getDataSource().getItems().apply(G1Constants.HEAP_REGION_DUMPS)
.getAggregate(JdkAggregators.FIRST_ITEM_START);
time = getDataSource().getItems().apply(G1Constants.HEAP_REGION_DUMPS).getAggregate(min);
} else {
IAggregator<Set<IQuantity>, ?> distinct = Aggregators.distinct(JdkAttributes.GC_ID);
Set<IQuantity> gcIds = gcTable.getSelection().getItems().getAggregate(distinct);
@@ -51,8 +51,8 @@
import org.openjdk.jmc.common.unit.QuantityRange;
import org.openjdk.jmc.common.unit.UnitLookup;
import org.openjdk.jmc.flightrecorder.JfrAttributes;
import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;

// FIXME: Move to flightrecorder bundle, and move back to Java 7
public class FlavorToolkit {
@@ -122,8 +122,8 @@ private static IItemFilter getThreadFilter(Set<IMCThread> threads, boolean sameT
private static Optional<IRange<IQuantity>> calculateTimestampRange(IItemStreamFlavor fromFlavor) {
if (fromFlavor != null) {
IItemCollection items = fromFlavor.evaluate();
IQuantity startTime = items.getAggregate(JdkAggregators.FIRST_ITEM_START);
IQuantity endTime = items.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity startTime = RulesToolkit.getEarliestStartTime(items);
IQuantity endTime = RulesToolkit.getLatestEndTime(items);
if (startTime != null) {
if (endTime != null && startTime.compareTo(endTime) < 0) {
return Optional.of(QuantityRange.createWithEnd(startTime, endTime));
@@ -144,8 +144,8 @@ private static IQuantity calculatePauseSumWithEncapsulationTree(
}

private static IRange<IQuantity> createRange(IItemCollection items) {
IQuantity start = items.getAggregate(JdkAggregators.FIRST_ITEM_START);
IQuantity end = items.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity start = RulesToolkit.getEarliestStartTime(items);
IQuantity end = RulesToolkit.getLatestEndTime(items);
return start != null && end != null ? QuantityRange.createWithEnd(start, end) : null;
}

@@ -48,7 +48,6 @@
import org.openjdk.jmc.common.util.IPreferenceValueProvider;
import org.openjdk.jmc.common.util.TypedPreference;
import org.openjdk.jmc.flightrecorder.JfrAttributes;
import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
import org.openjdk.jmc.flightrecorder.jdk.JdkQueries;
import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
@@ -87,8 +86,8 @@ private Result getResult(IItemCollection items, IPreferenceValueProvider valuePr

IItemCollection events = items.apply(JdkFilters.CLASS_LOAD);

IQuantity startTime = events.getAggregate(JdkAggregators.FIRST_ITEM_START);
IQuantity endTime = events.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity startTime = RulesToolkit.getEarliestStartTime(events);
IQuantity endTime = RulesToolkit.getLatestEndTime(events);
if (startTime != null && endTime != null) {
IQuantity totalTime = endTime.subtract(startTime);
IQuantity max = events.getAggregate(Aggregators.max(JfrAttributes.DURATION));
@@ -97,8 +97,8 @@ private Result getResult(IItemCollection items, IPreferenceValueProvider valuePr
return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JdkTypeIDs.MONITOR_ENTER);
}

IQuantity startTime = items.getAggregate(JdkAggregators.FIRST_ITEM_START);
IQuantity endTime = items.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity startTime = RulesToolkit.getEarliestStartTime(items);
IQuantity endTime = RulesToolkit.getLatestEndTime(items);
IQuantity recordingTime = endTime.subtract(startTime);

IQuantity byInstance = items.getAggregate(MONITOR_BALANCE_BY_INSTANCE);
@@ -225,7 +225,7 @@ public void visitWindow(IItemCollection windowItems, IQuantity startTime, IQuant
// If the beginning of the window is between a 'before' and an 'after' event.
if (lowestGcIdAfterWindowItems.hasItems() && !lowestGcIdBeforeWindowItems.hasItems()) {
if (lowestGcIdBeforeAllItems.hasItems()) {
newStartTime = lowestGcIdBeforeAllItems.getAggregate(JdkAggregators.FIRST_ITEM_END);
newStartTime = RulesToolkit.getEarliestEndTime(lowestGcIdBeforeAllItems);
}
}
IQuantity highestGcId = heapSummaryWindowItems.getAggregate(Aggregators.max(JdkAttributes.GC_ID));
@@ -240,7 +240,7 @@ public void visitWindow(IItemCollection windowItems, IQuantity startTime, IQuant
IItemCollection highestGcIdAfterAllItems = highestGcIdAllItems.apply(JdkFilters.HEAP_SUMMARY_BEFORE_GC);
if (highestGcIdBeforeWindowItems.hasItems() && !highestGcIdAfterWindowItems.hasItems()) {
if (highestGcIdAfterAllItems.hasItems()) {
newEndTime = highestGcIdAfterAllItems.getAggregate(JdkAggregators.FIRST_ITEM_START);
newEndTime = RulesToolkit.getEarliestStartTime(highestGcIdAfterAllItems);
}
}

@@ -153,7 +153,7 @@ private Result getResult(IItemCollection items, IPreferenceValueProvider valuePr
// FIXME: Should construct an message using memoryIncrease, not use a hard limit
if (ea == EventAvailability.DISABLED || ea == EventAvailability.UNKNOWN) {
if (score >= 25) {
IQuantity timeAfterJVMStart = items.getAggregate(JdkAggregators.FIRST_ITEM_START)
IQuantity timeAfterJVMStart = RulesToolkit.getEarliestStartTime(items)
.subtract(items.getAggregate(JdkAggregators.JVM_START_TIME));
String shortMessage = MessageFormat.format(
Messages.getString(Messages.IncreasingLiveSetRuleFactory_TEXT_INFO),
@@ -1333,8 +1333,8 @@ public static String getShortRecordingInfo(IItemCollection items, IQuantity shor
}

private static IQuantity getItemRange(IItemCollection items) {
IQuantity first = items.getAggregate(JdkAggregators.FIRST_ITEM_START);
IQuantity last = items.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity first = getEarliestStartTime(items);
IQuantity last = getLatestEndTime(items);

return last.subtract(first);
}
@@ -1366,4 +1366,96 @@ public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2)
}
return sortedMap;
}

/**
* Returns the earliest start time in the provided item collection. This method is based on the
* assumption that item collection lanes are sorted by timestamp.
*
* @param items
* the item collection to find the earliest start time in
* @return the earliest start time in the provided collection
*/
public static IQuantity getEarliestStartTime(IItemCollection items) {
IQuantity earliestStartTime = null;
for (IItemIterable iItemIterable : items) {
IMemberAccessor<IQuantity, IItem> startTimeAccessor = JfrAttributes.START_TIME
.getAccessor(iItemIterable.getType());
if (iItemIterable.iterator().hasNext()) {
IItem next = iItemIterable.iterator().next();
if (next != null && startTimeAccessor != null) {
IQuantity startTime = startTimeAccessor.getMember(next);
if (earliestStartTime == null) {
earliestStartTime = startTime;
} else {
if (earliestStartTime.compareTo(startTime) >= 0) {
earliestStartTime = startTime;
}
}
}
}
}
return earliestStartTime;
}

/**
* Returns the earliest end time in the provided item collection. This method is based on the
* assumption that item collection lanes are sorted by timestamp and are not overlapping.
*
* @param items
* the item collection to find the earliest end time in
* @return the earliest end time in the provided collection
*/
public static IQuantity getEarliestEndTime(IItemCollection items) {
IQuantity earliestEndTime = null;
for (IItemIterable iItemIterable : items) {
IMemberAccessor<IQuantity, IItem> endTimeAccessor = JfrAttributes.END_TIME
.getAccessor(iItemIterable.getType());
if (iItemIterable.iterator().hasNext()) {
IItem next = iItemIterable.iterator().next();
if (next != null && endTimeAccessor != null) {
IQuantity endTime = endTimeAccessor.getMember(next);
if (earliestEndTime == null) {
earliestEndTime = endTime;
} else {
if (earliestEndTime.compareTo(endTime) >= 0) {
earliestEndTime = endTime;
}
}
}
}
}
return earliestEndTime;
}

/**
* Returns the latest end time in the provided item collection. This method is based on the
* assumption that item collection lanes are sorted by timestamp and are not overlapping.
*
* @param items
* the item collection to find the latest end time in
* @return the latest end time in the provided collection
*/
public static IQuantity getLatestEndTime(IItemCollection items) {
IQuantity latestEndTime = null;
for (IItemIterable iItemIterable : items) {
IMemberAccessor<IQuantity, IItem> endTimeAccessor = JfrAttributes.END_TIME
.getAccessor(iItemIterable.getType());
Iterator<IItem> iterator = iItemIterable.iterator();
IItem next = null;
while (iterator.hasNext()) {
next = iterator.next();
}
if (next != null && endTimeAccessor != null) {
IQuantity startTime = endTimeAccessor.getMember(next);
if (latestEndTime == null) {
latestEndTime = startTime;
} else {
if (latestEndTime.compareTo(startTime) <= 0) {
latestEndTime = startTime;
}
}
}
}
return latestEndTime;
}
}
@@ -179,9 +179,9 @@ public static void slidingWindowUnordered(
public static void slidingWindowUnordered(
IUnorderedWindowVisitor callback, IItemCollection items, IQuantity windowSize, IQuantity slideSize,
boolean includeIntersecting) {
IQuantity first = includeIntersecting ? items.getAggregate(JdkAggregators.FIRST_ITEM_START)
: items.getAggregate(JdkAggregators.FIRST_ITEM_END);
IQuantity last = items.getAggregate(JdkAggregators.LAST_ITEM_END);
IQuantity first = includeIntersecting ? RulesToolkit.getEarliestStartTime(items)
: RulesToolkit.getEarliestEndTime(items);
IQuantity last = RulesToolkit.getLatestEndTime(items);

if (first == null) {
return;
@@ -348,9 +348,6 @@
Messages.getString(Messages.AGGR_SWEEP_RECLAIMED_SUM),
Messages.getString(Messages.AGGR_SWEEP_RECLAIMED_SUM_DESC), JdkTypeIDs.SWEEP_CODE_CACHE,
JdkAttributes.SWEEP_METHOD_RECLAIMED);
public static final IAggregator<IQuantity, ?> FIRST_ITEM_START = Aggregators.min(JfrAttributes.START_TIME);
public static final IAggregator<IQuantity, ?> FIRST_ITEM_END = Aggregators.min(JfrAttributes.END_TIME);
public static final IAggregator<IQuantity, ?> LAST_ITEM_END = Aggregators.max(JfrAttributes.END_TIME);
public static final IAggregator<IQuantity, ?> LONGEST_EVENT = Aggregators.max(DURATION);
public static final IAggregator<IQuantity, ?> ITEM_COUNT = Aggregators
.count(Messages.getString(Messages.AGGR_ITEM_COUNT), Messages.getString(Messages.AGGR_ITEM_COUNT_DESC));
@@ -8,5 +8,6 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy
Require-Bundle: org.junit,
org.openjdk.jmc.common.test,
org.openjdk.jmc.flightrecorder
org.openjdk.jmc.flightrecorder,
org.openjdk.jmc.flightrecorder.rules
Automatic-Module-Name: org.openjdk.jmc.flightrecorder.test
@@ -60,6 +60,11 @@
<artifactId>flightrecorder</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmc</groupId>
<artifactId>flightrecorder.rules</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -0,0 +1,54 @@
package org.openjdk.jmc.flightrecorder.test;

import java.io.IOException;

import org.junit.Assert;
import org.junit.Test;
import org.openjdk.jmc.common.IDisplayable;
import org.openjdk.jmc.common.item.Aggregators;
import org.openjdk.jmc.common.item.IAggregator;
import org.openjdk.jmc.common.item.IItemCollection;
import org.openjdk.jmc.common.item.ItemFilters;
import org.openjdk.jmc.common.unit.IQuantity;
import org.openjdk.jmc.common.unit.UnitLookup;
import org.openjdk.jmc.flightrecorder.CouldNotLoadRecordingException;
import org.openjdk.jmc.flightrecorder.JfrAttributes;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
import org.openjdk.jmc.flightrecorder.test.util.RecordingToolkit;

public class OverlappingEventsTest {

@Test
public void testStartTime() throws IOException, CouldNotLoadRecordingException {
IItemCollection overlap = RecordingToolkit.getNamedRecording("overlap.jfr")
.apply(ItemFilters.type("org.openjdk.jmc.test.OverlappingEvent"));
IAggregator<IQuantity, ?> first = Aggregators.min(JfrAttributes.START_TIME);
IQuantity expected = overlap.getAggregate(first);
IQuantity actual = RulesToolkit.getEarliestStartTime(overlap).in(expected.getUnit());
Assert.assertEquals("expected: " + expected.displayUsing(IDisplayable.AUTO) + ", actual: "
+ actual.displayUsing(IDisplayable.AUTO), expected, actual);
}

@Test
public void testFirstEndTime() throws IOException, CouldNotLoadRecordingException {
IItemCollection overlap = RecordingToolkit.getNamedRecording("overlap.jfr")
.apply(ItemFilters.type("org.openjdk.jmc.test.OverlappingEvent"));
IAggregator<IQuantity, ?> min = Aggregators.min(JfrAttributes.END_TIME);
IQuantity expected = overlap.getAggregate(min);
IQuantity actual = RulesToolkit.getEarliestEndTime(overlap).in(expected.getUnit());
Assert.assertEquals("expected: " + expected.displayUsing(IDisplayable.AUTO) + ", actual: "
+ actual.displayUsing(IDisplayable.AUTO), expected, actual);
}

@Test
public void testLastEndTime() throws IOException, CouldNotLoadRecordingException {
IItemCollection overlap = RecordingToolkit.getNamedRecording("overlap.jfr")
.apply(ItemFilters.type("org.openjdk.jmc.test.OverlappingEvent"));
IAggregator<IQuantity, ?> last = Aggregators.max(JfrAttributes.END_TIME);
IQuantity aggregatedLast = overlap.getAggregate(last).in(UnitLookup.EPOCH_NS);
IQuantity actual = RulesToolkit.getLatestEndTime(overlap).in(UnitLookup.EPOCH_NS);
Assert.assertEquals("expected: " + aggregatedLast.displayUsing(IDisplayable.AUTO) + ", actual: "
+ actual.displayUsing(IDisplayable.AUTO), aggregatedLast, actual);
}

}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.