Path: blob/master/test/hotspot/gtest/metaspace/test_metachunklist.cpp
41144 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "memory/metaspace/counters.hpp"27#include "memory/metaspace/freeChunkList.hpp"28#include "memory/metaspace/metachunkList.hpp"29#include "memory/metaspace/metaspaceSettings.hpp"30//#define LOG_PLEASE31#include "metaspaceGtestCommon.hpp"32#include "metaspaceGtestContexts.hpp"33#include "metaspaceGtestRangeHelpers.hpp"3435using metaspace::FreeChunkList;36using metaspace::FreeChunkListVector;37using metaspace::MemRangeCounter;38using metaspace::MetachunkList;39using metaspace::Settings;4041TEST_VM(metaspace, metachunklist) {4243ChunkGtestContext context;4445MetachunkList lst;4647Metachunk* chunks[10];48size_t total_size = 0;4950for (int i = 0; i < 10; i++) {51Metachunk* c = NULL;52context.alloc_chunk_expect_success(&c, ChunkLevelRanges::all_chunks().random_value());53chunks[i] = c;54total_size += c->committed_words();5556lst.add(c);57EXPECT_EQ(lst.first(), c);5859Metachunk* c2 = lst.remove_first();60EXPECT_EQ(c, c2);6162EXPECT_EQ(lst.count(), i);63lst.add(c);64EXPECT_EQ(lst.count(), i + 1);65EXPECT_EQ(lst.calc_committed_word_size(), total_size);6667}6869for (int i = 0; i < 10; i++) {70DEBUG_ONLY(EXPECT_TRUE(lst.contains(chunks[i]));)71}7273for (int i = 0; i < 10; i++) {74Metachunk* c = lst.remove_first();75DEBUG_ONLY(EXPECT_FALSE(lst.contains(c));)76context.return_chunk(c);77}7879EXPECT_EQ(lst.count(), 0);80EXPECT_EQ(lst.calc_committed_word_size(), (size_t)0);8182}8384TEST_VM(metaspace, freechunklist) {8586ChunkGtestContext context;8788FreeChunkListVector lst;8990MemRangeCounter cnt;91MemRangeCounter committed_cnt;9293// Add random chunks to list and check the counter apis (word_size, commited_word_size, num_chunks)94// Make every other chunk randomly uncommitted, and later we check that committed chunks are sorted in at the front95// of the lists.96for (int i = 0; i < 100; i++) {97Metachunk* c = NULL;98context.alloc_chunk_expect_success(&c, ChunkLevelRanges::all_chunks().random_value());99bool uncommitted_chunk = i % 3;100if (uncommitted_chunk) {101context.uncommit_chunk_with_test(c);102c->set_in_use();103}104105lst.add(c);106107LOG("->" METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c));108109cnt.add(c->word_size());110committed_cnt.add(c->committed_words());111112EXPECT_EQ(lst.num_chunks(), (int)cnt.count());113EXPECT_EQ(lst.word_size(), cnt.total_size());114EXPECT_EQ(lst.calc_committed_word_size(), committed_cnt.total_size());115}116117// Drain each list separately, front to back. While draining observe the order118// in which the chunks come: since uncommitted chunks are added to the tail of119// the list (see FreeChunkList::add_chunk()), no committed chunk should ever120// follow an uncommitted chunk.121for (chunklevel_t lvl = LOWEST_CHUNK_LEVEL; lvl <= HIGHEST_CHUNK_LEVEL; lvl++) {122Metachunk* c = lst.remove_first(lvl);123bool found_uncommitted = false;124while (c != NULL) {125126LOG("<-" METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c));127128if (found_uncommitted) {129EXPECT_TRUE(c->is_fully_uncommitted());130} else {131found_uncommitted = c->is_fully_uncommitted();132}133134cnt.sub(c->word_size());135committed_cnt.sub(c->committed_words());136137EXPECT_EQ(lst.num_chunks(), (int)cnt.count());138EXPECT_EQ(lst.word_size(), cnt.total_size());139EXPECT_EQ(lst.calc_committed_word_size(), committed_cnt.total_size());140141context.return_chunk(c);142143c = lst.remove_first(lvl);144}145}146147}148149// Test, for a list populated with a mixture of fully/partially/uncommitted chunks,150// the retrieval-by-minimally-committed-words function.151TEST_VM(metaspace, freechunklist_retrieval) {152153if (Settings::new_chunks_are_fully_committed()) {154return;155}156157ChunkGtestContext context;158FreeChunkList fcl;159Metachunk* c = NULL;160161// For a chunk level which allows us to have partially committed chunks...162const size_t chunk_word_size = Settings::commit_granule_words() * 4;163const chunklevel_t lvl = level_fitting_word_size(chunk_word_size);164165// get some chunks:166167// ...a completely uncommitted one ...168Metachunk* c_0 = NULL;169context.alloc_chunk_expect_success(&c_0, lvl, lvl, 0);170171// ... a fully committed one ...172Metachunk* c_full = NULL;173context.alloc_chunk_expect_success(&c_full, lvl);174175// ... a chunk with one commit granule committed ...176Metachunk* c_1g = NULL;177context.alloc_chunk_expect_success(&c_1g, lvl, lvl, Settings::commit_granule_words());178179// ... a chunk with two commit granules committed.180Metachunk* c_2g = NULL;181context.alloc_chunk_expect_success(&c_2g, lvl, lvl, Settings::commit_granule_words() * 2);182183LOG("c_0: " METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c_0));184LOG("c_full: " METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c_full));185LOG("c_1g: " METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c_1g));186LOG("c_2g: " METACHUNK_FULL_FORMAT, METACHUNK_FULL_FORMAT_ARGS(c_2g));187188189// Simple check 1. Empty list should yield nothing.190{191c = fcl.first_minimally_committed(0);192ASSERT_NULL(c);193}194195// Simple check 2. Just a single uncommitted chunk.196{197fcl.add(c_0);198c = fcl.first_minimally_committed(0);199ASSERT_EQ(c_0, c);200c = fcl.first_minimally_committed(1);201ASSERT_NULL(c);202fcl.remove(c_0);203}204205// Now a check with a fully populated list.206// For different insert orders, try to retrieve different chunks by minimal commit level207// and check the result.208for (int insert_order = 0; insert_order < 4; insert_order ++) {209210switch (insert_order) {211case 0:212fcl.add(c_0);213fcl.add(c_full);214fcl.add(c_1g);215fcl.add(c_2g);216break;217case 1:218fcl.add(c_1g);219fcl.add(c_2g);220fcl.add(c_0);221fcl.add(c_full);222break;223case 2:224fcl.add(c_2g);225fcl.add(c_1g);226fcl.add(c_full);227fcl.add(c_0);228break;229case 3:230fcl.add(c_full);231fcl.add(c_2g);232fcl.add(c_1g);233fcl.add(c_0);234break;235}236237c = fcl.first_minimally_committed(0);238ASSERT_TRUE(c == c_full || c == c_0 || c == c_1g || c == c_2g);239240c = fcl.first_minimally_committed(1);241ASSERT_TRUE(c == c_full || c == c_1g || c == c_2g);242243c = fcl.first_minimally_committed(Settings::commit_granule_words());244ASSERT_TRUE(c == c_full || c == c_1g || c == c_2g);245246c = fcl.first_minimally_committed(Settings::commit_granule_words() + 1);247ASSERT_TRUE(c == c_full || c == c_2g);248249c = fcl.first_minimally_committed(Settings::commit_granule_words() * 2);250ASSERT_TRUE(c == c_full || c == c_2g);251252c = fcl.first_minimally_committed((Settings::commit_granule_words() * 2) + 1);253ASSERT_TRUE(c == c_full);254255c = fcl.first_minimally_committed(chunk_word_size);256ASSERT_TRUE(c == c_full);257258c = fcl.first_minimally_committed(chunk_word_size + 1);259ASSERT_NULL(c);260261fcl.remove(c_0);262fcl.remove(c_full);263fcl.remove(c_1g);264fcl.remove(c_2g);265266}267268context.return_chunk(c_0);269context.return_chunk(c_full);270context.return_chunk(c_1g);271context.return_chunk(c_2g);272273}274275276277