hotspot/test/gc/g1/humongousObjects/TestHeapCounters.java
changeset 35933 e7a76427c582
child 38152 80e5da81fb2c
equal deleted inserted replaced
35932:511dd7b5313b 35933:e7a76427c582
       
     1 /*
       
     2  * Copyright (c) 2016, Oracle and/or its affiliates. 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 gc.g1.humongousObjects;
       
    26 
       
    27 import gc.testlibrary.Helpers;
       
    28 import jdk.test.lib.Asserts;
       
    29 import sun.hotspot.WhiteBox;
       
    30 
       
    31 import java.lang.management.GarbageCollectorMXBean;
       
    32 import java.lang.management.ManagementFactory;
       
    33 import java.util.ArrayList;
       
    34 import java.util.Arrays;
       
    35 import java.util.List;
       
    36 
       
    37 /**
       
    38  * @test TestHeapCounters
       
    39  * @summary Checks that heap counters work as expected after humongous allocations/deallocations
       
    40  * @requires vm.gc=="G1" | vm.gc=="null"
       
    41  * @library /testlibrary /test/lib /
       
    42  * @modules java.management
       
    43  * @build sun.hotspot.WhiteBox
       
    44  *        gc.testlibrary.Helpers
       
    45  *        gc.g1.humongousObjects.TestHeapCounters
       
    46  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
       
    47  *             sun.hotspot.WhiteBox$WhiteBoxPermission
       
    48  *
       
    49  * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
       
    50  *                   -Xmx128m -Xms128m
       
    51  *                   -XX:G1HeapRegionSize=1M -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP
       
    52  *                   -Xlog:gc -Xlog:gc:file=TestHeapCountersRuntime.gc.log
       
    53  *                    gc.g1.humongousObjects.TestHeapCounters RUNTIME_COUNTER
       
    54  *
       
    55  * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
       
    56  *                   -Xmx128m -Xms128m
       
    57  *                   -XX:G1HeapRegionSize=1M -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP
       
    58  *                   -Xlog:gc -Xlog:gc:file=TestHeapCountersMXBean.gc.log
       
    59  *                    gc.g1.humongousObjects.TestHeapCounters MX_BEAN_COUNTER
       
    60  */
       
    61 public class TestHeapCounters {
       
    62     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
       
    63     private static final int G1_REGION_SIZE = WHITE_BOX.g1RegionSize();
       
    64     private static final int HALF_G1_REGION_SIZE = G1_REGION_SIZE / 2;
       
    65 
       
    66     // Since during deallocation GC could free (very unlikely) some non-humongous data this value relaxes amount of
       
    67     // memory we expect to be freed.
       
    68     private static final double ALLOCATION_SIZE_TOLERANCE_FACTOR = 0.85D;
       
    69 
       
    70     private enum MemoryCounter {
       
    71         MX_BEAN_COUNTER {
       
    72             @Override
       
    73             public long getUsedMemory() {
       
    74                 return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
       
    75             }
       
    76         },
       
    77         RUNTIME_COUNTER {
       
    78             @Override
       
    79             public long getUsedMemory() {
       
    80                 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
       
    81             }
       
    82         };
       
    83 
       
    84         public abstract long getUsedMemory();
       
    85     }
       
    86 
       
    87     private static class Allocation {
       
    88         private byte[] allocation;
       
    89         public final long expectedSize;
       
    90 
       
    91         public Allocation(int allocationSize, long allocationExpectedSize) {
       
    92             allocation = new byte[allocationSize];
       
    93             expectedSize = allocationExpectedSize;
       
    94 
       
    95             System.out.println(String.format("Object size is %d; Object is %shumongous",
       
    96                     WHITE_BOX.getObjectSize(allocation),
       
    97                     (WHITE_BOX.g1IsHumongous(allocation) ? "" : "non-")));
       
    98 
       
    99             selfTest();
       
   100         }
       
   101 
       
   102         private void selfTest() {
       
   103             boolean isHumongous = WHITE_BOX.getObjectSize(allocation) > HALF_G1_REGION_SIZE;
       
   104             boolean shouldBeHumongous = WHITE_BOX.g1IsHumongous(allocation);
       
   105 
       
   106             // Sanity check
       
   107             Asserts.assertEquals(isHumongous, shouldBeHumongous,
       
   108                     String.format("Test Bug: Object of size %d is expected to be %shumongous but it is not",
       
   109                             WHITE_BOX.getObjectSize(allocation), (shouldBeHumongous ? "" : "non-")));
       
   110         }
       
   111 
       
   112         public void forgetAllocation() {
       
   113             allocation = null;
       
   114         }
       
   115     }
       
   116 
       
   117     public static void main(String[] args) {
       
   118 
       
   119         if (args.length != 1) {
       
   120             throw new Error("Expected memory counter name wasn't provided as command line argument");
       
   121         }
       
   122         MemoryCounter memoryCounter = MemoryCounter.valueOf(args[0].toUpperCase());
       
   123 
       
   124         int byteArrayMemoryOverhead = Helpers.detectByteArrayAllocationOverhead();
       
   125 
       
   126         // Largest non-humongous byte[]
       
   127         int maxByteArrayNonHumongousSize = HALF_G1_REGION_SIZE - byteArrayMemoryOverhead;
       
   128 
       
   129         // Maximum byte[] that takes one region
       
   130         int maxByteArrayOneRegionSize = G1_REGION_SIZE - byteArrayMemoryOverhead;
       
   131 
       
   132         List<Integer> allocationSizes = Arrays.asList(
       
   133                 (int) maxByteArrayNonHumongousSize + 1,
       
   134                 (int) (0.8f * maxByteArrayOneRegionSize),
       
   135                 (int) (maxByteArrayOneRegionSize),
       
   136                 (int) (1.2f * maxByteArrayOneRegionSize),
       
   137                 (int) (1.5f * maxByteArrayOneRegionSize),
       
   138                 (int) (1.7f * maxByteArrayOneRegionSize),
       
   139                 (int) (2.0f * maxByteArrayOneRegionSize),
       
   140                 (int) (2.5f * maxByteArrayOneRegionSize)
       
   141         );
       
   142 
       
   143         List<Allocation> allocations = new ArrayList<>();
       
   144         List<GarbageCollectorMXBean> gcBeans =
       
   145                 ManagementFactory.getGarbageCollectorMXBeans();
       
   146 
       
   147         long gcCountBefore = gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionCount).sum();
       
   148 
       
   149 
       
   150         System.out.println("Starting allocations - no GC should happen until we finish them");
       
   151 
       
   152         for (int allocationSize : allocationSizes) {
       
   153 
       
   154             long usedMemoryBefore = memoryCounter.getUsedMemory();
       
   155             long expectedAllocationSize = (long) Math.ceil((double) allocationSize / G1_REGION_SIZE) * G1_REGION_SIZE;
       
   156             allocations.add(new Allocation(allocationSize, expectedAllocationSize));
       
   157             long usedMemoryAfter = memoryCounter.getUsedMemory();
       
   158 
       
   159             System.out.format("Expected allocation size: %d\nUsed memory before allocation: %d\n"
       
   160                             + "Used memory after allocation: %d\n",
       
   161                     expectedAllocationSize, usedMemoryBefore, usedMemoryAfter);
       
   162 
       
   163             long gcCountNow = gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionCount).sum();
       
   164 
       
   165             if (gcCountNow == gcCountBefore) {
       
   166                 // We should allocate at least allocation.expectedSize
       
   167                 Asserts.assertGreaterThanOrEqual(usedMemoryAfter - usedMemoryBefore, expectedAllocationSize,
       
   168                         "Counter of type " + memoryCounter.getClass().getSimpleName() +
       
   169                                 " returned wrong allocation size");
       
   170             } else {
       
   171                 System.out.println("GC happened during allocation so the check is skipped");
       
   172                 gcCountBefore = gcCountNow;
       
   173             }
       
   174         }
       
   175 
       
   176         System.out.println("Finished allocations - no GC should have happened before this line");
       
   177 
       
   178 
       
   179         allocations.stream().forEach(allocation -> {
       
   180             long usedMemoryBefore = memoryCounter.getUsedMemory();
       
   181             allocation.forgetAllocation();
       
   182 
       
   183             WHITE_BOX.fullGC();
       
   184 
       
   185             long usedMemoryAfter = memoryCounter.getUsedMemory();
       
   186 
       
   187             // We should free at least allocation.expectedSize * ALLOCATION_SIZE_TOLERANCE_FACTOR
       
   188             Asserts.assertGreaterThanOrEqual(usedMemoryBefore - usedMemoryAfter,
       
   189                     (long) (allocation.expectedSize * ALLOCATION_SIZE_TOLERANCE_FACTOR),
       
   190                     "Counter of type " + memoryCounter.getClass().getSimpleName() + " returned wrong allocation size");
       
   191         });
       
   192     }
       
   193 }