Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/gc/survivorAlignment/SurvivorAlignmentTestMain.java
32284 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.lang.management.ManagementFactory;24import java.lang.management.MemoryPoolMXBean;25import java.util.Objects;26import java.util.Optional;27import java.util.regex.Matcher;28import java.util.regex.Pattern;2930import com.oracle.java.testlibrary.Asserts;31import com.sun.management.ThreadMXBean;32import sun.hotspot.WhiteBox;33import sun.misc.Unsafe;3435/**36* Main class for tests on {@code SurvivorAlignmentInBytes} option.37*38* Typical usage is to obtain instance using fromArgs method, allocate objects39* and verify that actual memory usage in tested heap space is close to40* expected.41*/42public class SurvivorAlignmentTestMain {43enum HeapSpace {44EDEN,45SURVIVOR,46TENURED47}4849public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();5051public static final long MAX_TENURING_THRESHOLD = Optional.ofNullable(52SurvivorAlignmentTestMain.WHITE_BOX.getIntxVMFlag(53"MaxTenuringThreshold")).orElse(15L);5455/**56* Regexp used to parse memory size params, like 2G, 34m or 15k.57*/58private static final Pattern SIZE_REGEX59= Pattern.compile("(?<size>[0-9]+)(?<multiplier>[GMKgmk])?");6061// Names of different heap spaces.62private static final String DEF_NEW_EDEN = "Eden Space";63private static final String DEF_NEW_SURVIVOR = "Survivor Space";64private static final String PAR_NEW_EDEN = "Par Eden Space";65private static final String PAR_NEW_SURVIVOR = "Par Survivor Space";66private static final String PS_EDEN = "PS Eden Space";67private static final String PS_SURVIVOR = "PS Survivor Space";68private static final String G1_EDEN = "G1 Eden Space";69private static final String G1_SURVIVOR = "G1 Survivor Space";70private static final String SERIAL_TENURED = "Tenured Gen";71private static final String CMS_TENURED = "CMS Old Gen";72private static final String PS_TENURED = "PS Old Gen";73private static final String G1_TENURED = "G1 Old Gen";7475private static final long G1_HEAP_REGION_SIZE = Optional.ofNullable(76SurvivorAlignmentTestMain.WHITE_BOX.getUintxVMFlag(77"G1HeapRegionSize")).orElse(-1L);7879/**80* Min size of free chunk in CMS generation.81* An object allocated in CMS generation will at least occupy this amount82* of bytes.83*/84private static final long CMS_MIN_FREE_CHUNK_SIZE85= 3L * Unsafe.ADDRESS_SIZE;8687private static final AlignmentHelper EDEN_SPACE_HELPER;88private static final AlignmentHelper SURVIVOR_SPACE_HELPER;89private static final AlignmentHelper TENURED_SPACE_HELPER;90/**91* Amount of memory that should be filled during a test run.92*/93private final long memoryToFill;94/**95* The size of an objects that will be allocated during a test run.96*/97private final long objectSize;98/**99* Amount of memory that will be actually occupied by an object in eden100* space.101*/102private final long actualObjectSize;103/**104* Storage for allocated objects.105*/106private final Object[] garbage;107/**108* Heap space whose memory usage is a subject of assertions during the test109* run.110*/111private final HeapSpace testedSpace;112113private long[] baselinedThreadMemoryUsage = null;114private long[] threadIds = null;115116/**117* Initialize {@code EDEN_SPACE_HELPER}, {@code SURVIVOR_SPACE_HELPER} and118* {@code TENURED_SPACE_HELPER} to represent heap spaces in use.119*120* Note that regardless to GC object's alignment in survivor space is121* expected to be equal to {@code SurvivorAlignmentInBytes} value and122* alignment in other spaces is expected to be equal to123* {@code ObjectAlignmentInBytes} value.124*125* In CMS generation we can't allocate less then {@code MinFreeChunk} value,126* for other CGs we expect that object of size {@code MIN_OBJECT_SIZE}127* could be allocated as it is (of course, its size could be aligned128* according to alignment value used in a particular space).129*130* For G1 GC MXBeans could report memory usage only with region size131* precision (if an object allocated in some G1 heap region, then all region132* will claimed as used), so for G1's spaces precision is equal to133* {@code G1HeapRegionSize} value.134*/135static {136AlignmentHelper edenHelper = null;137AlignmentHelper survivorHelper = null;138AlignmentHelper tenuredHelper = null;139for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {140switch (pool.getName()) {141case SurvivorAlignmentTestMain.DEF_NEW_EDEN:142case SurvivorAlignmentTestMain.PAR_NEW_EDEN:143case SurvivorAlignmentTestMain.PS_EDEN:144Asserts.assertNull(edenHelper,145"Only one bean for eden space is expected.");146edenHelper = new AlignmentHelper(147AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,148AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,149AlignmentHelper.MIN_OBJECT_SIZE, pool);150break;151case SurvivorAlignmentTestMain.G1_EDEN:152Asserts.assertNull(edenHelper,153"Only one bean for eden space is expected.");154edenHelper = new AlignmentHelper(155SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE,156AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,157AlignmentHelper.MIN_OBJECT_SIZE, pool);158break;159case SurvivorAlignmentTestMain.DEF_NEW_SURVIVOR:160case SurvivorAlignmentTestMain.PAR_NEW_SURVIVOR:161case SurvivorAlignmentTestMain.PS_SURVIVOR:162Asserts.assertNull(survivorHelper,163"Only one bean for survivor space is expected.");164survivorHelper = new AlignmentHelper(165AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,166AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES,167AlignmentHelper.MIN_OBJECT_SIZE, pool);168break;169case SurvivorAlignmentTestMain.G1_SURVIVOR:170Asserts.assertNull(survivorHelper,171"Only one bean for survivor space is expected.");172survivorHelper = new AlignmentHelper(173SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE,174AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES,175AlignmentHelper.MIN_OBJECT_SIZE, pool);176break;177case SurvivorAlignmentTestMain.SERIAL_TENURED:178case SurvivorAlignmentTestMain.PS_TENURED:179case SurvivorAlignmentTestMain.G1_TENURED:180Asserts.assertNull(tenuredHelper,181"Only one bean for tenured space is expected.");182tenuredHelper = new AlignmentHelper(183AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,184AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,185AlignmentHelper.MIN_OBJECT_SIZE, pool);186break;187case SurvivorAlignmentTestMain.CMS_TENURED:188Asserts.assertNull(tenuredHelper,189"Only one bean for tenured space is expected.");190tenuredHelper = new AlignmentHelper(191AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,192AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES,193SurvivorAlignmentTestMain.CMS_MIN_FREE_CHUNK_SIZE,194pool);195break;196}197}198EDEN_SPACE_HELPER = Objects.requireNonNull(edenHelper,199"AlignmentHelper for eden space should be initialized.");200SURVIVOR_SPACE_HELPER = Objects.requireNonNull(survivorHelper,201"AlignmentHelper for survivor space should be initialized.");202TENURED_SPACE_HELPER = Objects.requireNonNull(tenuredHelper,203"AlignmentHelper for tenured space should be initialized.");204}205/**206* Returns an SurvivorAlignmentTestMain instance constructed using CLI207* options.208*209* Following options are expected:210* <ul>211* <li>memoryToFill</li>212* <li>objectSize</li>213* </ul>214*215* Both argument may contain multiplier suffix k, m or g.216*/217public static SurvivorAlignmentTestMain fromArgs(String[] args) {218Asserts.assertEQ(args.length, 3, "Expected three arguments: "219+ "memory size, object size and tested heap space name.");220221long memoryToFill = parseSize(args[0]);222long objectSize = Math.max(parseSize(args[1]),223AlignmentHelper.MIN_ARRAY_SIZE);224HeapSpace testedSpace = HeapSpace.valueOf(args[2]);225226return new SurvivorAlignmentTestMain(memoryToFill, objectSize,227testedSpace);228}229230/**231* Returns a value parsed from a string with format232* <integer><multiplier>.233*/234private static long parseSize(String sizeString) {235Matcher matcher = SIZE_REGEX.matcher(sizeString);236Asserts.assertTrue(matcher.matches(),237"sizeString should have following format \"[0-9]+([MBK])?\"");238long size = Long.valueOf(matcher.group("size"));239240if (matcher.group("multiplier") != null) {241long K = 1024L;242// fall through multipliers243switch (matcher.group("multiplier").toLowerCase()) {244case "g":245size *= K;246case "m":247size *= K;248case "k":249size *= K;250}251}252return size;253}254255private SurvivorAlignmentTestMain(long memoryToFill, long objectSize,256HeapSpace testedSpace) {257this.objectSize = objectSize;258this.memoryToFill = memoryToFill;259this.testedSpace = testedSpace;260261AlignmentHelper helper = SurvivorAlignmentTestMain.EDEN_SPACE_HELPER;262263this.actualObjectSize = helper.getObjectSizeInThisSpace(264this.objectSize);265int arrayLength = helper.getObjectsCount(memoryToFill, this.objectSize);266garbage = new Object[arrayLength];267}268269/**270* Allocate byte arrays to fill {@code memoryToFill} memory.271*/272public void allocate() {273int byteArrayLength = Math.max((int) (objectSize274- Unsafe.ARRAY_BYTE_BASE_OFFSET), 0);275276for (int i = 0; i < garbage.length; i++) {277garbage[i] = new byte[byteArrayLength];278}279}280281/**282* Release memory occupied after {@code allocate} call.283*/284public void release() {285for (int i = 0; i < garbage.length; i++) {286garbage[i] = null;287}288}289290/**291* Returns expected amount of memory occupied in a {@code heapSpace} by292* objects referenced from {@code garbage} array.293*/294public long getExpectedMemoryUsage() {295AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace);296return alignmentHelper.getExpectedMemoryUsage(objectSize,297garbage.length);298}299300/**301* Verifies that memory usage in a {@code heapSpace} deviates from302* {@code expectedUsage} for no more than {@code MAX_RELATIVE_DEVIATION}.303*/304public void verifyMemoryUsage(long expectedUsage) {305AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace);306307long actualMemoryUsage = alignmentHelper.getActualMemoryUsage();308boolean otherThreadsAllocatedMemory = areOtherThreadsAllocatedMemory();309310long memoryUsageDiff = Math.abs(actualMemoryUsage - expectedUsage);311long maxAllowedUsageDiff312= alignmentHelper.getAllowedMemoryUsageDeviation(expectedUsage);313314System.out.println("Verifying memory usage in space: " + testedSpace);315System.out.println("Allocated objects count: " + garbage.length);316System.out.println("Desired object size: " + objectSize);317System.out.println("Actual object size: " + actualObjectSize);318System.out.println("Expected object size in space: "319+ alignmentHelper.getObjectSizeInThisSpace(objectSize));320System.out.println("Expected memory usage: " + expectedUsage);321System.out.println("Actual memory usage: " + actualMemoryUsage);322System.out.println("Memory usage diff: " + memoryUsageDiff);323System.out.println("Max allowed usage diff: " + maxAllowedUsageDiff);324325if (memoryUsageDiff > maxAllowedUsageDiff326&& otherThreadsAllocatedMemory) {327System.out.println("Memory usage diff is incorrect, but it seems "328+ "like someone else allocated objects");329return;330}331332Asserts.assertLTE(memoryUsageDiff, maxAllowedUsageDiff,333"Actual memory usage should not deviate from expected for " +334"more then " + maxAllowedUsageDiff);335}336337/**338* Baselines amount of memory allocated by each thread.339*/340public void baselineMemoryAllocation() {341ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean();342threadIds = bean.getAllThreadIds();343baselinedThreadMemoryUsage = bean.getThreadAllocatedBytes(threadIds);344}345346/**347* Checks if threads other then the current thread were allocating objects348* after baselinedThreadMemoryUsage call.349*350* If baselinedThreadMemoryUsage was not called, then this method will return351* {@code false}.352*/353public boolean areOtherThreadsAllocatedMemory() {354if (baselinedThreadMemoryUsage == null) {355return false;356}357358ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean();359long currentMemoryAllocation[]360= bean.getThreadAllocatedBytes(threadIds);361boolean otherThreadsAllocatedMemory = false;362363System.out.println("Verifying amount of memory allocated by threads:");364for (int i = 0; i < threadIds.length; i++) {365System.out.format("Thread %d%nbaseline allocation: %d"366+ "%ncurrent allocation:%d%n", threadIds[i],367baselinedThreadMemoryUsage[i], currentMemoryAllocation[i]);368System.out.println(bean.getThreadInfo(threadIds[i]));369370long bytesAllocated = Math.abs(currentMemoryAllocation[i]371- baselinedThreadMemoryUsage[i]);372if (bytesAllocated > 0373&& threadIds[i] != Thread.currentThread().getId()) {374otherThreadsAllocatedMemory = true;375}376}377378return otherThreadsAllocatedMemory;379}380381@Override382public String toString() {383StringBuilder builder = new StringBuilder();384385builder.append(String.format("SurvivorAlignmentTestMain info:%n"));386builder.append(String.format("Desired object size: %d%n", objectSize));387builder.append(String.format("Memory to fill: %d%n", memoryToFill));388builder.append(String.format("Objects to be allocated: %d%n",389garbage.length));390391builder.append(String.format("Alignment helpers to be used: %n"));392for (HeapSpace heapSpace: HeapSpace.values()) {393builder.append(String.format("For space %s:%n%s%n", heapSpace,394getAlignmentHelper(heapSpace)));395}396397return builder.toString();398}399400/**401* Returns {@code AlignmentHelper} for a space {@code heapSpace}.402*/403public static AlignmentHelper getAlignmentHelper(HeapSpace heapSpace) {404switch (heapSpace) {405case EDEN:406return SurvivorAlignmentTestMain.EDEN_SPACE_HELPER;407case SURVIVOR:408return SurvivorAlignmentTestMain.SURVIVOR_SPACE_HELPER;409case TENURED:410return SurvivorAlignmentTestMain.TENURED_SPACE_HELPER;411default:412throw new Error("Unexpected heap space: " + heapSpace);413}414}415}416417418