--- /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()); + } + } + +}