--- /dev/null 2016-10-25 08:46:44.038854975 +0200
+++ new/src/share/classes/sun/evtracing/TraceReaderThread.java 2016-10-25 10:40:32.773793142 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
+ *
+ * This file is part of the Lock Contention Tracing Subsystem for the HotSpot
+ * Virtual Machine, which is developed at Christian Doppler Laboratory on
+ * Monitoring and Evolution of Very-Large-Scale Software Systems. Please
+ * contact us at if you need additional information
+ * or have any questions.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work. If not, see .
+ *
+ */
+package sun.evtracing;
+
+import static java.lang.System.err;
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import sun.evtracing.parser.TraceParser;
+import sun.evtracing.processing.TraceEventDiagnosticsHandler;
+import sun.evtracing.processing.TraceEventHandler;
+import sun.evtracing.processing.TraceEventJsonWriter;
+import sun.evtracing.processing.TraceEventMetadataResolveHandler;
+import sun.evtracing.processing.TraceEventNopProcessor;
+import sun.evtracing.processing.TraceEventPrintHandler;
+import sun.evtracing.processing.TraceEventReorderHandler;
+import sun.evtracing.processing.TraceEventValidateHandler;
+import sun.evtracing.processing.TraceProcessor;
+import sun.evtracing.processing.io.Compression;
+import sun.evtracing.processing.io.TraceDataChannelWriter;
+import sun.evtracing.processing.statistics.StatisticsPrinter;
+import sun.evtracing.processing.statistics.TraceEventStatisticsHandler;
+
+public class TraceReaderThread implements Runnable {
+
+ private static final EventTracing tracing = EventTracing.getEventTracing();
+
+ private final TraceBufferQueue flushQueue;
+ private final TraceBufferQueue freeQueue;
+
+ private volatile boolean shuttingDown = false;
+ private Runnable onCompletion = () -> {};
+
+ public TraceReaderThread(TraceBufferQueue flushQueue, TraceBufferQueue freeQueue) throws IOException {
+ assert flushQueue != null;
+ this.flushQueue = flushQueue;
+ this.freeQueue = freeQueue;
+ }
+
+ private TraceProcessor initializeProcessor() throws IOException {
+ String config = EventTracing.getEventTracing().getConfiguration();
+ if (config == null || config.isEmpty()) {
+ config = "Statistics";
+ }
+
+ if (config.equals("Nop")) {
+ return new TraceEventNopProcessor();
+ }
+
+ boolean compressedOutput = config.startsWith("CompressedOutput");
+ if (compressedOutput || config.startsWith("Output")) {
+ String path;
+ if (config.startsWith("Output=") || config.startsWith("CompressedOutput=")) {
+ path = config.substring(1 + config.indexOf('='));
+ } else if (config.equals("Output") || config.equals("CompressedOutput")) {
+ path = "output.trc";
+ if (compressedOutput) {
+ path += ".lz4";
+ }
+ } else {
+ throw new RuntimeException("Invalid tracing configuration: '" + config + "'");
+ }
+
+ if (compressedOutput && !Compression.isSupported()) {
+ throw new RuntimeException("Compression not supported in this build");
+ }
+
+ SeekableByteChannel channel = Files.newByteChannel(Paths.get(path), WRITE, CREATE, TRUNCATE_EXISTING);
+ TraceDataChannelWriter writer = new TraceDataChannelWriter(channel, compressedOutput);
+ EventTracing.getEventTracing().setStatisticsProvider(writer);
+ return writer;
+ }
+
+ String[] handlerConfigs = config.split("\\+");
+ String primary = handlerConfigs[0];
+
+ TraceEventHandler handler;
+
+ if (primary.startsWith("Statistics")) {
+ final String path;
+ if (primary.equals("Statistics")) {
+ path = "trace-statistics.txt";
+ } else if (primary.startsWith("Statistics=")) {
+ path = primary.substring(1 + primary.indexOf('='));
+ } else {
+ throw new RuntimeException("Invalid primary handler: '" + primary + "'");
+ }
+ final TraceEventStatisticsHandler statisticsHandler = new TraceEventStatisticsHandler();
+ handler = statisticsHandler;
+
+ onCompletion = (() -> {
+ try (OutputStream out = new FileOutputStream(path)) {
+ new StatisticsPrinter(statisticsHandler.result(), out).print();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ } else if (primary.startsWith("JsonOutput")) {
+ final String path;
+ if (primary.equals("JsonOutput")) {
+ path = "trace-output.json";
+ } else if (primary.startsWith("JsonOutput=")) {
+ path = primary.substring(1 + primary.indexOf('='));
+ } else {
+ throw new RuntimeException("Invalid primary handler: '" + primary + "'");
+ }
+ handler = new TraceEventJsonWriter(new File(path));
+ } else if (primary.equals("Validate")) {
+ handler = new TraceEventValidateHandler();
+ } else {
+ throw new RuntimeException("Invalid primary handler: '" + primary + "'");
+ }
+
+ for (int i = 1; i < handlerConfigs.length; i++) {
+ String secondary = handlerConfigs[i];
+ if (secondary.equals("Print")) {
+ handler = new TraceEventPrintHandler(handler);
+ } else if (secondary.equals("Diagnostics")) {
+ handler = new TraceEventDiagnosticsHandler(handler);
+ } else {
+ throw new RuntimeException("Invalid secondary handler: '" + secondary + "'");
+ }
+ }
+
+ handler = new TraceEventReorderHandler(handler);
+ handler = new TraceEventMetadataResolveHandler(handler);
+
+ TraceParser parser = new TraceParser(handler, null);
+ EventTracing.getEventTracing().setStatisticsProvider(parser);
+ return parser;
+ }
+
+ void shutdown() {
+ shuttingDown = true;
+ }
+
+ @Override
+ public void run() {
+ try {
+ loop();
+ } catch (Exception e) {
+ e.printStackTrace(err);
+ }
+ }
+
+ @SuppressWarnings("try")
+ private void loop() throws Exception {
+ try (TraceProcessor processor = initializeProcessor()) {
+ while (true) {
+ TraceBuffer tb = flushQueue.dequeue();
+ if (tb == null) {
+ if (!shuttingDown) {
+ throw new RuntimeException("dequeue");
+ }
+ break;
+ }
+
+ processor.process(tb);
+
+ release(tb);
+ tb = null; // do not use after here
+ }
+
+ while (!flushQueue.isEmpty()) {
+ TraceBuffer tb = flushQueue.tryDequeue();
+ assert tb != null;
+
+ processor.process(tb);
+
+ release(tb);
+ tb = null; // do not use after here
+ }
+
+ onCompletion.run();
+ }
+ }
+
+ private void release(TraceBuffer tb) {
+ if (freeQueue != null) {
+ freeQueue.resetBufferAndEnqueue(tb);
+ } else {
+ tracing.freeBuffer(tb.handle());
+ }
+ }
+
+}