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         final long shenandoahMaxHeapRegionCount = 64;
 53         Recording recording = new Recording();
 54         recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0));
 55         recording.start();
 56         allocate();
 57         recording.stop();
 58 
 59         List<RecordedEvent> events = Events.fromRecording(recording);
 60         Asserts.assertFalse(events.isEmpty(), "No events found");
 61         for (RecordedEvent event : events) {
 62             if (!Events.isEventType(event, EVENT_NAME)) {
 63                 continue;
 64             }
 65             System.out.println("Event: " + event);
 66 
 67             long cSetRegions = Events.assertField(event, "cSetRegions").atLeast(0L).getValue();
 68             long setUsedAfter = Events.assertField(event, "cSetUsedAfter").atLeast(0L).getValue();
 69             long setUsedBefore = Events.assertField(event, "cSetUsedBefore").atLeast(setUsedAfter).getValue();
 70             long freeRegions = Events.assertField(event, "freeRegions").atLeast(0L).getValue();
 71             Events.assertField(event, "collectedOld").atLeast(0L).getValue();
 72             Events.assertField(event, "collectedYoung").atLeast(0L).getValue();
 73 
 74             Asserts.assertGreaterThanOrEqual(shenandoahMaxHeapRegionCount, freeRegions + cSetRegions, "numRegions >= freeRegions + cSetRegions");
 75             Asserts.assertGreaterThanOrEqual(shenandoahHeapRegionSize * cSetRegions, setUsedAfter, "ShenandoahHeapRegionSize * cSetRegions >= setUsedAfter");
 76             Asserts.assertGreaterThanOrEqual(shenandoahHeapRegionSize * cSetRegions, setUsedBefore, "ShenandoahHeapRegionSize * cSetRegions >= setUsedBefore");
 77 
 78             int gcId = Events.assertField(event, "gcId").getValue();
 79         }
 80     }
 81 
 82     /**
 83      * Allocate memory to trigger garbage collections.
 84      * We want the allocated objects to have different life time, because we want both "young" and "old" objects.
 85      * This is done by keeping the objects in an array and step the current index by a small random number in the loop.
 86      * The loop will continue until we have allocated a fixed number of bytes.
 87      */
 88     private static void allocate() {
 89         DummyObject[] dummys = new DummyObject[6000];
 90 
 91         Random r = new Random(0);
 92         long bytesToAllocate = 256 * 1024 * 1024;
 93         int currPos = 0;
 94         while (bytesToAllocate > 0) {
 95             int allocSize = 1000 + (r.nextInt(4000));
 96             bytesToAllocate -= allocSize;
 97             dummys[currPos] = new DummyObject(allocSize);
 98 
 99             // Skip a few positions to get different duration on the objects.
100             currPos = (currPos + r.nextInt(20)) % dummys.length;
101         }
102         for (int c=0; c<dummys.length; c++) {
103             dummys[c] = null;
104         }
105         System.gc();
106     }
107 
108     public static class DummyObject {
109         public byte[] payload;
110         DummyObject(int size) {
111             payload = new byte[size];
112         }
113     }
114 }