1 /* 2 * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018, 2020 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 #include "metaspace/metaspaceTestsCommon.hpp" 28 #include "metaspace/metaspaceTestContexts.hpp" 29 #include "runtime/mutexLocker.hpp" 30 31 using namespace metaspace::chunklevel; 32 33 // Test ChunkManager::get_chunk 34 TEST_VM(metaspace, get_chunk) { 35 36 ChunkTestsContext helper(8 * M); 37 Metachunk* c = NULL; 38 39 for (chunklevel_t pref_lvl = LOWEST_CHUNK_LEVEL; pref_lvl <= HIGHEST_CHUNK_LEVEL; pref_lvl ++) { 40 41 for (chunklevel_t max_lvl = pref_lvl; max_lvl <= HIGHEST_CHUNK_LEVEL; max_lvl ++) { 42 43 for (size_t min_committed_words = Settings::commit_granule_words(); 44 min_committed_words <= word_size_for_level(max_lvl); min_committed_words *= 2) { 45 helper.alloc_chunk_expect_success(&c, pref_lvl, max_lvl, min_committed_words); 46 helper.return_chunk(c); 47 } 48 } 49 } 50 } 51 52 // Test ChunkManager::get_chunk, but with a commit limit. 53 TEST_VM(metaspace, get_chunk_with_commit_limit) { 54 55 const size_t commit_limit_words = 1 * M; 56 ChunkTestsContext helper(commit_limit_words); 57 Metachunk* c = NULL; 58 59 for (chunklevel_t pref_lvl = LOWEST_CHUNK_LEVEL; pref_lvl <= HIGHEST_CHUNK_LEVEL; pref_lvl ++) { 60 61 for (chunklevel_t max_lvl = pref_lvl; max_lvl <= HIGHEST_CHUNK_LEVEL; max_lvl ++) { 62 63 for (size_t min_committed_words = Settings::commit_granule_words(); 64 min_committed_words <= word_size_for_level(max_lvl); min_committed_words *= 2) { 65 66 if (min_committed_words <= commit_limit_words) { 67 helper.alloc_chunk_expect_success(&c, pref_lvl, max_lvl, min_committed_words); 68 helper.return_chunk(c); 69 } else { 70 helper.alloc_chunk_expect_failure(pref_lvl, max_lvl, min_committed_words); 71 } 72 73 } 74 } 75 } 76 } 77 78 // Test that recommitting the used portion of a chunk will preserve the original content. 79 TEST_VM(metaspace, get_chunk_recommit) { 80 81 ChunkTestsContext helper; 82 Metachunk* c = NULL; 83 helper.alloc_chunk_expect_success(&c, ROOT_CHUNK_LEVEL, ROOT_CHUNK_LEVEL, 0); 84 helper.uncommit_chunk_with_test(c); 85 86 helper.commit_chunk_with_test(c, Settings::commit_granule_words()); 87 helper.allocate_from_chunk(c, Settings::commit_granule_words()); 88 89 c->ensure_committed(Settings::commit_granule_words()); 90 check_range_for_pattern(c->base(), c->used_words(), (uintx)c); 91 92 c->ensure_committed(Settings::commit_granule_words() * 2); 93 check_range_for_pattern(c->base(), c->used_words(), (uintx)c); 94 95 helper.return_chunk(c); 96 97 } 98 99 // Test ChunkManager::get_chunk, but with a reserve limit. 100 // (meaning, the underlying VirtualSpaceList cannot expand, like compressed class space). 101 TEST_VM(metaspace, get_chunk_with_reserve_limit) { 102 103 const size_t reserve_limit_words = word_size_for_level(ROOT_CHUNK_LEVEL); 104 const size_t commit_limit_words = 1024 * M; // just very high 105 ChunkTestsContext helper(commit_limit_words, reserve_limit_words); 106 107 // Reserve limit works at root chunk size granularity: if the chunk manager cannot satisfy 108 // a request for a chunk from its freelists, it will acquire a new root chunk from the 109 // underlying virtual space list. If that list is full and cannot be expanded (think ccs) 110 // we should get an error. 111 // Testing this is simply testing a chunk allocation which should cause allocation of a new 112 // root chunk. 113 114 // Cause allocation of the firstone root chunk, should still work: 115 Metachunk* c = NULL; 116 helper.alloc_chunk_expect_success(&c, HIGHEST_CHUNK_LEVEL); 117 118 // and this should need a new root chunk and hence fail: 119 helper.alloc_chunk_expect_failure(ROOT_CHUNK_LEVEL); 120 121 helper.return_chunk(c); 122 123 } 124 125 // Test MetaChunk::allocate 126 TEST_VM(metaspace, chunk_allocate_full) { 127 128 ChunkTestsContext helper; 129 130 for (chunklevel_t lvl = LOWEST_CHUNK_LEVEL; lvl <= HIGHEST_CHUNK_LEVEL; lvl ++) { 131 Metachunk* c = NULL; 132 helper.alloc_chunk_expect_success(&c, lvl); 133 helper.allocate_from_chunk(c, c->word_size()); 134 helper.return_chunk(c); 135 } 136 137 } 138 139 // Test MetaChunk::allocate 140 TEST_VM(metaspace, chunk_allocate_random) { 141 142 ChunkTestsContext helper; 143 144 for (chunklevel_t lvl = LOWEST_CHUNK_LEVEL; lvl <= HIGHEST_CHUNK_LEVEL; lvl ++) { 145 146 Metachunk* c = NULL; 147 helper.alloc_chunk_expect_success(&c, lvl); 148 helper.uncommit_chunk_with_test(c); // start out fully uncommitted 149 150 RandSizeGenerator rgen(1, c->word_size() / 30); 151 bool stop = false; 152 153 while (!stop) { 154 const size_t s = rgen.get(); 155 if (s <= c->free_words()) { 156 helper.commit_chunk_with_test(c, s); 157 helper.allocate_from_chunk(c, s); 158 } else { 159 stop = true; 160 } 161 162 } 163 helper.return_chunk(c); 164 165 } 166 167 } 168 169 TEST_VM(metaspace, chunk_buddy_stuff) { 170 171 for (chunklevel_t l = ROOT_CHUNK_LEVEL + 1; l <= HIGHEST_CHUNK_LEVEL; l ++) { 172 173 ChunkTestsContext helper; 174 175 // Allocate two chunks; since we know the first chunk is the first in its area, 176 // it has to be a leader, and the next one of the same size its buddy. 177 178 // (Note: strictly speaking the ChunkManager does not promise any placement but 179 // we know how the placement works so these tests make sense). 180 181 Metachunk* c1 = NULL; 182 helper.alloc_chunk(&c1, CHUNK_LEVEL_1K); 183 EXPECT_TRUE(c1->is_leader()); 184 185 Metachunk* c2 = NULL; 186 helper.alloc_chunk(&c2, CHUNK_LEVEL_1K); 187 EXPECT_FALSE(c2->is_leader()); 188 189 // buddies are adjacent in memory 190 // (next/prev_in_vs needs lock) 191 { 192 MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); 193 EXPECT_EQ(c1->next_in_vs(), c2); 194 EXPECT_EQ(c1->end(), c2->base()); 195 EXPECT_NULL(c1->prev_in_vs()); // since we know this is the first in the area 196 EXPECT_EQ(c2->prev_in_vs(), c1); 197 } 198 199 helper.return_chunk(c1); 200 helper.return_chunk(c2); 201 202 } 203 204 } 205 206 207 TEST_VM(metaspace, chunk_allocate_with_commit_limit) { 208 209 // This test does not make sense if commit-on-demand is off 210 if (Settings::new_chunks_are_fully_committed()) { 211 return; 212 } 213 214 const size_t granule_sz = Settings::commit_granule_words(); 215 const size_t commit_limit = granule_sz * 3; 216 ChunkTestsContext helper(commit_limit); 217 218 // A big chunk, but uncommitted. 219 Metachunk* c = NULL; 220 helper.alloc_chunk_expect_success(&c, ROOT_CHUNK_LEVEL, ROOT_CHUNK_LEVEL, 0); 221 helper.uncommit_chunk_with_test(c); // ... just to make sure. 222 223 // first granule... 224 helper.commit_chunk_with_test(c, granule_sz); 225 helper.allocate_from_chunk(c, granule_sz); 226 227 // second granule... 228 helper.commit_chunk_with_test(c, granule_sz); 229 helper.allocate_from_chunk(c, granule_sz); 230 231 // third granule... 232 helper.commit_chunk_with_test(c, granule_sz); 233 helper.allocate_from_chunk(c, granule_sz); 234 235 // This should fail now. 236 helper.commit_chunk_expect_failure(c, granule_sz); 237 238 helper.return_chunk(c); 239 240 } 241 242 // Test splitting a chunk 243 TEST_VM(metaspace, chunk_split_and_merge) { 244 245 // Split works like this: 246 // 247 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 248 // | A | 249 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 250 // 251 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 252 // | A' | b | c | d | e | 253 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 254 // 255 // A original chunk (A) is split to form a target chunk (A') and as a result splinter 256 // chunks form (b..e). A' is the leader of the (A',b) pair, which is the leader of the 257 // ((A',b), c) pair and so on. In other words, A' will be a leader chunk, all splinter 258 // chunks are follower chunks. 259 // 260 // Merging reverses this operation: 261 // 262 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 263 // | A | b | c | d | e | 264 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 265 // 266 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 267 // | A' | 268 // ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 269 // 270 // (A) will be merged with its buddy b, (A+b) with its buddy c and so on. The result 271 // chunk is A'. 272 // Note that merging also works, of course, if we were to start the merge at (b) (so, 273 // with a follower chunk, not a leader). Also, at any point in the merge 274 // process we may arrive at a follower chunk. So, the fact that in this test 275 // we only expect a leader merge is a feature of the test, and of the fact that we 276 // start each split test with a fresh MetaspaceTestHelper. 277 278 // Note: Splitting and merging chunks is usually done from within the ChunkManager and 279 // subject to a lot of assumptions and hence asserts. Here, we have to explicitly use 280 // VirtualSpaceNode::split/::merge and therefore have to observe rules: 281 // - both split and merge expect free chunks, so state has to be "free" 282 // - but that would trigger the "ideally merged" assertion in the RootChunkArea, so the 283 // original chunk has to be a root chunk, we cannot just split any chunk manually. 284 // - Also, after the split we have to completely re-merge to avoid triggering asserts 285 // in ~RootChunkArea() 286 // - finally we have to lock manually 287 288 ChunkTestsContext helper; 289 290 const chunklevel_t orig_lvl = ROOT_CHUNK_LEVEL; 291 for (chunklevel_t target_lvl = orig_lvl + 1; target_lvl <= HIGHEST_CHUNK_LEVEL; target_lvl ++) { 292 293 // Split a fully committed chunk. The resulting chunk should be fully 294 // committed as well, and have its content preserved. 295 Metachunk* c = NULL; 296 helper.alloc_chunk_expect_success(&c, orig_lvl); 297 298 // We allocate from this chunk to be able to completely paint the payload. 299 helper.allocate_from_chunk(c, c->word_size()); 300 301 const uintx canary = os::random(); 302 fill_range_with_pattern(c->base(), c->word_size(), canary); 303 304 FreeChunkListVector splinters; 305 306 { 307 // Splitting/Merging chunks is usually done by the chunkmanager, and no explicit 308 // outside API exists. So we split/merge chunks via the underlying vs node, directly. 309 // This means that we have to go through some extra hoops to not trigger any asserts. 310 MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); 311 c->reset_used_words(); 312 c->set_free(); 313 c->vsnode()->split(target_lvl, c, &splinters); 314 } 315 316 DEBUG_ONLY(helper.verify();) 317 318 EXPECT_EQ(c->level(), target_lvl); 319 EXPECT_TRUE(c->is_fully_committed()); 320 EXPECT_FALSE(c->is_root_chunk()); 321 EXPECT_TRUE(c->is_leader()); 322 323 check_range_for_pattern(c->base(), c->word_size(), canary); 324 325 // I expect splinter chunks (one for each splinter level: 326 // e.g. splitting a 1M chunk to get a 64K chunk should yield splinters: [512K, 256K, 128K, 64K] 327 for (chunklevel_t l = LOWEST_CHUNK_LEVEL; l < HIGHEST_CHUNK_LEVEL; l ++) { 328 const Metachunk* c2 = splinters.first_at_level(l); 329 if (l > orig_lvl && l <= target_lvl) { 330 EXPECT_NOT_NULL(c2); 331 EXPECT_EQ(c2->level(), l); 332 EXPECT_TRUE(c2->is_free()); 333 EXPECT_TRUE(!c2->is_leader()); 334 DEBUG_ONLY(c2->verify(false)); 335 check_range_for_pattern(c2->base(), c2->word_size(), canary); 336 } else { 337 EXPECT_NULL(c2); 338 } 339 } 340 341 // Revert the split by using merge. This should result in all splinters coalescing 342 // to one chunk. 343 { 344 MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); 345 Metachunk* merged = c->vsnode()->merge(c, &splinters); 346 347 // the merged chunk should occupy the same address as the splinter 348 // since it should have been the leader in the split. 349 EXPECT_EQ(merged, c); 350 EXPECT_TRUE(merged->is_root_chunk() || merged->is_leader()); 351 352 // Splitting should have arrived at the original chunk since none of the splinters are in use. 353 EXPECT_EQ(c->level(), orig_lvl); 354 355 // All splinters should have been removed from the list 356 EXPECT_EQ(splinters.num_chunks(), 0); 357 } 358 359 helper.return_chunk(c); 360 361 } 362 363 } 364 365 TEST_VM(metaspace, chunk_enlarge_in_place) { 366 367 ChunkTestsContext helper; 368 369 // Starting with the smallest chunk size, attempt to enlarge the chunk in place until we arrive 370 // at root chunk size. Since the state is clean, this should work. 371 372 Metachunk* c = NULL; 373 helper.alloc_chunk_expect_success(&c, HIGHEST_CHUNK_LEVEL); 374 375 chunklevel_t l = c->level(); 376 377 while (l != ROOT_CHUNK_LEVEL) { 378 379 // commit and allocate from chunk to pattern it... 380 const size_t original_chunk_size = c->word_size(); 381 helper.commit_chunk_with_test(c, c->free_words()); 382 helper.allocate_from_chunk(c, c->free_words()); 383 384 size_t used_before = c->used_words(); 385 size_t free_before = c->free_words(); 386 size_t free_below_committed_before = c->free_below_committed_words(); 387 const MetaWord* top_before = c->top(); 388 389 EXPECT_TRUE(helper.cm().attempt_enlarge_chunk(c)); 390 EXPECT_EQ(l - 1, c->level()); 391 EXPECT_EQ(c->word_size(), original_chunk_size * 2); 392 393 // Used words should not have changed 394 EXPECT_EQ(c->used_words(), used_before); 395 EXPECT_EQ(c->top(), top_before); 396 397 // free words should be expanded by the old size (since old chunk is doubled in size) 398 EXPECT_EQ(c->free_words(), free_before + original_chunk_size); 399 400 // free below committed can be larger but never smaller 401 EXPECT_GE(c->free_below_committed_words(), free_below_committed_before); 402 403 // Old content should be preserved 404 check_range_for_pattern(c->base(), original_chunk_size, (uintx)c); 405 406 l = c->level(); 407 } 408 409 helper.return_chunk(c); 410 411 } 412