# HG changeset patch # User egahlin # Date 1562290600 -7200 # Node ID 6fabe73e5d9ac57639d05926a4201e1adc3813ff # Parent 099789ceff7dff48d5b85f714ca2bd7a26f4e2bf Reduced allocation pressure. Fix getValue for startTime and duration diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java --- 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); } } }); diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/EventConsumer.java --- 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 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; diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java --- 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 END_TIME = (e1, e2) -> Long.compare(e1.endTime, e2.endTime); + private static final Comparator 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(); diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java --- 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 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; diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java --- 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 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; } } diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java --- 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. *

- * 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. *

- * 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} * diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java --- 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 vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) { + RecordedEvent(EventType type, List 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 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); + } } diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java --- 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 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 descriptors; - private final TimeConverter timeConverter; + protected final List descriptors; + protected final TimeConverter timeConverter; // package private, not to be subclassed outside this package RecordedObject(List 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; diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java --- 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); - } } diff -r 099789ceff7d -r 6fabe73e5d9a src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.java --- 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; } }