1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
   4  */
   5 
   6 import java.util.ArrayList;
   7 import java.util.HashSet;
   8 import java.util.List;
   9 import java.util.Random;
  10 import java.util.Set;
  11 import java.util.regex.Pattern;
  12 import jrockit.Asserts;
  13 import jrockit.jfr.TestRecording;
  14 import oracle.jrockit.jfr.parser.FLREvent;
  15 import static jrockit.Asserts.*;
  16 
  17 /*
  18  * @test
  19  * @key jfr
  20  * @library ../common
  21  * @build jrockit.jfr.ParseHelper
  22  * @run main/othervm -XX:G1HeapRegionSize=1m -Xmx64m -Xmn16m -XX:+UnlockCommercialFeatures -XX:+UseG1GC -XX:+FlightRecorder -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestEvacuationInfoEvent
  23  */
  24 public class TestEvacuationInfoEvent {
  25     private final static String EVENT_INFO_PATH = "vm/gc/detailed/evacuation_info";
  26     private final static String EVENT_FAILED_PATH = "vm/gc/detailed/evacuation_failed";
  27 
  28     public static List<DummyObject> dummyList;
  29 
  30     public static void main(String[] args) throws Throwable {
  31         TestRecording r = new TestRecording();
  32         final long g1HeapRegionSize = 1024 * 1024;
  33         try {
  34             r.createJVMSetting(EVENT_INFO_PATH, true, false, 0, 0);
  35             r.createJVMSetting(EVENT_FAILED_PATH, true, false, 0, 0);
  36             r.start();
  37             allocate();
  38             r.stop();
  39             String regexpPattern = String.format("(%s)|(%s)", EVENT_INFO_PATH, EVENT_FAILED_PATH);
  40             List<FLREvent> all = r.parser().findJVMEvents(Pattern.compile(regexpPattern));
  41             Asserts.assertFalse(all.isEmpty(), String.format("No events of type '%s' found", EVENT_INFO_PATH));
  42 
  43             // Save gcIds for all EvacuationFailedEvents. These will be used to verify the EvacuationInfo event.
  44             Set<Long> failedEvacuationGcIds = new HashSet<Long>();
  45             for (FLREvent event : all) {
  46                 if (EVENT_FAILED_PATH.equals(event.getPath())) {
  47                     failedEvacuationGcIds.add((Long)event.getValue("gcId"));
  48                 }
  49             }
  50 
  51             for (FLREvent event : all) {
  52                 if (EVENT_INFO_PATH.equals(event.getPath())) {
  53                     int setRegions = ((Integer)event.getValue("cSetRegions")).intValue();
  54                     long setUsedBefore = ((Long)event.getValue("cSetUsedBefore")).longValue();
  55                     long setUsedAfter = ((Long)event.getValue("cSetUsedAfter")).longValue();
  56                     int allocationRegions = ((Integer)event.getValue("allocationRegions")).intValue();
  57                     long allocRegionsUsedBefore = ((Long)event.getValue("allocRegionsUsedBefore")).longValue();
  58                     long allocRegionsUsedAfter = ((Long)event.getValue("allocRegionsUsedAfter")).longValue();
  59                     long bytesCopied = ((Long)event.getValue("bytesCopied")).longValue();
  60                     int regionsFreed = ((Integer)event.getValue("regionsFreed")).intValue();
  61 
  62                     try {
  63                         assertGreaterOrEqualThan(setRegions, 0, "setRegions >= 0");
  64                         assertGreaterOrEqualThan(setUsedBefore, 0L, "setUsedBefore>= 0");
  65                         assertGreaterOrEqualThan(setUsedAfter, 0L, "setUsedAfter >= 0");
  66                         assertGreaterOrEqualThan(allocationRegions, 0, "allocationRegions >= 0");
  67                         assertGreaterOrEqualThan(allocRegionsUsedBefore, 0L, "allocRegionsUsedBefore >= 0");
  68                         assertGreaterOrEqualThan(allocRegionsUsedAfter, 0L, "allocRegionsUsedAfter >= 0");
  69                         assertGreaterOrEqualThan(bytesCopied, 0L, "bytesCopied >= 0");
  70                         assertGreaterOrEqualThan(regionsFreed, 0, "regionsFreed >= 0");
  71 
  72                         assertGreaterOrEqualThan(setUsedBefore, setUsedAfter, "setUsedBefore >= setUsedAfter");
  73                         assertEquals(allocRegionsUsedBefore + bytesCopied, allocRegionsUsedAfter, "allocRegionsUsedBefore + bytesCopied = allocRegionsUsedAfter");
  74                         assertGreaterOrEqualThan(setRegions, regionsFreed, "setRegions >= regionsFreed");
  75                         assertGreaterOrEqualThan(g1HeapRegionSize * allocationRegions, allocRegionsUsedAfter, "G1HeapRegionSize * allocationRegions >= allocationRegionsUsedAfter");
  76                         assertGreaterOrEqualThan(g1HeapRegionSize * setRegions, setUsedAfter, "G1HeapRegionSize * setRegions >= setUsedAfter");
  77                         assertGreaterOrEqualThan(g1HeapRegionSize * setRegions, setUsedBefore, "G1HeapRegionSize * setRegions >= setUsedBefore");
  78                         assertGreaterOrEqualThan(g1HeapRegionSize, allocRegionsUsedBefore, "G1HeapRegionSize >= allocRegionsUsedBefore");
  79                         if (failedEvacuationGcIds.contains((Long)event.getValue("gcId"))) {
  80                             assertGreaterThan(setUsedAfter, 0L, "EvacuationFailure -> setUsedAfter > 0");
  81                             assertGreaterThan(setRegions, regionsFreed, "EvacuationFailure -> setRegions > regionsFreed");
  82                         } else {
  83                             assertEquals(setUsedAfter, 0L, "No EvacuationFailure -> setUsedAfter = 0");
  84                             assertEquals(setRegions, regionsFreed, "No EvacuationFailure -> setRegions = regionsFreed");
  85                         }
  86                     } catch (Throwable t) {
  87                         System.out.println("Failed event:");
  88                         System.out.println(event.toString());
  89                         throw t;
  90                     }
  91                 }
  92             }
  93         } catch (Throwable e) {
  94             e.printStackTrace();
  95             r.copyTo("TestEvacuationInfoEvent_failed.jfr");
  96             throw e;
  97         } finally {
  98             r.close();
  99         }
 100     }
 101 
 102     /**
 103      * Allocate memory to trigger garbage collections.
 104      * We want the allocated objects to have different life time, because we want both "young" and "old" objects.
 105      * This is done by keeping the objects in an array and step the current index by a small random number in the loop.
 106      * The loop will continue until we have allocated a fixed number of bytes.
 107      */
 108     private static void allocate() {
 109         Random r = new Random(0);
 110         final int arraySize = 6000;
 111         dummyList = new ArrayList<DummyObject>(arraySize);
 112         for (int c=0; c<arraySize; c++) {
 113             dummyList.add(null);
 114         }
 115         long bytesToAllocate = 256 * 1024 * 1024;
 116         int currPos = 0;
 117         while (bytesToAllocate > 0) {
 118             try {
 119                 int nextAlloc = 1000 + (r.nextInt(4000));
 120                 bytesToAllocate -= nextAlloc;
 121                 dummyList.set(currPos, new DummyObject(nextAlloc));
 122 
 123                 // Skip a few positions to get different duration on the objects.
 124                 currPos += r.nextInt(20);
 125                 if (currPos >= arraySize) {
 126                     currPos = 0;
 127                 }
 128             } catch (OutOfMemoryError e) {
 129                 // We should not get an OOM, but if we do, just clear the dummyList.
 130                 dummyList = null;
 131                 System.gc();
 132                 dummyList = new ArrayList<DummyObject>(arraySize);
 133                 for (int c=0; c<arraySize; c++) {
 134                     dummyList.add(null);
 135                 }
 136             }
 137         }
 138         dummyList = null;
 139         System.gc();
 140     }
 141 
 142     private static class DummyObject {
 143         public byte[] payload;
 144         DummyObject(int size) {
 145             payload = new byte[size];
 146         }
 147     }
 148 }
 149