77
88import com .datadoghq .profiler .AbstractProfilerTest ;
99import com .datadoghq .profiler .JavaProfiler ;
10+ import com .datadoghq .profiler .JfrEvent ;
11+ import com .datadoghq .profiler .JfrEvents ;
1012import com .datadoghq .profiler .Platform ;
1113import org .junit .jupiter .api .MethodOrderer ;
1214import org .junit .jupiter .api .Order ;
1315import org .junit .jupiter .api .Tag ;
1416import org .junit .jupiter .api .Test ;
1517import org .junit .jupiter .api .TestMethodOrder ;
1618import org .junitpioneer .jupiter .RetryingTest ;
17- import org .openjdk .jmc .common .IMCType ;
18- import org .openjdk .jmc .common .item .IAttribute ;
19- import org .openjdk .jmc .common .item .IItem ;
20- import org .openjdk .jmc .common .item .IItemCollection ;
21- import org .openjdk .jmc .common .item .IItemIterable ;
22- import org .openjdk .jmc .common .item .IMemberAccessor ;
2319
2420import java .nio .file .Files ;
2521import java .nio .file .Path ;
3228import static org .junit .jupiter .api .Assertions .assertEquals ;
3329import static org .junit .jupiter .api .Assertions .assertNotNull ;
3430import static org .junit .jupiter .api .Assertions .assertTrue ;
35- import static org .openjdk .jmc .common .item .Attribute .attr ;
36- import static org .openjdk .jmc .common .unit .UnitLookup .PLAIN_TEXT ;
3731
3832/**
3933 * PROF-15341 (+ lifecycle-wiring follow-up, + the Remaining Work Plan's target-selection bridging,
9286@ Tag ("slow" )
9387public class ReferenceChainTrackingTest extends AbstractProfilerTest {
9488
95- private static final IAttribute <String > SETTING_NAME = attr ("name" , "" , "" , PLAIN_TEXT );
96- private static final IAttribute <String > SETTING_VALUE = attr ("value" , "" , "" , PLAIN_TEXT );
97-
9889 // Arbitrary, test-chosen klass ids for the debug-only population-seeding seams below (see
9990 // ReferenceChainTestSeamsTest's own comment: LivenessTracker's population table treats these as
10091 // opaque keys, so they need not resolve to any real class). Distinct per test/from
@@ -224,19 +215,11 @@ protected boolean isPlatformSupported() {
224215 @ RetryingTest (5 )
225216 public void shouldExposeReferenceChainsSettingWhenEnabled () {
226217 stopProfiler ();
227- IItemCollection settings = verifyEvents ("jdk.ActiveSetting" );
218+ JfrEvents settings = verifyEvents ("jdk.ActiveSetting" );
228219 boolean sawEnabledSetting = false ;
229- for (IItemIterable iterable : settings ) {
230- IMemberAccessor <String , IItem > nameAccessor = SETTING_NAME .getAccessor (iterable .getType ());
231- IMemberAccessor <String , IItem > valueAccessor = SETTING_VALUE .getAccessor (iterable .getType ());
232- if (nameAccessor == null || valueAccessor == null ) {
233- continue ;
234- }
235- for (IItem item : iterable ) {
236- if ("enabled" .equals (nameAccessor .getMember (item ))
237- && "true" .equals (valueAccessor .getMember (item ))) {
238- sawEnabledSetting = true ;
239- }
220+ for (JfrEvent item : settings ) {
221+ if ("enabled" .equals (item .getString ("name" )) && "true" .equals (item .getString ("value" ))) {
222+ sawEnabledSetting = true ;
240223 }
241224 }
242225 assertTrue (sawEnabledSetting , "datadog.ReferenceChain#enabled setting was not found" );
@@ -334,7 +317,7 @@ public void shouldReconstructReferrerChainToGcRoot() throws Exception {
334317 // flag as leak candidates - this test's own assertions below look for ChainLink specifically
335318 // among however many datadog.ReferenceChain events actually appear, rather than assuming it
336319 // is the only one.
337- ReferenceChainAssertions .ChainMatch match = null ;
320+ ReferenceChainAssertions .JfrChainMatch match = null ;
338321 boolean seededTestKlassTrend = false ;
339322 int totalRounds = 16 ;
340323 for (int round = 1 ; round <= totalRounds && match == null ; round ++) {
@@ -436,7 +419,7 @@ public void shouldReconstructReferrerChainToGcRoot() throws Exception {
436419 // keep as its representative. Everything above chain[0] reflects real JDK-internal
437420 // collection representation (e.g. ArrayList's backing array) rather than anything this test
438421 // controls, so it is deliberately not asserted beyond "at least one hop was reconstructed".
439- assertEquals (ChainLink .class .getName (), match .chain .get (0 ). getFullName () );
422+ assertEquals (ChainLink .class .getName (), match .chain .get (0 ));
440423 assertTrue (match .targetTag > 0 , "targetTag should be a valid, non-zero JVMTI tag" );
441424 assertTrue (match .depth >= 0 , "depth should be a non-negative hop count" );
442425 assertTrue (!gcRootHolder .isEmpty ()); // keeps every allocated ChainLink reachable until here
@@ -515,7 +498,7 @@ public void shouldReconstructReferrerChainThroughUnboundedCacheLeak() throws Exc
515498 // floor rather than this test's own "memory=64" request, why totalRounds is capped at
516499 // 16 rather than a larger margin above the 10-round minimum (shared-fork heap headroom),
517500 // and why per-round growth itself is clamped to round 10 (Math.min(round, 10) below).
518- ReferenceChainAssertions .ChainMatch match = null ;
501+ ReferenceChainAssertions .JfrChainMatch match = null ;
519502 boolean seededTestKlassTrend = false ;
520503 int totalRounds = 16 ;
521504
@@ -559,7 +542,7 @@ public void shouldReconstructReferrerChainThroughUnboundedCacheLeak() throws Exc
559542 nextKey += newEntries ;
560543 System .gc ();
561544 dump (scratchDumpPath );
562- IItemCollection events1 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
545+ JfrEvents events1 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
563546 match = ReferenceChainAssertions .findMatchForClass (events1 , CachedPayload .class );
564547
565548 if (match == null && "debug" .equals (System .getProperty ("ddprof_test.config" ))) {
@@ -581,7 +564,7 @@ public void shouldReconstructReferrerChainThroughUnboundedCacheLeak() throws Exc
581564 JavaProfiler .setKlassPopulationRepresentativeForTest0 (CACHED_PAYLOAD_TEST_KLASS_ID , cache .get (keys [0 ]));
582565 JavaProfiler .pollReferenceChainTargets0 ();
583566 dump (scratchDumpPath );
584- IItemCollection events2 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
567+ JfrEvents events2 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
585568 match = ReferenceChainAssertions .findMatchForClass (events2 , CachedPayload .class );
586569 }
587570
@@ -591,32 +574,32 @@ public void shouldReconstructReferrerChainThroughUnboundedCacheLeak() throws Exc
591574 // slot against Profiler::dump()'s own exclusive hold.
592575 Thread .sleep (300 );
593576 dump (scratchDumpPath );
594- IItemCollection events3 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
577+ JfrEvents events3 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
595578 match = ReferenceChainAssertions .findMatchForClass (events3 , CachedPayload .class );
596579 }
597580 }
598581
599582 for (int attempt = 0 ; match == null && attempt < 5 ; attempt ++) {
600583 Thread .sleep (1000 );
601584 dump (scratchDumpPath );
602- IItemCollection events4 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
585+ JfrEvents events4 = verifyEvents (scratchDumpPath , "datadog.ReferenceChain" , false );
603586 match = ReferenceChainAssertions .findMatchForClass (events4 , CachedPayload .class );
604587 }
605588
606589 assertNotNull (match ,
607590 "Never observed a datadog.ReferenceChain event whose chain[0] is " + CachedPayload .class
608591 + " after " + cache .size () + " cached entries across up to " + totalRounds
609592 + " population-growth rounds plus a grace period" );
610- assertEquals (CachedPayload .class .getName (), match .chain .get (0 ). getFullName () );
593+ assertEquals (CachedPayload .class .getName (), match .chain .get (0 ));
611594 assertTrue (match .targetTag > 0 , "targetTag should be a valid, non-zero JVMTI tag" );
612595 assertTrue (match .depth >= 0 , "depth should be a non-negative hop count" );
613596
614597 // The point of this test over shouldReconstructReferrerChainToGcRoot(): confirm the walk
615598 // actually passed through the cache's own internal storage, not some other, coincidental
616599 // retainer - cache is the only thing keeping any CachedPayload instance reachable.
617600 boolean sawHashMapInternals = false ;
618- for (IMCType type : match .chain ) {
619- if (type .getFullName (). startsWith ("java.util.HashMap" )) {
601+ for (String type : match .chain ) {
602+ if (type .startsWith ("java.util.HashMap" )) {
620603 sawHashMapInternals = true ;
621604 break ;
622605 }
@@ -685,7 +668,7 @@ public void shouldReportAbandonedSearchOnTinyFrontierCap() throws Exception {
685668 Path dumpPath = Paths .get ("referencechains-abandoned-test.jfr" );
686669 try {
687670 dump (dumpPath );
688- IItemCollection abandoned = verifyEvents (dumpPath , "datadog.ReferenceChainAbandoned" , true );
671+ JfrEvents abandoned = verifyEvents (dumpPath , "datadog.ReferenceChainAbandoned" , true );
689672 assertTrue (abandoned .hasItems (), "Expected at least one datadog.ReferenceChainAbandoned event" );
690673 } finally {
691674 Files .deleteIfExists (dumpPath );
0 commit comments