# HG changeset patch # User mgronlun # Date 1568638718 -7200 # Node ID 945212abbac09839b4eb1faa027a15a3534a8f9c # Parent 38b5442bcab453f7b3f87dbec2840b581264c514# Parent 26bfa4d54737423c7c012ad01155cba5132c193c Merge diff -r 38b5442bcab4 -r 945212abbac0 src/hotspot/share/jfr/dcmd/jfrDcmds.cpp --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Mon Sep 16 14:57:11 2019 +0200 +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp Mon Sep 16 14:58:38 2019 +0200 @@ -349,7 +349,7 @@ _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false), _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"), _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"), - _flush_interval("flush-interval", "Minimum time before flushing buffers, measuared in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "0"), + _flush_interval("flush-interval", "Minimum time before flushing buffers, measuared in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "1s"), _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false), _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") { _dcmdparser.add_dcmd_option(&_name); diff -r 38b5442bcab4 -r 945212abbac0 src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java Mon Sep 16 14:57:11 2019 +0200 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java Mon Sep 16 14:58:38 2019 +0200 @@ -84,7 +84,7 @@ private TimerTask startTask; private AccessControlContext noDestinationDumpOnExitAccessControlContext; private boolean shuoldWriteActiveRecordingEvent = true; - private Duration flushInterval; + private Duration flushInterval = Duration.ofSeconds(1); PlatformRecording(PlatformRecorder recorder, long id) { // Typically the access control context is taken diff -r 38b5442bcab4 -r 945212abbac0 test/jdk/jdk/jfr/api/consumer/filestream/TestMultipleChunk.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/jdk/jfr/api/consumer/filestream/TestMultipleChunk.java Mon Sep 16 14:58:38 2019 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.consumer.filestream; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.atomic.AtomicLong; + +import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.consumer.EventStream; + +/** + * @test + * @summary Verifies that it is possible to stream contents from a multichunked file + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.consumer.filestream.TestMultipleChunk + */ +public class TestMultipleChunk { + + static class SnakeEvent extends Event { + int id; + } + + public static void main(String... args) throws Exception { + Path path = Paths.get("./using-file.jfr"); + try (Recording r1 = new Recording()) { + r1.start(); + emitSnakeEvent(1); + emitSnakeEvent(2); + emitSnakeEvent(3); + // Force a chunk rotation + try (Recording r2 = new Recording()) { + r2.start(); + emitSnakeEvent(4); + emitSnakeEvent(5); + emitSnakeEvent(6); + r2.stop(); + } + r1.stop(); + r1.dump(path); + AtomicLong counter = new AtomicLong(); + try (EventStream es = EventStream.openFile(path)) { + es.onEvent(e -> { + counter.incrementAndGet(); + }); + es.start(); + if (counter.get() != 6) { + throw new Exception("Expected 6 event, but got " + counter.get()); + } + } + } + } + + static void emitSnakeEvent(int id) { + SnakeEvent e = new SnakeEvent(); + e.id = id; + e.commit(); + } + +} diff -r 38b5442bcab4 -r 945212abbac0 test/jdk/jdk/jfr/api/consumer/streaming/TestFromFile.java --- a/test/jdk/jdk/jfr/api/consumer/streaming/TestFromFile.java Mon Sep 16 14:57:11 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jfr.api.consumer.streaming; - -import java.nio.file.Path; -import java.util.concurrent.atomic.AtomicLong; - -import jdk.jfr.Event; -import jdk.jfr.consumer.EventStream; - -/** - * @test - * @summary Verifies that it is possible to stream contents from a file - * @key jfr - * @requires vm.hasJFR - * @library /test/lib - * @run main/othervm jdk.jfr.api.consumer.streaming.TestFromFile - */ -public class TestFromFile { - - static class SnakeEvent extends Event { - int id; - } - - public static void main(String... args) throws Exception { -// Path path = Paths.get("./using-file.jfr"); -// try (Recording r1 = new Recording()) { -// r1.start(); -// emitSnakeEvent(1); -// emitSnakeEvent(2); -// emitSnakeEvent(3); -// // Force a chunk rotation -// try (Recording r2 = new Recording()) { -// r2.start(); -// emitSnakeEvent(4); -// emitSnakeEvent(5); -// emitSnakeEvent(6); -// r2.stop(); -// } -// r1.stop(); -// r1.dump(path); -// -// testIterator(path); -// testConsumer(path); -// } - } - - static void testConsumer(Path path) throws Exception { - AtomicLong counter = new AtomicLong(); - try (EventStream es = EventStream.openFile(path)) { - es.onEvent(e -> { - counter.incrementAndGet(); - }); - es.startAsync(); - if (counter.get() != 6) { - throw new Exception("Expected 6 event, but got " + counter.get()); - } - es.awaitTermination(); - } - } - - static void emitSnakeEvent(int id) { - SnakeEvent e = new SnakeEvent(); - e.id = id; - e.commit(); - } - -} diff -r 38b5442bcab4 -r 945212abbac0 test/jdk/jdk/jfr/api/consumer/streaming/UseCasesStream.java --- a/test/jdk/jdk/jfr/api/consumer/streaming/UseCasesStream.java Mon Sep 16 14:57:11 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jfr.api.consumer.streaming; - -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.ParseException; -import java.time.Duration; -import java.util.ArrayDeque; - -import jdk.jfr.Configuration; -import jdk.jfr.EventType; -import jdk.jfr.ValueDescriptor; -import jdk.jfr.consumer.RecordingStream; - -class UseCasesStream { - - // - // Use case: Out-of-the-Box Experience - // - // - Simple things should be simple - // - Pique interest, i.e. a one-liner on Stack Overflow - // - Few lines of code as possible - // - Should be easier than alternative technologies, like JMX and JVM TI - // - // - Non-goals: Corner-cases, advanced configuration, releasing resources - // - public static void outOfTheBox() throws InterruptedException { - try (RecordingStream rs = new RecordingStream()) { - rs.enable("jdk.ExceptionThrown"); - rs.onEvent(e -> System.out.println(e.getString("message"))); - rs.start(); - } - - // EventStream.start("jdk.JavaMonitorEnter", "threshold", "20 ms", - // "stackTrace", "false") - // .addConsumer(System.out::println); - // - // EventStream.start("jdk.CPULoad", "period", "1 s") - // .addConsumer(e -> System.out.println(100 * - // e.getDouble("totalMachine") + " %")); - // - // EventStream.start("jdk.GarbageCollection") - // .addConsumer(e -> System.out.println("GC: " + e.getStartTime() + " - // maxPauseTime=" + e.getDuration("maxPauseTime").toMillis() + " ms")); - - Thread.sleep(100_000); - } - - // Use case: Event Forwarding - // - // - Forward arbitrary event to frameworks such as RxJava, JSON/XML and - // Kafka - // - Handle flooding - // - Performant - // - Graceful shutdown - // - Non-goals: Filter events - // - public static void eventForwarding() throws InterruptedException, IOException, ParseException { - // KafkaProducer producer = new KafkaProducer(); - try (RecordingStream rs = new RecordingStream(Configuration.getConfiguration("default"))) { - rs.setMaxAge(Duration.ofMinutes(5)); - rs.setMaxSize(1000_000_000L); - // es.setParallel(true); - // es.setReuse(true); - // es.consume(e -> producer.send(new ProducerRecord("topic", - // e.getString("key"), e.getString("value")))); - rs.start(); - } - // Write primitive values to XML - try (RecordingStream rs = new RecordingStream(Configuration.getConfiguration("deafult"))) { - try (PrintWriter p = new PrintWriter(new FileWriter("recording.xml"))) { - // es.setParallel(false); - // es.setReuse(true); - p.println(""); - p.println(""); - rs.onEvent(e -> { - EventType type = e.getEventType(); - p.println(" "); - for (ValueDescriptor field : e.getEventType().getFields()) { - Object value = e.getValue(field.getName()); - if (value instanceof Number || field.getTypeName().equals("java.lang.String")) { - p.println(" " + value + ""); - } - } - }); - rs.start(); - p.println(""); - } - } - } - - // Use case: Repository Access - // - // - Read the disk repository from another process, for example a side car - // in - // Docker container - // - Be able to configure flush interval from command line or jcmd. - // - Graceful shutdown - // - public static void repositoryAccess() throws IOException, InterruptedException { - Path repository = Paths.get("c:\\repository").toAbsolutePath(); - String command = new String(); - command += "java -XX:StartFlightRecording:flush=2s"; - command += "-XX:FlightRecorderOption:repository=" + repository + " Application"; - Process myProcess = Runtime.getRuntime().exec(command); - try (RecordingStream rs = new RecordingStream()) { - rs.onEvent(System.out::println); - rs.startAsync(); - Thread.sleep(10_000); - myProcess.destroy(); - Thread.sleep(10_000); - } - } - - // Use: Tooling - // - // - Monitor a stream of data for a very long time - // - Predictable interval, i.e. once every second - // - Notification with minimal delay - // - Events with the same period should arrive together - // - Consume events in chronological order - // - Low overhead - // - public static void tooling() throws IOException, ParseException { - ArrayDeque measurements = new ArrayDeque<>(); - try (RecordingStream rs = new RecordingStream(Configuration.getConfiguration("profile"))) { - rs.setInterval(Duration.ofSeconds(1)); - rs.setMaxAge(Duration.ofMinutes(1)); - // rs.setOrdered(true); - // rs.setReuse(false); - // rs.setParallel(true); - rs.onEvent("jdk.CPULoad", e -> { - double d = e.getDouble("totalMachine"); - measurements.addFirst(d); - if (measurements.size() > 60) { - measurements.removeLast(); - } - // repaint(); - }); - rs.start(); - } - } - - // Use case: Low Impact - // - // - Support event subscriptions in a low latency environment (minimal GC - // pauses) - // - Filter out relevant events to minimize disk overhead and allocation - // pressure - // - Avoid impact from other recordings - // - Avoid Heisenberg effects, in particular self-recursion - // - // Non-goals: one-liner - // - public static void lowImpact() throws InterruptedException, IOException, ParseException { - try (RecordingStream rs = new RecordingStream()) { - rs.enable("jdk.JavaMonitorEnter#threshold").withThreshold(Duration.ofMillis(10)); - rs.enable("jdk.ExceptionThrow#enabled"); - // ep.setReuse(true); - rs.onEvent("jdk.JavaMonitorEnter", System.out::println); - rs.onEvent("jdk.ExceptionThrow", System.out::println); - rs.start(); - ; - } - } -}