24 /* 25 * @test TestPLABPromotion 26 * @bug 8141278 8141141 27 * @summary Test PLAB promotion 28 * @requires vm.gc=="G1" | vm.gc=="null" 29 * @requires vm.opt.FlightRecorder != true 30 * @library /testlibrary /test/lib / 31 * @modules java.management 32 * @build ClassFileInstaller 33 * sun.hotspot.WhiteBox 34 * gc.g1.plab.lib.MemoryConsumer 35 * gc.g1.plab.lib.LogParser 36 * gc.g1.plab.lib.AppPLABPromotion 37 * @run main ClassFileInstaller sun.hotspot.WhiteBox 38 * sun.hotspot.WhiteBox$WhiteBoxPermission 39 * @run main/timeout=240 gc.g1.plab.TestPLABPromotion 40 */ 41 package gc.g1.plab; 42 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Arrays; 46 import java.io.PrintStream; 47 48 import gc.g1.plab.lib.AppPLABPromotion; 49 import gc.g1.plab.lib.LogParser; 50 import gc.g1.plab.lib.PLABUtils; 51 52 import jdk.test.lib.OutputAnalyzer; 53 import jdk.test.lib.ProcessTools; 54 import jdk.test.lib.Platform; 55 56 /** 57 * Test checks PLAB promotion of different size objects. 58 */ 59 public class TestPLABPromotion { 60 61 // GC ID with survivor PLAB statistics 62 private final static long GC_ID_SURVIVOR_STATS = 1l; 63 // GC ID with old PLAB statistics 64 private final static long GC_ID_OLD_STATS = 2l; 65 66 // Allowable difference for memory consumption (percentage) 67 private final static long MEM_DIFFERENCE_PCT = 5; 68 69 private static final int PLAB_SIZE_SMALL = 1024; 70 private static final int PLAB_SIZE_MEDIUM = 4096; 71 private static final int PLAB_SIZE_HIGH = 65536; 72 private static final int OBJECT_SIZE_SMALL = 10; 73 private static final int OBJECT_SIZE_MEDIUM = 100; 74 private static final int OBJECT_SIZE_HIGH = 1000; 75 private static final int GC_NUM_SMALL = 1; 76 private static final int GC_NUM_MEDIUM = 3; 77 private static final int GC_NUM_HIGH = 7; 78 private static final int WASTE_PCT_SMALL = 10; 79 private static final int WASTE_PCT_MEDIUM = 20; 80 private static final int WASTE_PCT_HIGH = 30; 81 private static final int YOUNG_SIZE_LOW = 16; 82 private static final int YOUNG_SIZE_HIGH = 64; 83 private static final boolean PLAB_FIXED = true; 84 private static final boolean PLAB_DYNAMIC = false; 85 103 new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), 104 new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), 105 new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, false), 106 new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), 107 new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), 108 new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true) 109 }; 110 111 public static void main(String[] args) throws Throwable { 112 113 for (TestCase testCase : TEST_CASES) { 114 // What we going to check. 115 testCase.print(System.out); 116 List<String> options = PLABUtils.prepareOptions(testCase.toOptions()); 117 options.add(AppPLABPromotion.class.getName()); 118 OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); 119 if (out.getExitValue() != 0) { 120 System.out.println(out.getOutput()); 121 throw new RuntimeException("Expect exit code 0."); 122 } 123 checkResults(out.getOutput(), testCase); 124 } 125 } 126 127 private static void checkResults(String output, TestCase testCase) { 128 long plabAllocatedSurvivor; 129 long directAllocatedSurvivor; 130 long plabAllocatedOld; 131 long directAllocatedOld; 132 long memAllocated = testCase.getMemToFill(); 133 LogParser logParser = new LogParser(output); 134 135 Map<String, Long> survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS); 136 Map<String, Long> oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS); 137 138 plabAllocatedSurvivor = survivorStats.get("used"); 139 directAllocatedSurvivor = survivorStats.get("direct allocated"); 140 plabAllocatedOld = oldStats.get("used"); 141 directAllocatedOld = oldStats.get("direct allocated"); 142 143 System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); 144 System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated); 145 146 // Unreachable objects case 147 if (testCase.isDeadObjectCase()) { 148 // No dead objects should be promoted 149 if (!(checkRatio(plabAllocatedSurvivor, memAllocated) && checkRatio(directAllocatedSurvivor, memAllocated))) { 150 System.out.println(output); 151 throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Survivor"); 152 } 153 if (!(checkRatio(plabAllocatedOld, memAllocated) && checkRatio(directAllocatedOld, memAllocated))) { 154 System.out.println(output); 155 throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Old"); 156 } 157 } else { 158 // Live objects case 159 if (testCase.isPromotedByPLAB()) { 160 // All live small objects should be promoted using PLAB 161 if (!checkDifferenceRatio(plabAllocatedSurvivor, memAllocated)) { 162 System.out.println(output); 163 throw new RuntimeException("Expect that Survivor PLAB allocation are similar to all mem consumed"); 164 } 165 if (!checkDifferenceRatio(plabAllocatedOld, memAllocated)) { 166 System.out.println(output); 167 throw new RuntimeException("Expect that Old PLAB allocation are similar to all mem consumed"); 168 } 169 } else { 170 // All big objects should be directly allocated 171 if (!checkDifferenceRatio(directAllocatedSurvivor, memAllocated)) { 172 System.out.println(output); 173 throw new RuntimeException("Test fails. Expect that Survivor direct allocation are similar to all mem consumed"); 174 } 175 if (!checkDifferenceRatio(directAllocatedOld, memAllocated)) { 176 System.out.println(output); 177 throw new RuntimeException("Test fails. Expect that Old direct allocation are similar to all mem consumed"); 178 } 179 } 180 181 // All promoted objects size should be similar to all consumed memory 182 if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) { 183 System.out.println(output); 184 throw new RuntimeException("Test fails. Expect that Survivor gen total allocation are similar to all mem consumed"); 185 } 186 if (!checkDifferenceRatio(plabAllocatedOld + directAllocatedOld, memAllocated)) { 187 System.out.println(output); 188 throw new RuntimeException("Test fails. Expect that Old gen total allocation are similar to all mem consumed"); 189 } 190 } 191 System.out.println("Test passed!"); 192 } 193 194 /** 195 * Returns true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue. 196 * 197 * @param checkedValue - checked value 198 * @param controlValue - referent value 199 * @return true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue 200 */ 201 private static boolean checkRatio(long checkedValue, long controlValue) { 202 return (Math.abs(checkedValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT; 203 } 204 205 /** 206 * Returns true if difference of checkedValue and controlValue is less than 207 * MEM_DIFFERENCE_PCT percent of controlValue. 208 * 209 * @param checkedValue - checked value 210 * @param controlValue - referent value 211 * @return true if difference of checkedValue and controlValue is less than 212 * MEM_DIFFERENCE_PCT percent of controlValue 213 */ 214 private static boolean checkDifferenceRatio(long checkedValue, long controlValue) { 215 return (Math.abs(checkedValue - controlValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT; 216 } 217 218 private static Map<String, Long> getPlabStats(LogParser logParser, LogParser.ReportType type, long gc_id) { 219 220 Map<String, Long> survivorStats = logParser.getEntries() 221 .get(gc_id) 222 .get(type); 223 return survivorStats; 224 } 225 226 /** 227 * Description of one test case. 228 */ 229 private static class TestCase { 230 231 private final int wastePct; 232 private final int plabSize; 233 private final int chunkSize; 234 private final int parGCThreads; 235 private final int edenSize; 236 private final boolean plabIsFixed; 237 private final boolean objectsAreReachable; 238 private final boolean promotedByPLAB; 239 240 /** 241 * @param wastePct 242 * ParallelGCBufferWastePct 243 * @param plabSize | 24 /* 25 * @test TestPLABPromotion 26 * @bug 8141278 8141141 27 * @summary Test PLAB promotion 28 * @requires vm.gc=="G1" | vm.gc=="null" 29 * @requires vm.opt.FlightRecorder != true 30 * @library /testlibrary /test/lib / 31 * @modules java.management 32 * @build ClassFileInstaller 33 * sun.hotspot.WhiteBox 34 * gc.g1.plab.lib.MemoryConsumer 35 * gc.g1.plab.lib.LogParser 36 * gc.g1.plab.lib.AppPLABPromotion 37 * @run main ClassFileInstaller sun.hotspot.WhiteBox 38 * sun.hotspot.WhiteBox$WhiteBoxPermission 39 * @run main/timeout=240 gc.g1.plab.TestPLABPromotion 40 */ 41 package gc.g1.plab; 42 43 import java.util.List; 44 import java.util.Arrays; 45 import java.io.PrintStream; 46 47 import gc.g1.plab.lib.AppPLABPromotion; 48 import gc.g1.plab.lib.LogParser; 49 import gc.g1.plab.lib.PLABUtils; 50 import gc.g1.plab.lib.PlabInfo; 51 52 import jdk.test.lib.OutputAnalyzer; 53 import jdk.test.lib.ProcessTools; 54 55 /** 56 * Test checks PLAB promotion of different size objects. 57 */ 58 public class TestPLABPromotion { 59 60 // GC ID with survivor PLAB statistics 61 private final static long GC_ID_SURVIVOR_STATS = 1l; 62 // GC ID with old PLAB statistics 63 private final static long GC_ID_OLD_STATS = 2l; 64 65 private final static String PLAB_USED_FIELD_NAME = "used"; 66 private final static String PLAB_DIRECT_ALLOCATED_FIELD_NAME = "direct allocated"; 67 private final static List<String> FIELDS_TO_EXTRACT = Arrays.asList(PLAB_USED_FIELD_NAME, PLAB_DIRECT_ALLOCATED_FIELD_NAME); 68 69 private static String output; 70 71 // Allowable difference for memory consumption (percentage) 72 private final static long MEM_DIFFERENCE_PCT = 5; 73 74 private static final int PLAB_SIZE_SMALL = 1024; 75 private static final int PLAB_SIZE_MEDIUM = 4096; 76 private static final int PLAB_SIZE_HIGH = 65536; 77 private static final int OBJECT_SIZE_SMALL = 10; 78 private static final int OBJECT_SIZE_MEDIUM = 100; 79 private static final int OBJECT_SIZE_HIGH = 1000; 80 private static final int GC_NUM_SMALL = 1; 81 private static final int GC_NUM_MEDIUM = 3; 82 private static final int GC_NUM_HIGH = 7; 83 private static final int WASTE_PCT_SMALL = 10; 84 private static final int WASTE_PCT_MEDIUM = 20; 85 private static final int WASTE_PCT_HIGH = 30; 86 private static final int YOUNG_SIZE_LOW = 16; 87 private static final int YOUNG_SIZE_HIGH = 64; 88 private static final boolean PLAB_FIXED = true; 89 private static final boolean PLAB_DYNAMIC = false; 90 108 new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), 109 new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), 110 new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, false), 111 new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), 112 new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), 113 new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true) 114 }; 115 116 public static void main(String[] args) throws Throwable { 117 118 for (TestCase testCase : TEST_CASES) { 119 // What we going to check. 120 testCase.print(System.out); 121 List<String> options = PLABUtils.prepareOptions(testCase.toOptions()); 122 options.add(AppPLABPromotion.class.getName()); 123 OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()])); 124 if (out.getExitValue() != 0) { 125 System.out.println(out.getOutput()); 126 throw new RuntimeException("Expect exit code 0."); 127 } 128 output = out.getOutput(); 129 checkResults(testCase); 130 } 131 } 132 133 private static void checkResults(TestCase testCase) { 134 long plabAllocatedSurvivor; 135 long directAllocatedSurvivor; 136 long plabAllocatedOld; 137 long directAllocatedOld; 138 long memAllocated = testCase.getMemToFill(); 139 LogParser logParser = new LogParser(output); 140 141 PlabInfo survivorPlabInfo = logParser.getSpecifiedStats(GC_ID_SURVIVOR_STATS, LogParser.ReportType.SURVIVOR_STATS, FIELDS_TO_EXTRACT); 142 PlabInfo oldPlabInfo = logParser.getSpecifiedStats(GC_ID_OLD_STATS, LogParser.ReportType.OLD_STATS, FIELDS_TO_EXTRACT); 143 144 checkFields(survivorPlabInfo); 145 checkFields(oldPlabInfo); 146 147 plabAllocatedSurvivor = survivorPlabInfo.get(PLAB_USED_FIELD_NAME); 148 directAllocatedSurvivor = survivorPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME); 149 plabAllocatedOld = oldPlabInfo.get(PLAB_USED_FIELD_NAME); 150 directAllocatedOld = oldPlabInfo.get(PLAB_DIRECT_ALLOCATED_FIELD_NAME); 151 152 System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); 153 System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated); 154 155 // Unreachable objects case 156 if (testCase.isDeadObjectCase()) { 157 checkDeadObjectsPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); 158 checkDeadObjectsPromotion(plabAllocatedOld, directAllocatedOld, memAllocated); 159 160 } else { 161 // Live objects case 162 if (testCase.isPromotedByPLAB()) { 163 checkLiveObjectsPromotion(plabAllocatedSurvivor, memAllocated, "Expect that Survivor PLAB allocation are similar to all mem consumed"); 164 checkLiveObjectsPromotion(plabAllocatedOld, memAllocated, "Expect that Old PLAB allocation are similar to all mem consumed"); 165 } else { 166 // All big objects should be directly allocated 167 checkLiveObjectsPromotion(directAllocatedSurvivor, memAllocated, "Expect that Survivor direct allocation are similar to all mem consumed"); 168 checkLiveObjectsPromotion(directAllocatedOld, memAllocated, "Expect that Old direct allocation are similar to all mem consumed"); 169 } 170 171 checkTotalPromotion(plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated, "Expect that Survivor gen total allocation are similar to all mem consumed"); 172 checkTotalPromotion(plabAllocatedOld, directAllocatedOld, memAllocated, "Expect that Old gen total allocation are similar to all mem consumed"); 173 } 174 System.out.println("Test passed!"); 175 } 176 177 private static void checkTotalPromotion(long plabAllocatedSurvivor, long directAllocatedSurvivor, long memAllocated, String exceptionMessage) { 178 // All promoted objects size should be similar to all consumed memory 179 if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) { 180 System.out.println(output); 181 throw new RuntimeException(exceptionMessage); 182 } 183 } 184 185 /** 186 * Checks that live objects were promoted as expected. 187 * @param plabAllocated 188 * @param totalMemAllocated 189 * @param exceptionMessage 190 */ 191 private static void checkLiveObjectsPromotion(long plabAllocated, long totalMemAllocated, String exceptionMessage) { 192 // All live small objects should be promoted using PLAB 193 if (!checkDifferenceRatio(plabAllocated, totalMemAllocated)) { 194 System.out.println(output); 195 throw new RuntimeException(exceptionMessage); 196 } 197 } 198 199 /** 200 * Checks that dead objects are not promoted. 201 * @param plabPromoted promoted by PLAB 202 * @param directlyPromoted 203 * @param memoryAllocated total memory allocated 204 */ 205 private static void checkDeadObjectsPromotion(long plabPromoted, long directlyPromoted, long memoryAllocated) { 206 // No dead objects should be promoted 207 if (!(checkRatio(plabPromoted, memoryAllocated) && checkRatio(directlyPromoted, memoryAllocated))) { 208 System.out.println(output); 209 throw new RuntimeException("Unreachable objects should not be allocated using PLAB or directly allocated to Survivor/Old"); 210 } 211 } 212 213 /** 214 * Checks that PLAB statistics contains expected fields. 215 * @param info 216 */ 217 private static void checkFields(PlabInfo info) { 218 if (!info.checkFields(FIELDS_TO_EXTRACT)) { 219 System.out.println(output); 220 throw new RuntimeException("PLAB log does not contain expected fields"); 221 } 222 } 223 224 /** 225 * Returns true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue. 226 * 227 * @param checkedValue - checked value 228 * @param controlValue - referent value 229 * @return true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue 230 */ 231 private static boolean checkRatio(long checkedValue, long controlValue) { 232 return (Math.abs(checkedValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT; 233 } 234 235 /** 236 * Returns true if difference of checkedValue and controlValue is less than 237 * MEM_DIFFERENCE_PCT percent of controlValue. 238 * 239 * @param checkedValue - checked value 240 * @param controlValue - referent value 241 * @return true if difference of checkedValue and controlValue is less than 242 * MEM_DIFFERENCE_PCT percent of controlValue 243 */ 244 private static boolean checkDifferenceRatio(long checkedValue, long controlValue) { 245 return (Math.abs(checkedValue - controlValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT; 246 } 247 248 /** 249 * Description of one test case. 250 */ 251 private static class TestCase { 252 253 private final int wastePct; 254 private final int plabSize; 255 private final int chunkSize; 256 private final int parGCThreads; 257 private final int edenSize; 258 private final boolean plabIsFixed; 259 private final boolean objectsAreReachable; 260 private final boolean promotedByPLAB; 261 262 /** 263 * @param wastePct 264 * ParallelGCBufferWastePct 265 * @param plabSize |