diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index bad9c707b1e51..a5ca715bd40f3 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,6 +27,8 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" +#include "jfr/jfrEvents.hpp" +#include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "memory/heapInspection.hpp" @@ -74,6 +76,8 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con } #if INCLUDE_SERVICES + +template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; const size_t _total_size_in_words; @@ -88,7 +92,8 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _timestamp); + ObjectCountEventSender::send(entry, _timestamp); + // Event::send(entry, _timestamp); } } @@ -99,21 +104,39 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; +void GCTracer::report_object_count(KlassInfoTable* cit) { + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); + cit->iterate(&event_sender); + ObjectCountClosure::reset_table(); + // if (Event::should_send_event()) { + // ResourceMark rm; + + // KlassInfoTable cit(false); + // if (!cit.allocation_failed()) { + // HeapInspection hi; + // hi.populate_table(&cit, is_alive_cl, workers); + // ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); + // cit.iterate(&event_sender); + // } + // } +} + void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - - if (ObjectCountEventSender::should_send_event()) { + if (ObjectCountEventSender::should_send_event()) { ResourceMark rm; KlassInfoTable cit(false); if (!cit.allocation_failed()) { HeapInspection hi; hi.populate_table(&cit, is_alive_cl, workers); - ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); + // ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } } } + #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { @@ -187,3 +210,8 @@ void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { void OldGCTracer::report_concurrent_mode_failure() { send_concurrent_mode_failure_event(); } + +// #if INCLUDE_SERVICES +// template void GCTracer::report_object_count(KlassInfoTable*); +// template void GCTracer::report_object_count(KlassInfoTable*); +// #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 6a47e54090f88..d257f54ef36f1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -35,6 +35,7 @@ #include "memory/referenceType.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" +#include "memory/heapInspection.hpp" class GCHeapSummary; class MetaspaceChunkFreeListSummary; @@ -103,7 +104,10 @@ class GCTracer { void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const; void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; - void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; + + void report_object_count(KlassInfoTable* cit) NOT_SERVICES_RETURN; + + void report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; protected: diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp new file mode 100644 index 0000000000000..68dd721056f50 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -0,0 +1,35 @@ +#include "gc/shared/gcId.hpp" +#include "gc/shared/objectCountClosure.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" + +class KlassInfoEntry; +class Klass; + +KlassInfoTable ObjectCountClosure::cit(false); + +void ObjectCountClosure::reset_table() { + if (!check_table_exists()) { + return; + } + cit.~KlassInfoTable(); + ::new((void*)&cit) KlassInfoTable(false); +} + +bool ObjectCountClosure::check_table_exists() { + return !cit.allocation_failed(); +} + +bool ObjectCountClosure::record_object(oop o) { + if (!check_table_exists()) { + return false; + } + cit.record_instance(o); + return true; +} + +KlassInfoTable* ObjectCountClosure::get_table() { + return check_table_exists() ? &cit : nullptr; +} diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp new file mode 100644 index 0000000000000..684d8db45c7c5 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -0,0 +1,24 @@ +#ifndef SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP + +#include "gc/shared/gcId.hpp" +#include "gc/shared/objectCountEventSender.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" + +class KlassInfoEntry; +class Klass; + +class ObjectCountClosure : public ObjectCountEventSender { + static KlassInfoTable cit; + +public: + static bool check_table_exists(); + static bool record_object(oop o); + static KlassInfoTable* get_table(); + static void reset_table(); +}; + +#endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index a28c52e5c901d..fdbc307216b89 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -31,9 +31,10 @@ #include "utilities/ticks.hpp" #if INCLUDE_SERVICES +template bool ObjectCountEventSender::should_send_event() { #if INCLUDE_JFR - return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); + return _should_send_requestable_event || Event::is_enabled(); #else return false; #endif // INCLUDE_JFR @@ -63,13 +64,25 @@ void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, ju } } + +template void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) { Klass* klass = entry->klass(); jlong count = entry->count(); julong total_size = entry->words() * BytesPerWord; - send_event_if_enabled(klass, count, total_size, timestamp); - send_event_if_enabled(klass, count, total_size, timestamp); + send_event_if_enabled(klass, count, total_size, timestamp); + // If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount + // If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent + if (std::is_same::value && ObjectCountEventSender::should_send_event()) { + send_event_if_enabled(klass, count, total_size, timestamp); + } } +template bool ObjectCountEventSender::should_send_event(); +template bool ObjectCountEventSender::should_send_event(); + +template void ObjectCountEventSender::send(const KlassInfoEntry*, const Ticks&); +template void ObjectCountEventSender::send(const KlassInfoEntry*, const Ticks&); + #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 115fbfdaf7d3a..b05af2bb8b071 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -39,17 +39,21 @@ class Klass; class ObjectCountEventSender : public AllStatic { static bool _should_send_requestable_event; - template + template static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp); public: static void enable_requestable_event(); static void disable_requestable_event(); + template static void send(const KlassInfoEntry* entry, const Ticks& timestamp); + + template static bool should_send_event(); }; + #endif // INCLUDE_SERVICES #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp new file mode 100644 index 0000000000000..136977023f124 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -0,0 +1,122 @@ +// #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP +// #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP + +// #include "gc/shared/gcId.hpp" +// #include "jfr/jfrEvents.hpp" +// #include "memory/heapInspection.hpp" +// #include "utilities/macros.hpp" +// #include "utilities/ticks.hpp" +// #if INCLUDE_SERVICES + +// class KlassInfoEntry; +// class Klass; + +// template +// class ObjectCountEventSenderTemplate : public AllStatic { +// static bool _should_send_requestable_event; +// static KlassInfoTable cit; + +// template +// static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp); + +// public: +// static bool check_table_exists(); +// static KlassInfoTable* get_table(); +// static void reset_table(); + + +// static void enable_requestable_event(); +// static void disable_requestable_event(); +// static bool record_object_instance(oop o); + +// static void send(const KlassInfoEntry* entry, const Ticks& timestamp); +// static bool should_send_event(); +// }; + +// typedef ObjectCountEventSenderTemplate ObjectCountEventSender; +// typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; + +// template +// bool ObjectCountEventSenderTemplate::should_send_event() { +// #if INCLUDE_JFR +// return _should_send_requestable_event || Event::is_enabled(); +// #else +// return false; +// #endif // INCLUDE_JFR +// } + +// template +// bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; + +// template +// KlassInfoTable ObjectCountEventSenderTemplate::cit(false); + +// template +// void ObjectCountEventSenderTemplate::reset_table() { +// cit.~KlassInfoTable(); +// ::new((void*)&cit) KlassInfoTable(false); +// } + + +// template +// bool ObjectCountEventSenderTemplate::check_table_exists() { +// return !cit.allocation_failed(); +// } + +// template +// bool ObjectCountEventSenderTemplate::record_object_instance(oop o) { +// if (!check_table_exists()) { +// return false; +// } +// cit.record_instance(o); +// return true; +// } + +// template +// KlassInfoTable* ObjectCountEventSenderTemplate::get_table() { +// return &cit; +// } + + +// template +// void ObjectCountEventSenderTemplate::enable_requestable_event() { +// _should_send_requestable_event = true; +// } + + +// template +// void ObjectCountEventSenderTemplate::disable_requestable_event() { +// _should_send_requestable_event = false; +// } + +// template +// template +// void ObjectCountEventSenderTemplate::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) { +// T event(UNTIMED); +// if (event.should_commit()) { +// event.set_starttime(timestamp); +// event.set_endtime(timestamp); +// event.set_gcId(GCId::current()); +// event.set_objectClass(klass); +// event.set_count(count); +// event.set_totalSize(size); +// event.commit(); +// } +// } + +// template +// void ObjectCountEventSenderTemplate::send(const KlassInfoEntry* entry, const Ticks& timestamp) { +// Klass* klass = entry->klass(); +// jlong count = entry->count(); +// julong total_size = entry->words() * BytesPerWord; + +// send_event_if_enabled(klass, count, total_size, timestamp); +// // If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount +// // If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent +// if (std::is_same::value && ObjectCountEventSender::should_send_event()) { +// send_event_if_enabled(klass, count, total_size, timestamp); +// } +// } +// #endif // INCLUDE_SERVICES + +// #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 2f264cae70f19..578f1b67a4dbe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -28,6 +28,9 @@ #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/objectCountClosure.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -35,6 +38,7 @@ #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationalHeap.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahLock.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" @@ -770,6 +774,19 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } + // Efficient implementation: + { + KlassInfoTable* cit = ObjectCountClosure::get_table(); + heap->tracer()->report_object_count(cit); + } + + // Naive implementation: + // { + // ShenandoahIsAliveClosure is_alive; + // heap->tracer()->report_object_count_after_gc(&is_alive, heap->workers()); + // } + + if (!heap->cancelled_gc()) { _mark.finish_mark(); assert(!heap->cancelled_gc(), "STW mark cannot OOM"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 2dc0813e51354..5e3ee66a98d92 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -47,6 +47,7 @@ #include "runtime/prefetch.inline.hpp" #include "utilities/devirtualizer.inline.hpp" #include "utilities/powerOfTwo.hpp" +#include "gc/shared/objectCountClosure.hpp" template void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) { @@ -365,6 +366,9 @@ inline void ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, marked = mark_context->mark_strong(obj, /* was_upgraded = */ skip_live); } if (marked) { + if (ObjectCountClosure::should_send_event()) { + ObjectCountClosure::record_object(obj); + } bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); } diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c08..62b2b4dff47cc 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -34,6 +34,7 @@ #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 5ffdc8d9e4dbf..d7b7b6e1921ad 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -360,7 +360,7 @@ - false + true diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java new file mode 100644 index 0000000000000..30d9e141d8285 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -0,0 +1,67 @@ +package jdk.jfr.event.gc.objectcount; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +public class ObjectCountEvent { + private static final String objectCountEventPath = EventNames.ObjectCount; + private static final String gcEventPath = EventNames.GarbageCollection; + private static final String heapSummaryEventPath = EventNames.GCHeapSummary; + + public static void test(String gcName) throws Exception { + Recording recording = new Recording(); + recording.enable(objectCountEventPath); + recording.enable(gcEventPath); + recording.enable(heapSummaryEventPath); + + ObjectCountEventVerifier.createTestData(); + recording.start(); + + Path tempFile = Path.of("temp.jfr"); + recording.dump(tempFile); // Forces chunk rotation + System.gc(); + recording.stop(); + + Files.deleteIfExists(tempFile); + + System.out.println("gcName=" + gcName); + List events = Events.fromRecording(recording); + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + } + + Optional gcEvent = events.stream() + .filter(e -> isMySystemGc(e, gcName)) + .findFirst(); + + List objCountEvents = events.stream() + .filter(e -> Events.isEventType(e, objectCountEventPath)) + .collect(Collectors.toList()); + Asserts.assertFalse(objCountEvents.isEmpty(), "No objCountEvents"); + + Optional heapSummaryEvent = events.stream() + .filter(e -> Events.isEventType(e, heapSummaryEventPath)) + .filter(e -> "After GC".equals(Events.assertField(e, "when").getValue())) + .findFirst(); + Asserts.assertTrue(heapSummaryEvent.isPresent(), "No heapSummary"); + System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get()); + + Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue(); + ObjectCountEventVerifier.verify(objCountEvents); + } + + private static boolean isMySystemGc(RecordedEvent event, String gcName) { + return Events.isEventType(event, gcEventPath) && + gcName.equals(Events.assertField(event, "name").getValue()) && + "System.gc()".equals(Events.assertField(event, "cause").getValue()); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java new file mode 100644 index 0000000000000..cd70c05239ccb --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java @@ -0,0 +1,22 @@ +package jdk.jfr.event.gc.objectcount; + +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (vm.gc == "G1" | vm.gc == null) + * & vm.opt.ExplicitGCInvokesConcurrent != true + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:MarkSweepDeadRatio=0 + * -XX:-UseCompressedOops -XX:-UseCompressedClassPointers + * -XX:+IgnoreUnrecognizedVMOptions + * jdk.jfr.event.gc.objectcount.TestObjectCountEventWithG1FullCollection + */ +public class TestObjectCountEventWithG1FullCollection { + public static void main(String[] args) throws Exception { + ObjectCountEvent.test(GCHelper.gcG1Full); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java new file mode 100644 index 0000000000000..421c356a31579 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java @@ -0,0 +1,21 @@ +package jdk.jfr.event.gc.objectcount; + +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires vm.gc == "Parallel" | vm.gc == null + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC + * -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops + * -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions + * jdk.jfr.event.gc.objectcount.TestObjectCountEventWithParallelOld + */ +public class TestObjectCountEventWithParallelOld { + public static void main(String[] args) throws Exception { + ObjectCountEvent.test(GCHelper.gcParallelOld); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java new file mode 100644 index 0000000000000..3191ebb43d3f2 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java @@ -0,0 +1,17 @@ +package jdk.jfr.event.gc.objectcount; +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (vm.gc == "Shenandoah" | vm.gc == null) + * & vm.opt.ExplicitGCInvokesConcurrent != false + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEventWithShenandoah + */ +public class TestObjectCountEventWithShenandoah { + public static void main(String[] args) throws Exception { + ObjectCountEvent.test(GCHelper.gcShenandoah); + } +} diff --git a/test/lib/jdk/test/lib/jfr/GCHelper.java b/test/lib/jdk/test/lib/jfr/GCHelper.java index 07c6c1e1ce550..4b30e79ba0d43 100644 --- a/test/lib/jdk/test/lib/jfr/GCHelper.java +++ b/test/lib/jdk/test/lib/jfr/GCHelper.java @@ -74,6 +74,7 @@ public class GCHelper { public static final String gcPSMarkSweep = "PSMarkSweep"; public static final String gcParallelOld = "ParallelOld"; public static final String pauseLevelEvent = "GCPhasePauseLevel"; + public static final String gcShenandoah = "Shenandoah"; private static final List g1HeapRegionTypes; private static final List shenandoahHeapRegionStates;