Reduced allocation pressure. Fix getValue for startTime and duration JEP-349-branch
authoregahlin
Fri, 05 Jul 2019 03:36:40 +0200
branchJEP-349-branch
changeset 57452 6fabe73e5d9a
parent 57449 099789ceff7d
child 57453 0391c57da284
Reduced allocation pressure. Fix getValue for startTime and duration
src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventConsumer.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java
src/jdk.jfr/share/classes/jdk/jfr/consumer/TimeConverter.java
src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInput.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);
                 }
             }
         });
--- 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;
         }
     }