Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8295487

JFR: Add stop methods for recording streams

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 20
    • hotspot
    • None
    • jfr
    • source
    • minimal
    • Java API
    • JDK

      Summary

      Add methods RecordingStream::stop() and RemoteRecordingStream::stop() to finish a recording stream without closing it.

      Problem

      A recording stream can be created to monitor what happens during some piece of code, for example, a test method like this:

          AtomicBoolean socketUse = new AtomicBoolean();
          try (var r = new RecordingStream()) {
              r.setMaxSize(Long.MAX_VALUE);
              r.enable("jdk.SocketWrite").withoutThreshold();
              r.enable("jdk.SocketRead").withoutThreshold();
              r.onEvent(event -> socketUse.set(true));
              r.startAsync();
              testFoo();
              // ???? Wait for events here
              if (socketUse.get()) {
                  r.dump(Path.of("socket-events.jfr"));
                  throw new AssertionError("testFoo() should not use network");
              }
          }

      The problem is that there is no good way to ensure all events have been consumed in the stream before checking the result.

      This limitation has led users to abandon the RecordingStream and instead use a combination of RecordingFile and Recording class to manage the life cycle. It works, but the code becomes more complex and they can't leverage other benefits provided by the RecordingStream class, such as filtering and sorting of events.

      Solution

      Introduce a stop() method that will finish the recording, but wait for all events to be consumed before returning.

      r.startAsync();
      testFoo();
      r.stop();
      if (socketUse.get()) {
          r.dump(Path.of("socket-events.jfr"));
          throw new AssertionError("testFoo() should not use network");
      }

      The jdk.jfr.consumer.Recording and jdk.management.jfr.FlightRecorderMXBean classes already have stop() methods, so extending the functionality to RecordingStream and RemoteRecordingStream is a natural fit.

      Specification

      jdk.jfr.RecordingStream:

      +    /**
      +     * Stops the recording stream.
      +     * <p>
      +     * Stops a started stream and waits until all events in the recording have
      +     * been consumed.
      +     * <p>
      +     * Invoking this method in an action, for example in the
      +     * {@link #onEvent(Consumer)} method, could block the stream indefinitely.
      +     * To stop the stream abruptly, use the {@link #close} method.
      +     * <p>
      +     * The following code snippet illustrates how this method can be used in
      +     * conjunction with the {@link #startAsync()} method to monitor what happens
      +     * during a test method:
      +     * <p>
      +     * {@snippet class="Snippets" region="RecordingStreamStop"}
      +     *
      +     * @return {@code true} if recording is stopped, {@code false} otherwise
      +     *
      +     * @throws IllegalStateException if the recording is not started or is already stopped
      +     */

      jdk.managment.jfr.RemoteRecordingStream:

      +    /**
      +     * Stops the recording stream.
      +     * <p>
      +     * Stops a started stream and waits until all events in the recording have
      +     * been consumed.
      +     * <p>
      +     * Invoking this method in an action, for example in the
      +     * {@link #onEvent(Consumer)} method, could block the stream indefinitely.
      +     * To stop the stream abruptly, use the {@link #close} method.
      +     * <p>
      +     * The following code snippet illustrates how this method can be used in
      +     * conjunction with the {@link #startAsync()} method to monitor what happens
      +     * during a test method:
      +     * <p>
      +     * {@snippet :
      +     *   AtomicLong bytesWritten = new AtomicLong();
      +     *   try (var r = new RemoteRecordingStream(connection)) {
      +     *     r.setMaxSize(Long.MAX_VALUE);
      +     *     r.enable("jdk.FileWrite").withoutThreshold();
      +     *     r.onEvent(event ->
      +     *       bytesWritten.addAndGet(event.getLong("bytesWritten"))
      +     *     );
      +     *     r.startAsync();
      +     *     testFoo();
      +     *     r.stop();
      +     *     if (bytesWritten.get() > 1_000_000L) {
      +     *       r.dump(Path.of("file-write-events.jfr"));
      +     *       throw new AssertionError("testFoo() write to much data to disk");
      +     *     }
      +     *   }
      +     * }
      +     * @return {@code true} if recording is stopped, {@code false} otherwise
      +     *
      +     * @throws IllegalStateException if the recording is not started or is already stopped
      +     */
      +    public boolean stop() {

            egahlin Erik Gahlin
            egahlin Erik Gahlin
            Markus Grönlund
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: