Skip to content
Permalink
Browse files

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

Reviewed-by: hirt
  • Loading branch information
Henrik Dafgård
Henrik Dafgård committed Jan 27, 2020
1 parent 875abcd commit 6dd19dd5ae3fc4c7e7bfc1e997725408188dbb79
Showing with 173 additions and 27 deletions.
  1. +3 −5 ...openjdk.jmc.flightrecorder.ext.g1/src/main/java/org/openjdk/jmc/flightrecorder/ext/g1/G1Page.java
  2. +3 −3 ...mc.flightrecorder.ui/src/main/java/org/openjdk/jmc/flightrecorder/ui/selection/FlavorToolkit.java
  3. +2 −2 ...rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/dataproviders/HaltsProvider.java
  4. +2 −3 ...er.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/general/ClassLoadingRule.java
  5. +2 −2 ...er.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/latency/JavaBlockingRule.java
  6. +2 −2 ...der.rules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/memory/GcFreedRatioRule.java
  7. +1 −1 ...ules.jdk/src/main/java/org/openjdk/jmc/flightrecorder/rules/jdk/memory/IncreasingLiveSetRule.java
  8. +94 −2 ...mc.flightrecorder.rules/src/main/java/org/openjdk/jmc/flightrecorder/rules/util/RulesToolkit.java
  9. +3 −3 ...trecorder.rules/src/main/java/org/openjdk/jmc/flightrecorder/rules/util/SlidingWindowToolkit.java
  10. +0 −3 ...g.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/jdk/JdkAggregators.java
  11. +2 −1 core/tests/org.openjdk.jmc.flightrecorder.test/META-INF/MANIFEST.MF
  12. +5 −0 core/tests/org.openjdk.jmc.flightrecorder.test/pom.xml
  13. +54 −0 ....flightrecorder.test/src/test/java/org/openjdk/jmc/flightrecorder/test/OverlappingEventsTest.java
  14. BIN core/tests/org.openjdk.jmc.flightrecorder.test/src/test/resources/recordings/overlap.jfr
@@ -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);
}

}
Binary file not shown.

0 comments on commit 6dd19dd

Please sign in to comment.
You can’t perform that action at this time.