1 /* 2 * Copyright (c) 2016, 2020, 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 #include "precompiled.hpp" 25 #include "gc/g1/g1CollectedHeap.inline.hpp" 26 #include "gc/g1/g1IHOPControl.hpp" 27 #include "gc/g1/g1OldGenAllocationTracker.hpp" 28 #include "gc/g1/g1Predictions.hpp" 29 #include "unittest.hpp" 30 31 static void test_update_allocation_tracker(G1OldGenAllocationTracker* alloc_tracker, 32 size_t alloc_amount) { 33 alloc_tracker->add_allocated_bytes_since_last_gc(alloc_amount); 34 alloc_tracker->reset_after_gc((size_t)0); 35 } 36 37 static void test_update(G1IHOPControl* ctrl, 38 G1OldGenAllocationTracker* alloc_tracker, 39 double alloc_time, size_t alloc_amount, 40 size_t young_size, double mark_time) { 41 test_update_allocation_tracker(alloc_tracker, alloc_amount); 42 for (int i = 0; i < 100; i++) { 43 ctrl->update_allocation_info(alloc_time, young_size); 44 ctrl->update_marking_length(mark_time); 45 } 46 } 47 48 static void test_update_humongous(G1IHOPControl* ctrl, 49 G1OldGenAllocationTracker* alloc_tracker, 50 double alloc_time, 51 size_t alloc_amount_non_hum, 52 size_t alloc_amount_hum, 53 size_t humongous_bytes_after_last_gc, 54 size_t young_size, 55 double mark_time) { 56 alloc_tracker->add_allocated_bytes_since_last_gc(alloc_amount_non_hum); 57 alloc_tracker->add_allocated_humongous_bytes_since_last_gc(alloc_amount_hum); 58 alloc_tracker->reset_after_gc(humongous_bytes_after_last_gc); 59 for (int i = 0; i < 100; i++) { 60 ctrl->update_allocation_info(alloc_time, young_size); 61 ctrl->update_marking_length(mark_time); 62 } 63 } 64 65 // @requires UseG1GC 66 TEST_VM(G1StaticIHOPControl, simple) { 67 // Test requires G1 68 if (!UseG1GC) { 69 return; 70 } 71 72 const size_t initial_ihop = 45; 73 74 G1OldGenAllocationTracker alloc_tracker; 75 G1StaticIHOPControl ctrl(initial_ihop, &alloc_tracker); 76 ctrl.update_target_occupancy(100); 77 78 size_t threshold = ctrl.get_conc_mark_start_threshold(); 79 EXPECT_EQ(initial_ihop, threshold); 80 81 test_update_allocation_tracker(&alloc_tracker, 100); 82 ctrl.update_allocation_info(100.0, 100); 83 threshold = ctrl.get_conc_mark_start_threshold(); 84 EXPECT_EQ(initial_ihop, threshold); 85 86 ctrl.update_marking_length(1000.0); 87 threshold = ctrl.get_conc_mark_start_threshold(); 88 EXPECT_EQ(initial_ihop, threshold); 89 90 // Whatever we pass, the IHOP value must stay the same. 91 test_update(&ctrl, &alloc_tracker, 2, 10, 10, 3); 92 threshold = ctrl.get_conc_mark_start_threshold(); 93 94 EXPECT_EQ(initial_ihop, threshold); 95 96 test_update(&ctrl, &alloc_tracker, 12, 10, 10, 3); 97 threshold = ctrl.get_conc_mark_start_threshold(); 98 99 EXPECT_EQ(initial_ihop, threshold); 100 } 101 102 // @requires UseG1GC 103 TEST_VM(G1AdaptiveIHOPControl, simple) { 104 // Test requires G1 105 if (!UseG1GC) { 106 return; 107 } 108 109 const size_t initial_threshold = 45; 110 const size_t young_size = 10; 111 const size_t target_size = 100; 112 113 // The final IHOP value is always 114 // target_size - (young_size + alloc_amount/alloc_time * marking_time) 115 116 G1OldGenAllocationTracker alloc_tracker; 117 G1Predictions pred(0.95); 118 G1AdaptiveIHOPControl ctrl(initial_threshold, &alloc_tracker, &pred, 0, 0); 119 ctrl.update_target_occupancy(target_size); 120 121 // First "load". 122 const size_t alloc_time1 = 2; 123 const size_t alloc_amount1 = 10; 124 const size_t marking_time1 = 2; 125 const size_t settled_ihop1 = target_size 126 - (young_size + alloc_amount1 / alloc_time1 * marking_time1); 127 128 size_t threshold; 129 threshold = ctrl.get_conc_mark_start_threshold(); 130 131 EXPECT_EQ(initial_threshold, threshold); 132 133 for (size_t i = 0; i < G1AdaptiveIHOPNumInitialSamples - 1; i++) { 134 test_update_allocation_tracker(&alloc_tracker, alloc_amount1); 135 ctrl.update_allocation_info(alloc_time1, young_size); 136 ctrl.update_marking_length(marking_time1); 137 // Not enough data yet. 138 threshold = ctrl.get_conc_mark_start_threshold(); 139 140 ASSERT_EQ(initial_threshold, threshold) << "on step " << i; 141 } 142 143 test_update(&ctrl, &alloc_tracker, alloc_time1, alloc_amount1, young_size, marking_time1); 144 145 threshold = ctrl.get_conc_mark_start_threshold(); 146 147 EXPECT_EQ(settled_ihop1, threshold); 148 149 // Second "load". A bit higher allocation rate. 150 const size_t alloc_time2 = 2; 151 const size_t alloc_amount2 = 30; 152 const size_t marking_time2 = 2; 153 const size_t settled_ihop2 = target_size 154 - (young_size + alloc_amount2 / alloc_time2 * marking_time2); 155 156 test_update(&ctrl, &alloc_tracker, alloc_time2, alloc_amount2, young_size, marking_time2); 157 158 threshold = ctrl.get_conc_mark_start_threshold(); 159 160 EXPECT_LT(threshold, settled_ihop1); 161 162 // Third "load". Very high (impossible) allocation rate. 163 const size_t alloc_time3 = 1; 164 const size_t alloc_amount3 = 50; 165 const size_t marking_time3 = 2; 166 const size_t settled_ihop3 = 0; 167 168 test_update(&ctrl, &alloc_tracker, alloc_time3, alloc_amount3, young_size, marking_time3); 169 threshold = ctrl.get_conc_mark_start_threshold(); 170 171 EXPECT_EQ(settled_ihop3, threshold); 172 173 // And back to some arbitrary value. 174 test_update(&ctrl, &alloc_tracker, alloc_time2, alloc_amount2, young_size, marking_time2); 175 176 threshold = ctrl.get_conc_mark_start_threshold(); 177 178 EXPECT_GT(threshold, settled_ihop3); 179 } 180 181 TEST_VM(G1AdaptiveIHOPControl, humongous) { 182 // Test requires G1 183 if (!UseG1GC) { 184 return; 185 } 186 187 const size_t initial_threshold = 45; 188 const size_t young_size = 10; 189 const size_t target_size = 100; 190 const double duration = 10.0; 191 const size_t marking_time = 2; 192 193 G1OldGenAllocationTracker alloc_tracker; 194 G1Predictions pred(0.95); 195 G1AdaptiveIHOPControl ctrl(initial_threshold, &alloc_tracker, &pred, 0, 0); 196 ctrl.update_target_occupancy(target_size); 197 198 size_t old_bytes = 100; 199 size_t humongous_bytes = 200; 200 size_t humongous_bytes_after_gc = 150; 201 size_t humongous_bytes_after_last_gc = 50; 202 // Load 1 203 test_update_humongous(&ctrl, &alloc_tracker, duration, 0, humongous_bytes, 204 humongous_bytes_after_last_gc, young_size, marking_time); 205 // Test threshold 206 size_t threshold; 207 threshold = ctrl.get_conc_mark_start_threshold(); 208 // Adjusted allocated bytes: 209 // Total bytes: humongous_bytes 210 // Freed hum bytes: humongous_bytes - humongous_bytes_after_last_gc 211 double alloc_rate = humongous_bytes_after_last_gc / duration; 212 size_t target_threshold = target_size - (size_t)(young_size + alloc_rate * marking_time); 213 214 EXPECT_EQ(threshold, target_threshold); 215 216 // Load 2 217 G1AdaptiveIHOPControl ctrl2(initial_threshold, &alloc_tracker, &pred, 0, 0); 218 ctrl2.update_target_occupancy(target_size); 219 test_update_humongous(&ctrl2, &alloc_tracker, duration, old_bytes, humongous_bytes, 220 humongous_bytes_after_gc, young_size, marking_time); 221 threshold = ctrl2.get_conc_mark_start_threshold(); 222 // Adjusted allocated bytes: 223 // Total bytes: old_bytes + humongous_bytes 224 // Freed hum bytes: humongous_bytes - (humongous_bytes_after_gc - humongous_bytes_after_last_gc) 225 alloc_rate = (old_bytes + (humongous_bytes_after_gc - humongous_bytes_after_last_gc)) / duration; 226 target_threshold = target_size - (size_t)(young_size + alloc_rate * marking_time); 227 228 EXPECT_EQ(threshold, target_threshold); 229 230 // Load 3 231 humongous_bytes_after_last_gc = humongous_bytes_after_gc; 232 humongous_bytes_after_gc = 50; 233 G1AdaptiveIHOPControl ctrl3(initial_threshold, &alloc_tracker, &pred, 0, 0); 234 ctrl3.update_target_occupancy(target_size); 235 test_update_humongous(&ctrl3, &alloc_tracker, duration, old_bytes, humongous_bytes, 236 humongous_bytes_after_gc, young_size, marking_time); 237 threshold = ctrl3.get_conc_mark_start_threshold(); 238 // Adjusted allocated bytes: 239 // All humongous are cleaned up since humongous_bytes_after_gc < humongous_bytes_after_last_gc 240 // Total bytes: old_bytes + humongous_bytes 241 // Freed hum bytes: humongous_bytes 242 alloc_rate = old_bytes / duration; 243 target_threshold = target_size - (size_t)(young_size + alloc_rate * marking_time); 244 245 EXPECT_EQ(threshold, target_threshold); 246 }