1 package jdk.jfr.threading;
  2 
  3 import java.util.List;
  4 
  5 import jdk.jfr.Event;
  6 import jdk.jfr.Name;
  7 import jdk.jfr.Recording;
  8 import jdk.jfr.consumer.RecordedEvent;
  9 import jdk.jfr.consumer.RecordedFrame;
 10 import jdk.jfr.consumer.RecordedMethod;
 11 import jdk.jfr.consumer.RecordedStackTrace;
 12 import jdk.test.lib.Asserts;
 13 import jdk.test.lib.jfr.Events;
 14 
 15 /**
 16  * @test
 17  * @summary Tests emitting an event, both in Java and native, in a virtual
 18  *          thread with the maximum number of allowed stack frames for JFR
 19  * @key jfr
 20  * @requires vm.hasJFR
 21  * @library /test/lib /test/jdk
 22  * @modules jdk.jfr/jdk.jfr.internal
 23  * @compile --enable-preview -source ${jdk.version} TestDeepVirtualStackTrace.java
 24  * @run main/othervm --enable-preview -XX:FlightRecorderOptions:stackdepth=2048
 25  *      jdk.jfr.threading.TestDeepVirtualStackTrace
 26  */
 27 public class TestDeepVirtualStackTrace {
 28 
 29     public final static int FRAME_COUNT = 2048;
 30 
 31     @Name("test.Deep")
 32     private static class TestEvent extends Event {
 33     }
 34 
 35     public static Object[] allocated;
 36 
 37     public static void main(String... args) throws Exception {
 38         testJavaEvent();
 39         testNativeEvent();
 40     }
 41 
 42     private static void testJavaEvent() throws Exception {
 43         assertStackTrace(() -> deepevent(FRAME_COUNT), "test.Deep", "deepevent");
 44     }
 45 
 46     private static void deepevent(int depth) {
 47         if (depth == 0) {
 48             TestEvent e = new TestEvent();
 49             e.commit();
 50             System.out.println("Emitted Deep event");
 51             return;
 52         }
 53         deepevent(depth - 1);
 54     }
 55 
 56     private static void testNativeEvent() throws Exception {
 57         assertStackTrace(() -> deepsleep(FRAME_COUNT), "jdk.ObjectAllocationOutsideTLAB", "sleep");
 58     }
 59 
 60     private static void deepsleep(int depth) {
 61         if (depth == 0) {
 62             allocated = new Object[10_000_000];
 63             System.out.println("Emitted ObjectAllocationOutsideTLAB event");
 64             return;
 65         }
 66         deepsleep(depth - 1);
 67     }
 68 
 69     private static void assertStackTrace(Runnable eventEmitter, String eventName, String stackMethod) throws Exception {
 70         System.out.println();
 71         System.out.println("Testing event: " + eventName);
 72         System.out.println("=============================");
 73         try (Recording r = new Recording()) {
 74             r.enable(eventName).withoutThreshold();
 75             r.start();
 76             Thread vt = Thread.ofVirtual().start(eventEmitter);
 77             vt.join();
 78             r.stop();
 79             List<RecordedEvent> events = Events.fromRecording(r);
 80             Asserts.assertEquals(events.size(), 1, "No event found in virtual thread");
 81             RecordedEvent event = events.get(0);
 82             System.out.println(event);
 83             RecordedStackTrace stackTrace = event.getStackTrace();
 84             List<RecordedFrame> frames = stackTrace.getFrames();
 85             Asserts.assertTrue(stackTrace.isTruncated());
 86             int count = 0;
 87             for (RecordedFrame frame : frames) {
 88                 Asserts.assertTrue(frame.isJavaFrame());
 89                 Asserts.assertNotNull(frame.getMethod());
 90                 RecordedMethod m = frame.getMethod();
 91                 Asserts.assertNotNull(m.getType());
 92                 if (m.getName().contains(stackMethod)) {
 93                     count++;
 94                 }
 95             }
 96             Asserts.assertEquals(count, FRAME_COUNT);
 97             Asserts.assertEquals(frames.size(), FRAME_COUNT);
 98         }
 99     }
100 
101 }