51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53
54 import org.openjdk.jmc.flightrecorder.CouldNotLoadRecordingException;
55 import org.openjdk.jmc.flightrecorder.internal.parser.Chunk;
56 import org.openjdk.jmc.flightrecorder.internal.parser.LoaderContext;
57 import org.openjdk.jmc.flightrecorder.internal.parser.v0.ChunkLoaderV0;
58 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkLoaderV1;
59 import org.openjdk.jmc.flightrecorder.parser.IParserExtension;
60 import org.openjdk.jmc.flightrecorder.parser.ParserExtensionRegistry;
61
62 /**
63 * Helper class for loading flight recordings from disk.
64 */
65 public final class FlightRecordingLoader {
66
67 private static final Logger LOGGER = Logger.getLogger(FlightRecordingLoader.class.getName());
68 private static final String SINGLE_THREADED_PARSER_PROPERTY_KEY = "org.openjdk.jmc.flightrecorder.parser.singlethreaded"; //$NON-NLS-1$
69 private static final int MIN_MEMORY_PER_THREAD = 300 * 1024 * 1024; // Unless the chunks are very big, 300MB of available memory per parallel chunk load should be plenty
70 private static final short VERSION_0 = 0; // JDK7 & JDK8
71 private static final short VERSION_1 = 1; // JDK9
72 private static final byte[] FLIGHT_RECORDER_MAGIC = {'F', 'L', 'R', '\0'};
73
74 public static EventArray[] loadStream(InputStream stream, boolean hideExperimentals, boolean ignoreTruncatedChunk)
75 throws CouldNotLoadRecordingException, IOException {
76 return loadStream(stream, ParserExtensionRegistry.getParserExtensions(), hideExperimentals,
77 ignoreTruncatedChunk);
78 }
79
80 /**
81 * Read events from an input stream of JFR data.
82 *
83 * @param stream
84 * input stream
85 * @param extensions
86 * the extensions to use when parsing the data
87 * @param hideExperimentals
88 * if {@code true}, then events of types marked as experimental will be ignored when
89 * reading the data
90 * @return an array of EventArrays (one event type per EventArray)
91 */
160 long nextChunkPos = 0;
161 final List<ChunkInfo> chunks = new ArrayList<>();
162 byte[] buffer = new byte[0];
163 Chunk nextChunk;
164 while ((nextChunk = chunkSupplier.getNextChunk(buffer)) != null) {
165 ChunkInfo info = getChunkInfo(nextChunk, nextChunkPos);
166 nextChunk.skip(info.getChunkSize());
167 buffer = nextChunk.getReusableBuffer();
168 nextChunkPos += info.getChunkSize();
169 chunks.add(info);
170 }
171 return chunks;
172 }
173
174 private static ChunkInfo getChunkInfo(Chunk nextChunk, long nextChunkPos)
175 throws CouldNotLoadRecordingException, IOException {
176 switch (nextChunk.getMajorVersion()) {
177 case VERSION_0:
178 return ChunkLoaderV0.getInfo(nextChunk, nextChunkPos);
179 case VERSION_1:
180 return ChunkLoaderV1.getInfo(nextChunk, nextChunkPos);
181 default:
182 throw new VersionNotSupportedException();
183 }
184 }
185
186 public static EventArray[] readChunks(
187 Runnable monitor, IChunkSupplier chunkSupplier, boolean hideExperimentals, boolean ignoreTruncatedChunk)
188 throws CouldNotLoadRecordingException, IOException {
189 return readChunks(monitor, ParserExtensionRegistry.getParserExtensions(), chunkSupplier, hideExperimentals,
190 ignoreTruncatedChunk);
191 }
192
193 public static EventArray[] readChunks(
194 Runnable monitor, List<? extends IParserExtension> extensions, IChunkSupplier chunkSupplier,
195 boolean hideExperimentals, boolean ignoreTruncatedChunk) throws CouldNotLoadRecordingException, IOException {
196 LoaderContext context = new LoaderContext(extensions, hideExperimentals);
197 Runtime rt = Runtime.getRuntime();
198 long availableMemory = rt.maxMemory() - rt.totalMemory() + rt.freeMemory();
199 long maxBuffersCount = Math.min(Math.max(availableMemory / MIN_MEMORY_PER_THREAD, 1),
279 * @param context
280 * loader context that the returned chunk loader will send event data to
281 * @param buffer
282 * Initial byte array to use for storing chunk data. See
283 * {@link IChunkSupplier#getNextChunk(byte[])}.
284 * @param ignoreTruncatedChunk
285 * if true, then any exceptions caused by getting and reading the next chunk will be
286 * ignored and instead make the method return null
287 * @return a new chunk loader or null if no more data is available from the chunk supplier
288 */
289 private static IChunkLoader createChunkLoader(
290 IChunkSupplier chunkSupplier, LoaderContext context, byte[] buffer, boolean ignoreTruncatedChunk)
291 throws CouldNotLoadRecordingException, IOException {
292 try {
293 Chunk chunk = chunkSupplier.getNextChunk(buffer);
294 if (chunk != null) {
295 switch (chunk.getMajorVersion()) {
296 case VERSION_0:
297 return ChunkLoaderV0.create(chunk, context);
298 case VERSION_1:
299 return ChunkLoaderV1.create(chunk, context);
300 default:
301 throw new VersionNotSupportedException();
302 }
303 }
304 } catch (IOException e) {
305 if (ignoreTruncatedChunk) {
306 LOGGER.log(Level.INFO, "Ignoring exception while reading chunk", e); //$NON-NLS-1$
307 } else {
308 throw e;
309 }
310 }
311 return null;
312 }
313 }
|
51 import java.util.logging.Level;
52 import java.util.logging.Logger;
53
54 import org.openjdk.jmc.flightrecorder.CouldNotLoadRecordingException;
55 import org.openjdk.jmc.flightrecorder.internal.parser.Chunk;
56 import org.openjdk.jmc.flightrecorder.internal.parser.LoaderContext;
57 import org.openjdk.jmc.flightrecorder.internal.parser.v0.ChunkLoaderV0;
58 import org.openjdk.jmc.flightrecorder.internal.parser.v1.ChunkLoaderV1;
59 import org.openjdk.jmc.flightrecorder.parser.IParserExtension;
60 import org.openjdk.jmc.flightrecorder.parser.ParserExtensionRegistry;
61
62 /**
63 * Helper class for loading flight recordings from disk.
64 */
65 public final class FlightRecordingLoader {
66
67 private static final Logger LOGGER = Logger.getLogger(FlightRecordingLoader.class.getName());
68 private static final String SINGLE_THREADED_PARSER_PROPERTY_KEY = "org.openjdk.jmc.flightrecorder.parser.singlethreaded"; //$NON-NLS-1$
69 private static final int MIN_MEMORY_PER_THREAD = 300 * 1024 * 1024; // Unless the chunks are very big, 300MB of available memory per parallel chunk load should be plenty
70 private static final short VERSION_0 = 0; // JDK7 & JDK8
71 private static final short VERSION_1 = 1; // JDK9 & JDK10
72 private static final short VERSION_2 = 2; // JDK11
73 private static final byte[] FLIGHT_RECORDER_MAGIC = {'F', 'L', 'R', '\0'};
74
75 public static EventArray[] loadStream(InputStream stream, boolean hideExperimentals, boolean ignoreTruncatedChunk)
76 throws CouldNotLoadRecordingException, IOException {
77 return loadStream(stream, ParserExtensionRegistry.getParserExtensions(), hideExperimentals,
78 ignoreTruncatedChunk);
79 }
80
81 /**
82 * Read events from an input stream of JFR data.
83 *
84 * @param stream
85 * input stream
86 * @param extensions
87 * the extensions to use when parsing the data
88 * @param hideExperimentals
89 * if {@code true}, then events of types marked as experimental will be ignored when
90 * reading the data
91 * @return an array of EventArrays (one event type per EventArray)
92 */
161 long nextChunkPos = 0;
162 final List<ChunkInfo> chunks = new ArrayList<>();
163 byte[] buffer = new byte[0];
164 Chunk nextChunk;
165 while ((nextChunk = chunkSupplier.getNextChunk(buffer)) != null) {
166 ChunkInfo info = getChunkInfo(nextChunk, nextChunkPos);
167 nextChunk.skip(info.getChunkSize());
168 buffer = nextChunk.getReusableBuffer();
169 nextChunkPos += info.getChunkSize();
170 chunks.add(info);
171 }
172 return chunks;
173 }
174
175 private static ChunkInfo getChunkInfo(Chunk nextChunk, long nextChunkPos)
176 throws CouldNotLoadRecordingException, IOException {
177 switch (nextChunk.getMajorVersion()) {
178 case VERSION_0:
179 return ChunkLoaderV0.getInfo(nextChunk, nextChunkPos);
180 case VERSION_1:
181 case VERSION_2:
182 return ChunkLoaderV1.getInfo(nextChunk, nextChunkPos);
183 default:
184 throw new VersionNotSupportedException();
185 }
186 }
187
188 public static EventArray[] readChunks(
189 Runnable monitor, IChunkSupplier chunkSupplier, boolean hideExperimentals, boolean ignoreTruncatedChunk)
190 throws CouldNotLoadRecordingException, IOException {
191 return readChunks(monitor, ParserExtensionRegistry.getParserExtensions(), chunkSupplier, hideExperimentals,
192 ignoreTruncatedChunk);
193 }
194
195 public static EventArray[] readChunks(
196 Runnable monitor, List<? extends IParserExtension> extensions, IChunkSupplier chunkSupplier,
197 boolean hideExperimentals, boolean ignoreTruncatedChunk) throws CouldNotLoadRecordingException, IOException {
198 LoaderContext context = new LoaderContext(extensions, hideExperimentals);
199 Runtime rt = Runtime.getRuntime();
200 long availableMemory = rt.maxMemory() - rt.totalMemory() + rt.freeMemory();
201 long maxBuffersCount = Math.min(Math.max(availableMemory / MIN_MEMORY_PER_THREAD, 1),
281 * @param context
282 * loader context that the returned chunk loader will send event data to
283 * @param buffer
284 * Initial byte array to use for storing chunk data. See
285 * {@link IChunkSupplier#getNextChunk(byte[])}.
286 * @param ignoreTruncatedChunk
287 * if true, then any exceptions caused by getting and reading the next chunk will be
288 * ignored and instead make the method return null
289 * @return a new chunk loader or null if no more data is available from the chunk supplier
290 */
291 private static IChunkLoader createChunkLoader(
292 IChunkSupplier chunkSupplier, LoaderContext context, byte[] buffer, boolean ignoreTruncatedChunk)
293 throws CouldNotLoadRecordingException, IOException {
294 try {
295 Chunk chunk = chunkSupplier.getNextChunk(buffer);
296 if (chunk != null) {
297 switch (chunk.getMajorVersion()) {
298 case VERSION_0:
299 return ChunkLoaderV0.create(chunk, context);
300 case VERSION_1:
301 case VERSION_2:
302 return ChunkLoaderV1.create(chunk, context);
303 default:
304 throw new VersionNotSupportedException();
305 }
306 }
307 } catch (IOException e) {
308 if (ignoreTruncatedChunk) {
309 LOGGER.log(Level.INFO, "Ignoring exception while reading chunk", e); //$NON-NLS-1$
310 } else {
311 throw e;
312 }
313 }
314 return null;
315 }
316 }
|