Reduced allocation pressure. Fix getValue for startTime and duration
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java Fri Jul 05 03:36:40 2019 +0200
@@ -64,6 +64,7 @@
private boolean reuse;
private boolean ordered;
private boolean resetEventCache;
+ private long firstNanos;
public ChunkParser(RecordingInput input, boolean reuse) throws IOException {
this(new ChunkHeader(input), null, 500);
@@ -359,6 +360,17 @@
// Need to call updateEventParsers() for
// change to take effect
+ public void setFirstNanos(long firstNanos) {
+ long chunkStart = chunkHeader.getStartNanos();
+ // Optimization.
+ if (firstNanos < chunkStart - 1_000_000_000L) {
+ firstNanos = 0;
+ }
+ this.firstNanos = firstNanos;
+ }
+
+ // Need to call updateEventParsers() for
+ // change to take effect
public void resetEventCache() {
this.resetEventCache = true;
}
@@ -370,16 +382,17 @@
String name = ep.getEventType().getName();
ep.setOrdered(ordered);
ep.setReuse(reuse);
+ ep.setFirstNanos(firstNanos);
if (resetEventCache) {
ep.resetCache();
}
long threshold = eventFilter.getThreshold(name);
if (threshold >= 0) {
ep.setEnabled(true);
- ep.setThreshold(timeConverter.convertDurationNanos(threshold));
+ ep.setThresholdNanos(threshold);
} else {
ep.setEnabled(false);
- ep.setThreshold(Long.MAX_VALUE);
+ ep.setThresholdNanos(Long.MAX_VALUE);
}
}
});
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventConsumer.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventConsumer.java Fri Jul 05 03:36:40 2019 +0200
@@ -35,6 +35,7 @@
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@@ -50,6 +51,7 @@
abstract class EventConsumer implements Runnable {
public final static Instant NEXT_EVENT = Instant.now();
+ public final static Comparator<? super RecordedEvent> END_TIME = (e1, e2) -> Long.compare(e1.endTimeTicks, e2.endTimeTicks);
final static class EventDispatcher {
public final static EventDispatcher[] NO_DISPATCHERS = new EventDispatcher[0];
@@ -208,10 +210,6 @@
}
public void dispatch(RecordedEvent e) {
- if (e.endTime < startNanos) {
- return;
- }
-
EventDispatcher[] consumerDispatch = dispatcher.get(e.getEventType().getId());
if (consumerDispatch == null) {
consumerDispatch = EventDispatcher.NO_DISPATCHERS;
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java Fri Jul 05 03:36:40 2019 +0200
@@ -47,7 +47,7 @@
static final class DirectoryConsumer extends EventConsumer {
- private static final Comparator<? super RecordedEvent> END_TIME = (e1, e2) -> Long.compare(e1.endTime, e2.endTime);
+ private static final Comparator<? super RecordedEvent> END_TIME = (e1, e2) -> Long.compare(e1.endTimeTicks, e2.endTimeTicks);
private static final int DEFAULT_ARRAY_SIZE = 10_000;
private final RepositoryFiles repositoryFiles;
private ChunkParser chunkParser;
@@ -78,6 +78,7 @@
while (!isClosed() && !chunkParser.isChunkFinished()) {
chunkParser.setReuse(this.reuse);
chunkParser.setOrdered(this.ordered);
+ chunkParser.setFirstNanos(startNanos);
chunkParser.resetEventCache();
chunkParser.setParserFilter(this.eventFilter);
chunkParser.updateEventParsers();
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java Fri Jul 05 03:36:40 2019 +0200
@@ -32,7 +32,6 @@
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.Objects;
import java.util.function.Consumer;
@@ -45,7 +44,6 @@
final class EventFileStream implements EventStream {
private final static class FileConsumer extends EventConsumer {
- private static final Comparator<? super RecordedEvent> END_TIME = (e1, e2) -> Long.compare(e1.endTime, e2.endTime);
private static final int DEFAULT_ARRAY_SIZE = 100_000;
private final RecordingInput input;
private ChunkParser chunkParser;
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java Fri Jul 05 03:36:40 2019 +0200
@@ -46,11 +46,14 @@
private final boolean hasDuration;
private final List<ValueDescriptor> valueDescriptors;
private final int startIndex;
- private long thresholdTicks = -1;
+ private final int length;
+ private final RecordedEvent unorderedEvent;
private boolean enabled = true;
private RecordedEvent[] eventCache;
private int index;
private boolean ordered;
+ private long firstNanos;
+ private long thresholdNanos = -1;
EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) {
this.timeConverter = timeConverter;
@@ -58,32 +61,36 @@
this.eventType = type;
this.hasDuration = type.getField(FIELD_DURATION) != null;
this.startIndex = hasDuration ? 2 : 1;
+ this.length = parsers.length - startIndex;
this.valueDescriptors = type.getFields();
+ this.unorderedEvent = new RecordedEvent(eventType, valueDescriptors, new Object[length], 0L, 0L, timeConverter);
}
private RecordedEvent cachedEvent() {
- if (index == eventCache.length) {
- RecordedEvent[] cache = eventCache;
- eventCache = new RecordedEvent[eventCache.length * 2];
- System.arraycopy(cache, 0, eventCache, 0, cache.length);
+ if (ordered) {
+ if (index == eventCache.length) {
+ RecordedEvent[] cache = eventCache;
+ eventCache = new RecordedEvent[eventCache.length * 2];
+ System.arraycopy(cache, 0, eventCache, 0, cache.length);
+ }
+ RecordedEvent event = eventCache[index];
+ if (event == null) {
+ event = new RecordedEvent(eventType, valueDescriptors, new Object[length], 0L, 0L, timeConverter);
+ eventCache[index] = event;
+ }
+ index++;
+ return event;
+ } else {
+ return unorderedEvent;
}
- RecordedEvent event = eventCache[index];
- if (event == null) {
- event = new RecordedEvent(eventType, valueDescriptors, new Object[parsers.length], 0L, 0L, timeConverter);
- eventCache[index] = event;
- }
- if (ordered) {
- index++;
- }
- return event;
}
public EventType getEventType() {
return eventType;
}
- public void setThreshold(long thresholdTicks) {
- this.thresholdTicks = thresholdTicks;
+ public void setThresholdNanos(long thresholdNanos) {
+ this.thresholdNanos = thresholdNanos;
}
public void setEnabled(boolean enabled) {
@@ -100,46 +107,34 @@
long durationTicks = 0;
if (hasDuration) {
durationTicks = input.readLong();
- if (durationTicks < thresholdTicks) {
+ if (thresholdNanos > 0L) {
+ if (timeConverter.convertTimespan(durationTicks) < thresholdNanos) {
+ return null;
+ }
+ }
+ }
+ long endTicks = startTicks + durationTicks;
+ if (firstNanos > 0L) {
+ if (timeConverter.convertTimestamp(endTicks) < firstNanos) {
return null;
}
}
+
if (eventCache != null) {
RecordedEvent event = cachedEvent();
+ event.startTimeTicks = startTicks;
+ event.endTimeTicks = endTicks;
Object[] values = event.objects;
- for (int i = startIndex; i < parsers.length; i++) {
- values[i] = parsers[i].parse(input);
- }
- values[0] = startTicks;
- if (hasDuration) {
- values[1] = Long.valueOf(durationTicks);
+ for (int i = 0; i < length; i++) {
+ values[i] = parsers[startIndex + i].parse(input);
}
- long startTime = timeConverter.convertTimestamp(startTicks);
- if (hasDuration) {
- event.startTime = startTime;
- event.endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
- return event;
- } else {
- event.startTime = startTime;
- event.endTime = startTime;
- return event;
- }
+ return event;
} else {
- Object[] values = new Object[parsers.length];
- for (int i = startIndex; i < parsers.length; i++) {
- values[i] = parsers[i].parse(input);
- }
- values[0] = startTicks;
- if (hasDuration) {
- values[1] = Long.valueOf(durationTicks);
+ Object[] values = new Object[length];
+ for (int i = 0; i < length; i++) {
+ values[i] = parsers[startIndex + i].parse(input);
}
- long startTime = timeConverter.convertTimestamp(startTicks);
- if (hasDuration) {
- long endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
- return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter);
- } else {
- return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter);
- }
+ return new RecordedEvent(eventType, valueDescriptors, values, startTicks, endTicks, timeConverter);
}
}
return null;
@@ -170,11 +165,15 @@
}
}
+ public void setFirstNanos(long firstNanos) {
+ this.firstNanos = firstNanos;
+ }
+
public void setOrdered(boolean ordered) {
if (this.ordered == ordered) {
return;
}
- this.ordered = ordered;
- this.index = 0;
+ this.ordered = ordered;
+ this.index = 0;
}
}
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java Fri Jul 05 03:36:40 2019 +0200
@@ -40,8 +40,7 @@
/**
* Creates a stream from a disk repository.
* <p>
- * By default, the stream will start with the next event that is flushed by
- * Flight Recorder.
+ * By default, the stream starts with the next event flushed by Flight Recorder.
*
* @param directory location of the disk repository, not {@code null}
*
@@ -57,7 +56,7 @@
/**
* Creates an event stream from a file.
* <p>
- * By default, the stream will start with the first event in the file.
+ * By default, the stream starts with the first event in the file.
*
* @param file location of the file, not {@code null}
*
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java Fri Jul 05 03:36:40 2019 +0200
@@ -40,15 +40,15 @@
*/
public final class RecordedEvent extends RecordedObject {
private final EventType eventType;
- long startTime;
- long endTime;
+ long startTimeTicks;
+ long endTimeTicks;
// package private
- RecordedEvent(EventType type, List<ValueDescriptor> vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) {
+ RecordedEvent(EventType type, List<ValueDescriptor> vds, Object[] values, long startTimeTicks, long endTimeTicks, TimeConverter timeConverter) {
super(vds, values, timeConverter);
this.eventType = type;
- this.startTime = startTime;
- this.endTime = endTime;
+ this.startTimeTicks = startTimeTicks;
+ this.endTimeTicks = endTimeTicks;
}
/**
@@ -88,7 +88,7 @@
* @return the start time, not {@code null}
*/
public Instant getStartTime() {
- return Instant.ofEpochSecond(0, startTime);
+ return Instant.ofEpochSecond(0, getStartTimeNanos());
}
/**
@@ -99,7 +99,7 @@
* @return the end time, not {@code null}
*/
public Instant getEndTime() {
- return Instant.ofEpochSecond(0, endTime);
+ return Instant.ofEpochSecond(0, getEndTimeNanos());
}
/**
@@ -108,7 +108,7 @@
* @return the duration in nanoseconds, not {@code null}
*/
public Duration getDuration() {
- return Duration.ofNanos(endTime - startTime);
+ return Duration.ofNanos(getEndTimeNanos() - getStartTimeNanos());
}
/**
@@ -120,4 +120,29 @@
public List<ValueDescriptor> getFields() {
return getEventType().getFields();
}
+
+ protected final Object objectAt(int index) {
+ if (index == 0) {
+ return startTimeTicks;
+ }
+ if (hasDuration()) {
+ if (index == 1) {
+ return endTimeTicks - startTimeTicks;
+ }
+ return objects[index - 2];
+ }
+ return objects[index - 1];
+ }
+
+ private boolean hasDuration() {
+ return objects.length + 2 == descriptors.size();
+ }
+
+ private long getStartTimeNanos() {
+ return timeConverter.convertTimestamp(startTimeTicks);
+ }
+
+ private long getEndTimeNanos() {
+ return timeConverter.convertTimestamp(endTimeTicks);
+ }
}
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java Fri Jul 05 03:36:40 2019 +0200
@@ -73,7 +73,7 @@
@Override
public void sort(List<RecordedEvent> events) {
- Collections.sort(events, (e1, e2) -> Long.compare(e1.endTime, e2.endTime));
+ Collections.sort(events, (e1, e2) -> Long.compare(e1.endTimeTicks, e2.endTimeTicks));
}
@Override
@@ -96,8 +96,8 @@
}
final Object[] objects;
- private final List<ValueDescriptor> descriptors;
- private final TimeConverter timeConverter;
+ protected final List<ValueDescriptor> descriptors;
+ protected final TimeConverter timeConverter;
// package private, not to be subclassed outside this package
RecordedObject(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
@@ -201,12 +201,16 @@
return t;
}
+ protected Object objectAt(int index) {
+ return objects[index];
+ }
+
private Object getValue(String name, boolean allowUnsigned) {
Objects.requireNonNull(name);
int index = 0;
for (ValueDescriptor v : descriptors) {
if (name.equals(v.getName())) {
- Object object = objects[index];
+ Object object = objectAt(index);
if (object == null) {
// error or missing
return null;
--- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java Fri Jul 05 03:36:40 2019 +0200
@@ -69,8 +69,4 @@
public ZoneOffset getZoneOffset() {
return zoneOffet;
}
-
- public long convertDurationNanos(long durationNanos) {
- return (long) (durationNanos * divisor);
- }
}
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java Wed Jul 03 22:51:44 2019 +0200
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java Fri Jul 05 03:36:40 2019 +0200
@@ -40,9 +40,10 @@
private static final class Block {
private byte[] bytes = new byte[0];
private long blockPosition;
- private int size;
+ private long blockPositionEnd;
+
boolean contains(long position) {
- return position >= blockPosition && position < blockPosition + size;
+ return position >= blockPosition && position < blockPositionEnd;
}
public void read(RandomAccessFile file, int amount) throws IOException {
@@ -51,7 +52,7 @@
if (amount > bytes.length) {
bytes = new byte[amount];
}
- this.size = amount;
+ this.blockPositionEnd = blockPosition + amount;
file.readFully(bytes, 0 , amount);
}
@@ -61,7 +62,7 @@
public void reset() {
blockPosition = 0;
- size = 0;
+ blockPositionEnd = 0;
}
}