# HG changeset patch # User egahlin # Date 1558974793 -7200 # Node ID 8e8a06a3059cfc9a6ddb3d7b46b519ecd7b7bc2f # Parent 3efa9b992c4d4d996f865d219ca2784d5e7abcdb Add foundation for event object reuse diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java Mon May 27 18:33:13 2019 +0200 @@ -61,9 +61,15 @@ private LongMap parsers; private boolean chunkFinished; private InternalEventFilter eventFilter = InternalEventFilter.ACCEPT_ALL; + private boolean reuse; - public ChunkParser(RecordingInput input) throws IOException { + public ChunkParser(RecordingInput input, boolean reuse) throws IOException { this(new ChunkHeader(input), null, 500); + this.reuse = reuse; + } + + public void setReuse(boolean resue) { + this.reuse = resue; } private ChunkParser(ChunkHeader header, ChunkParser previous, long pollInterval) throws IOException { @@ -108,10 +114,13 @@ return this.eventFilter; } - private void updateParserFilters() { + private void updateParsers() { parsers.forEach(p -> { if (p instanceof EventParser) { EventParser ep = (EventParser) p; + if (reuse) { + ep.setReuse(true); + } long threshold = eventFilter.getThreshold(ep.getEventType().getName()); if (threshold >= 0) { ep.setEnabled(true); @@ -152,7 +161,7 @@ ParserFactory factory = new ParserFactory(metadata, constantLookups, timeConverter); parsers = factory.getParsers(); typeMap = factory.getTypeMap(); - updateParserFilters(); + updateParsers(); } if (contantPosition != chunkHeader.getConstantPoolPosition()) { Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found new constant pool data. Filling up pools with new values"); diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventDirectoryStream.java Mon May 27 18:33:13 2019 +0200 @@ -102,6 +102,10 @@ } runCloseActions(); } + + public void setReuse(boolean reuse) { + // ignore hint + } } private final EventSetConsumer eventConsumer; @@ -172,4 +176,9 @@ public void awaitTermination() { eventConsumer.awaitTermination(Duration.ofMillis(0)); } + + @Override + public void setReuse(boolean reuse) { + eventConsumer.setReuse(reuse); + } } diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventFileStream.java Mon May 27 18:33:13 2019 +0200 @@ -45,8 +45,7 @@ private final static class FileEventConsumer extends EventConsumer { private final RecordingInput input; private ChunkParser chunkParser; - private RecordedEvent event; - private boolean moreEvents = true; + private boolean reuse = true; public FileEventConsumer(AccessControlContext acc, RecordingInput input) throws IOException { super(acc); @@ -55,12 +54,14 @@ @Override public void process() throws Exception { - chunkParser = new ChunkParser(input); - while (moreEvents) { + chunkParser = new ChunkParser(input, reuse); + chunkParser.setReuse(reuse); + RecordedEvent event; + while (true) { event = chunkParser.readEvent(); if (event == null) { - findNext(); - if (!moreEvents) { + event = findNext(); + if (event == null) { return; } } @@ -68,18 +69,24 @@ } } - private void findNext() throws IOException { + private RecordedEvent findNext() throws IOException { + RecordedEvent event = null; while (event == null) { - if (chunkParser == null) { - chunkParser = new ChunkParser(input); - } else if (!chunkParser.isLastChunk()) { - chunkParser = chunkParser.nextChunkParser(); - } else { - moreEvents = false; - return; + if (chunkParser.isLastChunk()) { + return null; } + chunkParser = chunkParser.nextChunkParser(); event = chunkParser.readEvent(); } + return event; + } + + public void setReuse(boolean reuse) { + if (chunkParser == null) { + this.reuse = reuse; + } else { + chunkParser.setReuse(reuse); + } } } @@ -139,6 +146,10 @@ eventConsumer.start(0); } + public void setReuse(boolean reuse) { + eventConsumer.setReuse(reuse); + } + @Override public void startAsync() { eventConsumer.startAsync(0); diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java Mon May 27 18:33:13 2019 +0200 @@ -46,8 +46,10 @@ private final boolean hasDuration; private final List valueDescriptors; private final int startIndex; + private final RecordedEvent event; private long thresholdTicks = -1; private boolean enabled = true; + private boolean reuse; EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) { this.timeConverter = timeConverter; @@ -56,6 +58,7 @@ this.hasDuration = type.getField(FIELD_DURATION) != null; this.startIndex = hasDuration ? 2 : 1; this.valueDescriptors = type.getFields(); + this.event = new RecordedEvent(type, valueDescriptors, new Object[parsers.length], 0L, 0L, timeConverter); } public EventType getEventType() { @@ -84,24 +87,44 @@ return null; } } - 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); - } - long startTime = timeConverter.convertTimestamp(startTicks); - if (hasDuration) { - long endTime = timeConverter.convertTimestamp(startTicks + durationTicks); - return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter); + if (reuse) { + 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); + } + 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; + } } else { - return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter); + 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); + } + 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 null; - + return event; } @Override @@ -109,4 +132,8 @@ throw new InternalError("Should not call this method. More efficent to read event size and skip ahead"); } + public void setReuse(boolean reuse) { + this.reuse = reuse; + } + } diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/EventSet.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventSet.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventSet.java Mon May 27 18:33:13 2019 +0200 @@ -159,7 +159,7 @@ // held with lock private void addSegment(int index) throws IOException { if (chunkParser == null) { - chunkParser = new ChunkParser(new RecordingInput(path.toFile())); + chunkParser = new ChunkParser(new RecordingInput(path.toFile()), false); } if (dirtyFilter) { chunkParser.setParserFilter(globalFilter); diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java Mon May 27 18:33:13 2019 +0200 @@ -45,8 +45,8 @@ */ public static EventStream openRepository(Path directory) throws IOException { throw new UnsupportedOperationException("Not yet implemented"); -// AccessControlContext acc = AccessController.getContext(); -// return new EventDirectoryStream(acc); + // AccessControlContext acc = AccessController.getContext(); + // return new EventDirectoryStream(acc); } /** @@ -55,11 +55,12 @@ * @param file location of the file, not {@code null} * @return an event stream, not {@code null} * - * @throws IOException if a stream can't be opened,or an I/O error occurs during reading + * @throws IOException if a stream can't be opened,or an I/O error occurs + * during reading */ public static EventStream openFile(Path file) throws IOException { throw new UnsupportedOperationException("Not yet implemented"); -// return new EventFileStream(file); + // return new EventFileStream(file); } /** @@ -67,24 +68,23 @@ * * @param file location of the file, not {@code null} * - * @param the start start time for the stream, or {@code null} to get data from - * the beginning of the + * @param the start start time for the stream, or {@code null} to get data + * from the beginning of the * - * @param the end end time for the stream, or {@code null} to get data until the - * end. + * @param the end end time for the stream, or {@code null} to get data until + * the end. * * @throws IllegalArgumentException if {@code end} happens before * {@code start} * - * @throws IOException if a stream can't be opened,or an I/O error occurs during reading + * @throws IOException if a stream can't be opened,or an I/O error occurs + * during reading */ public static EventStream openFile(Path file, Instant from, Instant to) throws IOException { throw new UnsupportedOperationException("Not yet implemented"); -// return new EventFileStream(file); + // return new EventFileStream(file); } - - /** * Performs an action on all events in the stream. * @@ -140,6 +140,19 @@ boolean remove(Object action); /** + * Hint that the the event object in an {@link #onEvent(Consumer)} action + * may be reused. + *

+ * If reuse is set to + * {@code true), a callback should not keep a reference to the event object + * after the callback from {@code onEvent} has returned. + *

+ * By default reuse is {@code true} + * + */ + public void setReuse(boolean reuse); + + /** * Starts processing events in the stream. *

* All actions will performed on this stream will happen in the current diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java Mon May 27 18:33:13 2019 +0200 @@ -40,9 +40,8 @@ */ public final class RecordedEvent extends RecordedObject { private final EventType eventType; - private final long startTime; - // package private needed for efficient sorting - final long endTime; + long startTime; + long endTime; // package private RecordedEvent(EventType type, List vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) { diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java Mon May 27 18:33:13 2019 +0200 @@ -95,7 +95,7 @@ } } - private final Object[] objects; + final Object[] objects; private final List descriptors; private final TimeConverter timeConverter; diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingFile.java Mon May 27 18:33:13 2019 +0200 @@ -237,7 +237,7 @@ private void findNext() throws IOException { while (nextEvent == null) { if (chunkParser == null) { - chunkParser = new ChunkParser(input); + chunkParser = new ChunkParser(input, false); } else if (!chunkParser.isLastChunk()) { chunkParser = chunkParser.nextChunkParser(); } else { diff -r 3efa9b992c4d -r 8e8a06a3059c src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java Fri May 24 20:51:28 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java Mon May 27 18:33:13 2019 +0200 @@ -296,4 +296,9 @@ public void awaitTermination() { stream.awaitTermination(); } + + @Override + public void setReuse(boolean reuse) { + // hint is ignored + } }