1 /*
  2  * Copyright Amazon.com Inc. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 package jdk.jfr.event.gc.detailed;
 26 
 27 import java.time.Duration;
 28 import java.util.List;
 29 import java.util.Random;
 30 
 31 import jdk.jfr.Recording;
 32 import jdk.jfr.consumer.RecordedEvent;
 33 import jdk.test.lib.Asserts;
 34 import jdk.test.lib.jfr.EventNames;
 35 import jdk.test.lib.jfr.Events;
 36 import jdk.test.lib.jfr.GCHelper;
 37 
 38 /**
 39  * @test
 40  * @bug 8221507
 41  * @requires vm.hasJFR & vm.gc.Shenandoah
 42  * @key jfr
 43  * @library /test/lib /test/jdk
 44  * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational jdk.jfr.event.gc.detailed.TestShenandoahEvacuationInformationEvent
 45  */
 46 
 47 public class TestShenandoahEvacuationInformationEvent {
 48     private final static String EVENT_NAME = EventNames.ShenandoahEvacuationInformation;
 49 
 50     public static void main(String[] args) throws Exception {
 51         final long shenandoahHeapRegionSize = 1024 * 1024;
 52         Recording recording = new Recording();
 53         recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
 54         recording.start();
 55         allocate();
 56         recording.stop();
 57 
 58         List<RecordedEvent> events = Events.fromRecording(recording);
 59         Asserts.assertFalse(events.isEmpty(), "No events found");
 60         for (RecordedEvent event : events) {
 61             if (!Events.isEventType(event, EVENT_NAME)) {
 62                 continue;
 63             }
 64             System.out.println("Event: " + event);
 65 
 66             long setRegions = Events.assertField(event, "cSetRegions").atLeast(0L).getValue();
 67             long setUsedAfter = Events.assertField(event, "cSetUsedAfter").atLeast(0L).getValue();
 68             long setUsedBefore = Events.assertField(event, "cSetUsedBefore").atLeast(setUsedAfter).getValue();
 69             long regionsFreed = Events.assertField(event, "regionsFreed").atLeast(0L).getValue();
 70             Events.assertField(event, "collectedOld").atLeast(0L).getValue();
 71             Events.assertField(event, "collectedYoung").atLeast(0L).getValue();
 72 
 73             Asserts.assertGreaterThanOrEqual(setRegions, regionsFreed, "setRegions >= regionsFreed");
 74             Asserts.assertGreaterThanOrEqual(shenandoahHeapRegionSize * setRegions, setUsedAfter, "ShenandoahHeapRegionSize * setRegions >= setUsedAfter");
 75             Asserts.assertGreaterThanOrEqual(shenandoahHeapRegionSize * setRegions, setUsedBefore, "ShenandoahHeapRegionSize * setRegions >= setUsedBefore");
 76 
 77             int gcId = Events.assertField(event, "gcId").getValue();
 78         }
 79     }
 80 
 81     /**
 82      * Allocate memory to trigger garbage collections.
 83      * We want the allocated objects to have different life time, because we want both "young" and "old" objects.
 84      * This is done by keeping the objects in an array and step the current index by a small random number in the loop.
 85      * The loop will continue until we have allocated a fixed number of bytes.
 86      */
 87     private static void allocate() {
 88         DummyObject[] dummys = new DummyObject[6000];
 89 
 90         Random r = new Random(0);
 91         long bytesToAllocate = 256 * 1024 * 1024;
 92         int currPos = 0;
 93         while (bytesToAllocate > 0) {
 94             int allocSize = 1000 + (r.nextInt(4000));
 95             bytesToAllocate -= allocSize;
 96             dummys[currPos] = new DummyObject(allocSize);
 97 
 98             // Skip a few positions to get different duration on the objects.
 99             currPos = (currPos + r.nextInt(20)) % dummys.length;
100         }
101         for (int c=0; c<dummys.length; c++) {
102             dummys[c] = null;
103         }
104         System.gc();
105     }
106 
107     public static class DummyObject {
108         public byte[] payload;
109         DummyObject(int size) {
110             payload = new byte[size];
111         }
112     }
113 }