--- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-05-14 16:14:47.498130708 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-05-14 16:14:47.199132806 -0400 @@ -66,6 +66,10 @@ #include "gc/shenandoah/heuristics/shenandoahPassiveHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahStaticHeuristics.hpp" #include "gc/shenandoah/heuristics/shenandoahTraversalHeuristics.hpp" +#if INCLUDE_JFR +#include "gc/shenandoah/shenandoahJfrSupport.hpp" +#endif + #include "memory/metaspace.hpp" #include "oops/compressedOops.inline.hpp" #include "runtime/globals.hpp" @@ -583,6 +587,8 @@ ref_processing_init(); _heuristics->initialize(); + + JFR_ONLY(ShenandoahJFRSupport::register_jfr_type_serializers()); } size_t ShenandoahHeap::used() const { --- old/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp 2019-05-14 16:14:48.082126610 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp 2019-05-14 16:14:47.784128701 -0400 @@ -30,6 +30,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahTraversalGC.hpp" #include "gc/shared/space.inline.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -93,7 +94,7 @@ case _empty_uncommitted: do_commit(); case _empty_committed: - _state = _regular; + set_state(_regular); case _regular: case _pinned: return; @@ -114,10 +115,10 @@ case _cset: case _humongous_start: case _humongous_cont: - _state = _regular; + set_state(_regular); return; case _pinned_cset: - _state = _pinned; + set_state(_pinned); return; case _regular: case _pinned: @@ -133,7 +134,7 @@ case _empty_uncommitted: do_commit(); case _empty_committed: - _state = _humongous_start; + set_state(_humongous_start); return; default: report_illegal_transition("humongous start allocation"); @@ -149,7 +150,7 @@ case _regular: case _humongous_start: case _humongous_cont: - _state = _humongous_start; + set_state(_humongous_start); return; default: report_illegal_transition("humongous start bypass"); @@ -162,7 +163,7 @@ case _empty_uncommitted: do_commit(); case _empty_committed: - _state = _humongous_cont; + set_state(_humongous_cont); return; default: report_illegal_transition("humongous continuation allocation"); @@ -178,7 +179,7 @@ case _regular: case _humongous_start: case _humongous_cont: - _state = _humongous_cont; + set_state(_humongous_cont); return; default: report_illegal_transition("humongous continuation bypass"); @@ -190,14 +191,14 @@ switch (_state) { case _regular: assert (_critical_pins == 0, "sanity"); - _state = _pinned; + set_state(_pinned); case _pinned_cset: case _pinned: _critical_pins++; return; case _humongous_start: assert (_critical_pins == 0, "sanity"); - _state = _pinned_humongous_start; + set_state(_pinned_humongous_start); case _pinned_humongous_start: _critical_pins++; return; @@ -219,7 +220,7 @@ assert (_critical_pins > 0, "sanity"); _critical_pins--; if (_critical_pins == 0) { - _state = _regular; + set_state(_regular); } return; case _regular: @@ -231,14 +232,14 @@ assert (_critical_pins > 0, "sanity"); _critical_pins--; if (_critical_pins == 0) { - _state = _cset; + set_state(_cset); } return; case _pinned_humongous_start: assert (_critical_pins > 0, "sanity"); _critical_pins--; if (_critical_pins == 0) { - _state = _humongous_start; + set_state(_humongous_start); } return; default: @@ -250,7 +251,7 @@ _heap->assert_heaplock_owned_by_current_thread(); switch (_state) { case _regular: - _state = _cset; + set_state(_cset); case _cset: return; default: @@ -268,7 +269,7 @@ // Reclaiming humongous regions case _regular: // Immediate region reclaim - _state = _trash; + set_state(_trash); return; default: report_illegal_transition("trashing"); @@ -287,7 +288,7 @@ _heap->assert_heaplock_owned_by_current_thread(); switch (_state) { case _trash: - _state = _empty_committed; + set_state(_empty_committed); _empty_time = os::elapsedTime(); return; default: @@ -300,7 +301,7 @@ switch (_state) { case _empty_committed: do_uncommit(); - _state = _empty_uncommitted; + set_state(_empty_uncommitted); return; default: report_illegal_transition("uncommiting"); @@ -314,7 +315,7 @@ switch (_state) { case _empty_uncommitted: do_commit(); - _state = _empty_committed; + set_state(_empty_committed); return; default: report_illegal_transition("commit bypass"); @@ -679,3 +680,16 @@ } _heap->decrease_committed(ShenandoahHeapRegion::region_size_bytes()); } + +void ShenandoahHeapRegion::set_state(RegionState to) { + EventShenandoahHeapRegionStateChange evt; + if (evt.should_commit()){ + evt.set_index(region_number()); + evt.set_start((uintptr_t)bottom()); + evt.set_used(used()); + evt.set_from(_state); + evt.set_to(to); + evt.commit(); + } + _state = to; +} --- old/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp 2019-05-14 16:14:48.650122624 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp 2019-05-14 16:14:48.354124701 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -32,9 +32,11 @@ #include "utilities/sizes.hpp" class VMStructs; +class ShenandoahHeapRegionStateConstant; class ShenandoahHeapRegion : public ContiguousSpace { friend class VMStructs; + friend class ShenandoahHeapRegionStateConstant; private: /* Region state is described by a state machine. Transitions are guarded by @@ -115,9 +117,10 @@ _pinned, // region is pinned _pinned_cset, // region is pinned and in cset (evac failure path) _trash, // region contains only trash + _REGION_STATES_NUM, // last }; - const char* region_state_to_string(RegionState s) const { + static const char* region_state_to_string(RegionState s) { switch (s) { case _empty_uncommitted: return "Empty Uncommitted"; case _empty_committed: return "Empty Committed"; @@ -157,6 +160,10 @@ void report_illegal_transition(const char* method); public: + static const int region_states_num() { + return _REGION_STATES_NUM; + } + // Allowed transitions from the outside code: void make_regular_allocation(); void make_regular_bypass(); @@ -424,6 +431,8 @@ void oop_iterate_humongous(OopIterateClosure* cl); inline void internal_increase_live_data(size_t s); + + void set_state(RegionState to); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAPREGION_HPP --- old/src/hotspot/share/jfr/metadata/metadata.xml 2019-05-14 16:14:49.214118667 -0400 +++ new/src/hotspot/share/jfr/metadata/metadata.xml 2019-05-14 16:14:48.916120758 -0400 @@ -979,6 +979,27 @@ + + + + + + + + + + + + + + + + + + + --- old/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp 2019-05-14 16:14:49.784114667 -0400 +++ new/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp 2019-05-14 16:14:49.489116737 -0400 @@ -65,7 +65,9 @@ #include "services/threadService.hpp" #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" - +#if INCLUDE_SHENANDOAHGC +#include "gc/shenandoah/shenandoahJfrSupport.hpp" +#endif /** * JfrPeriodic class * Implementation of declarations in @@ -620,3 +622,14 @@ event.set_flushingEnabled(UseCodeCacheFlushing); event.commit(); } + + +TRACE_REQUEST_FUNC(ShenandoahHeapRegionInformation) { +#if INCLUDE_SHENANDOAHGC + if (UseShenandoahGC) { + VM_ShenandoahSendHeapRegionInfoEvents op; + VMThread::execute(&op); + } +#endif +} + --- old/src/jdk.jfr/share/conf/jfr/default.jfc 2019-05-14 16:14:50.352110681 -0400 +++ new/src/jdk.jfr/share/conf/jfr/default.jfc 2019-05-14 16:14:50.054112772 -0400 @@ -444,6 +444,15 @@ false + + + false + everyChunk + + + + false + true --- old/src/jdk.jfr/share/conf/jfr/profile.jfc 2019-05-14 16:14:50.922106681 -0400 +++ new/src/jdk.jfr/share/conf/jfr/profile.jfc 2019-05-14 16:14:50.621108794 -0400 @@ -445,6 +445,15 @@ false + + false + everyChunk + + + + false + + true true --- old/test/lib/jdk/test/lib/jfr/EventNames.java 2019-05-14 16:14:51.485102731 -0400 +++ new/test/lib/jdk/test/lib/jfr/EventNames.java 2019-05-14 16:14:51.190104801 -0400 @@ -101,6 +101,8 @@ public final static String G1HeapSummary = PREFIX + "G1HeapSummary"; public final static String G1HeapRegionInformation = PREFIX + "G1HeapRegionInformation"; public final static String G1HeapRegionTypeChange = PREFIX + "G1HeapRegionTypeChange"; + public final static String ShenandoahHeapRegionInformation = PREFIX + "ShenandoahHeapRegionInformation"; + public final static String ShenandoahHeapRegionStateChange = PREFIX + "ShenandoahHeapRegionStateChange"; public final static String TenuringDistribution = PREFIX + "TenuringDistribution"; public final static String GarbageCollection = PREFIX + "GarbageCollection"; public final static String ParallelOldGarbageCollection = PREFIX + "ParallelOldGarbageCollection"; --- old/test/lib/jdk/test/lib/jfr/GCHelper.java 2019-05-14 16:14:52.046098794 -0400 +++ new/test/lib/jdk/test/lib/jfr/GCHelper.java 2019-05-14 16:14:51.751100864 -0400 @@ -80,6 +80,7 @@ public static final String pauseLevelEvent = "GCPhasePauseLevel"; private static final List g1HeapRegionTypes; + private static final List shenandoahHeapRegionStates; private static PrintStream defaultErrorLog = null; public static int getGcId(RecordedEvent event) { @@ -207,6 +208,21 @@ }; g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals)); + + String[] shenandoahHeapRegionStateLiterals = new String[] { + "Empty Uncommitted", + "Empty Committed", + "Regular", + "Humongous Start", + "Humongous Continuation", + "Humonguous Start, Pinned", + "Collection Set", + "Pinned", + "Collection Set, Pinned", + "Trash" + }; + + shenandoahHeapRegionStates = Collections.unmodifiableList(Arrays.asList(shenandoahHeapRegionStateLiterals)); } /** @@ -443,6 +459,13 @@ return g1HeapRegionTypes.contains(type); } + public static boolean assertIsValidShenandoahHeapRegionState(final String state) { + if (!shenandoahHeapRegionStates.contains(state)) { + throw new AssertionError("Unknown state '" + state + "', valid heap region states are " + shenandoahHeapRegionStates); + } + return true; + } + /** * Helper function to align heap size up. * --- /dev/null 2019-05-13 11:42:57.167211276 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp 2019-05-14 16:14:52.320096871 -0400 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahJfrSupport.hpp" +#include "jfr/jfrEvents.hpp" +#if INCLUDE_JFR +#include "jfr/metadata/jfrSerializer.hpp" +#endif + +#if INCLUDE_JFR + +class ShenandoahHeapRegionStateConstant : public JfrSerializer { + friend class ShenandoahHeapRegion; +public: + virtual void serialize(JfrCheckpointWriter& writer) { + static const u4 nof_entries = ShenandoahHeapRegion::region_states_num(); + writer.write_count(nof_entries); + for (u4 i = 0; i < nof_entries; ++i) { + writer.write_key(i); + writer.write(ShenandoahHeapRegion::region_state_to_string((ShenandoahHeapRegion::RegionState)i)); + } + } +}; + +void ShenandoahJFRSupport::register_jfr_type_serializers() { + JfrSerializer::register_serializer(TYPE_SHENANDOAHHEAPREGIONSTATE, + false, + true, + new ShenandoahHeapRegionStateConstant()); +} +#endif + +class ShenandoahDumpHeapRegionInfoClosure : public ShenandoahHeapRegionClosure { +public: + virtual void heap_region_do(ShenandoahHeapRegion* r) { + EventShenandoahHeapRegionInformation evt; + evt.set_index(r->region_number()); + evt.set_state((u8)r->state()); + evt.set_start((uintptr_t)r->bottom()); + evt.set_used(r->used()); + evt.commit(); + } +}; + +void VM_ShenandoahSendHeapRegionInfoEvents::doit() { + ShenandoahDumpHeapRegionInfoClosure c; + ShenandoahHeap::heap()->heap_region_iterate(&c); +} --- /dev/null 2019-05-13 11:42:57.167211276 -0400 +++ new/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.hpp 2019-05-14 16:14:52.898092816 -0400 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + * 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. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP + +#include "runtime/vmOperations.hpp" + +class VM_ShenandoahSendHeapRegionInfoEvents : public VM_Operation { +public: + virtual void doit(); + virtual VMOp_Type type() const { return VMOp_HeapIterateOperation; } +}; + +class ShenandoahJFRSupport { +public: + static void register_jfr_type_serializers(); +}; + +#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHJFRSUPPORT_HPP --- /dev/null 2019-05-13 11:42:57.167211276 -0400 +++ new/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahHeapRegionInformationEvent.java 2019-05-14 16:14:53.480088731 -0400 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + * 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.event.gc.detailed; + +import java.nio.file.Paths; +import java.util.List; + +import jdk.jfr.EventType; +import jdk.jfr.FlightRecorder; +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; +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @bug 8221507 + * @requires vm.hasJFR + * @requires vm.gc == "Shenandoah" | vm.gc == null + * @key jfr + * @library /test/lib /test/jdk + * @run main/othervm -Xmx32m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGarbageThreshold=1 jdk.jfr.event.gc.detailed.TestShenandoahHeapRegionInformationEvent + */ + + +public class TestShenandoahHeapRegionInformationEvent { + private final static String EVENT_NAME = EventNames.ShenandoahHeapRegionInformation; + public static void main(String[] args) throws Exception { + Recording recording = null; + try { + recording = new Recording(); + // activate the event we are interested in and start recording + for (EventType t : FlightRecorder.getFlightRecorder().getEventTypes()) { + System.out.println(t.getName()); + } + recording.enable(EVENT_NAME); + recording.start(); + recording.stop(); + + // Verify recording + List events = Events.fromRecording(recording); + Events.hasEvents(events); + for (RecordedEvent event : events) { + Events.assertField(event, "index").notEqual(-1); + GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "state").getValue()); + Events.assertField(event, "used").atMost(1L*1024*1024); + } + } finally { + if (recording != null) { + recording.close(); + } + } + } +} --- /dev/null 2019-05-13 11:42:57.167211276 -0400 +++ new/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahHeapRegionStateChangeEvent.java 2019-05-14 16:14:54.056084690 -0400 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + * 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.event.gc.detailed; + +import java.nio.file.Paths; +import java.time.Duration; +import java.util.List; + +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; +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @bug 8221507 + * @requires vm.hasJFR + * @requires vm.gc == "Shenandoah" | vm.gc == null + * @key jfr + * @library /test/lib /test/jdk + * @run main/othervm -Xmx32m -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahGarbageThreshold=1 jdk.jfr.event.gc.detailed.TestShenandoahHeapRegionStateChangeEvent + */ + +public class TestShenandoahHeapRegionStateChangeEvent { + private final static String EVENT_NAME = EventNames.ShenandoahHeapRegionStateChange; + + public static void main(String[] args) throws Exception { + Recording recording = null; + try { + recording = new Recording(); + // activate the event we are interested in and start recording + recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0)); + recording.start(); + + byte[][] array = new byte[1024][]; + for (int i = 0; i < array.length; i++) { + array[i] = new byte[20 * 1024]; + } + recording.stop(); + + // Verify recording + List events = Events.fromRecording(recording); + Asserts.assertFalse(events.isEmpty(), "No events found"); + + for (RecordedEvent event : events) { + Events.assertField(event, "index").notEqual(-1); + GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "from").getValue()); + GCHelper.assertIsValidShenandoahHeapRegionState(Events.assertField(event, "to").getValue()); + Events.assertField(event, "used").atMost(1L*1024*1024); + } + } finally { + if (recording != null) { + recording.close(); + } + } + } +}