2021-06-21 10:06:05 +00:00
|
|
|
|
/*
|
2024-01-29 17:12:13 +00:00
|
|
|
|
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
|
2021-06-21 10:06:05 +00:00
|
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
|
*
|
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
|
*
|
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
|
* accompanied this code).
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*
|
|
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
|
* questions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "precompiled.hpp"
|
|
|
|
|
#include "gc/g1/g1CardSet.inline.hpp"
|
|
|
|
|
#include "gc/g1/g1CardSetContainers.hpp"
|
|
|
|
|
#include "gc/g1/g1CardSetMemory.hpp"
|
2024-02-27 08:58:52 +00:00
|
|
|
|
#include "gc/g1/g1HeapRegionRemSet.hpp"
|
2022-11-08 09:02:11 +00:00
|
|
|
|
#include "gc/g1/g1MonotonicArenaFreePool.hpp"
|
2021-06-21 10:06:05 +00:00
|
|
|
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
2021-10-14 14:05:36 +00:00
|
|
|
|
#include "gc/shared/workerThread.hpp"
|
2021-06-21 10:06:05 +00:00
|
|
|
|
#include "logging/log.hpp"
|
2021-11-27 00:46:09 +00:00
|
|
|
|
#include "memory/allocation.hpp"
|
2021-06-21 10:06:05 +00:00
|
|
|
|
#include "unittest.hpp"
|
|
|
|
|
#include "utilities/powerOfTwo.hpp"
|
|
|
|
|
|
|
|
|
|
class G1CardSetTest : public ::testing::Test {
|
|
|
|
|
|
2021-11-18 16:59:41 +00:00
|
|
|
|
class G1CountCardsClosure : public G1CardSet::CardClosure {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
public:
|
|
|
|
|
size_t _num_cards;
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure() : _num_cards(0) { }
|
|
|
|
|
void do_card(uint region_idx, uint card_idx) override {
|
|
|
|
|
_num_cards++;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-14 14:05:36 +00:00
|
|
|
|
static WorkerThreads* _workers;
|
2021-06-21 10:06:05 +00:00
|
|
|
|
static uint _max_workers;
|
|
|
|
|
|
2021-10-14 14:05:36 +00:00
|
|
|
|
static WorkerThreads* workers() {
|
2024-01-29 17:12:13 +00:00
|
|
|
|
if (_workers == nullptr) {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
_max_workers = os::processor_count();
|
2021-10-14 14:05:36 +00:00
|
|
|
|
_workers = new WorkerThreads("G1CardSetTest Workers", _max_workers);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
_workers->initialize_workers();
|
2021-10-14 14:05:36 +00:00
|
|
|
|
_workers->set_active_workers(_max_workers);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
}
|
|
|
|
|
return _workers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check whether iteration agrees with the expected number of entries. If the
|
|
|
|
|
// add has been single-threaded, we can also check whether the occupied()
|
|
|
|
|
// (which is an estimate in that case) agrees.
|
|
|
|
|
static void check_iteration(G1CardSet* card_set,
|
|
|
|
|
const size_t expected,
|
|
|
|
|
const bool add_was_single_threaded = true);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
G1CardSetTest() { }
|
|
|
|
|
~G1CardSetTest() { }
|
|
|
|
|
|
|
|
|
|
static uint next_random(uint& seed, uint i) {
|
|
|
|
|
// Park–Miller random number generator
|
|
|
|
|
seed = (seed * 279470273u) % 0xfffffffb;
|
|
|
|
|
return (seed % i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cardset_basic_test();
|
|
|
|
|
static void cardset_mt_test();
|
|
|
|
|
|
|
|
|
|
static void add_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards, G1AddCardResult* results);
|
|
|
|
|
static void contains_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards);
|
|
|
|
|
|
|
|
|
|
static void translate_cards(uint cards_per_region, uint region_idx, uint* cards, uint num_cards);
|
|
|
|
|
|
2021-11-18 16:59:41 +00:00
|
|
|
|
static void iterate_cards(G1CardSet* card_set, G1CardSet::CardClosure* cl);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-01-29 17:12:13 +00:00
|
|
|
|
WorkerThreads* G1CardSetTest::_workers = nullptr;
|
2021-06-21 10:06:05 +00:00
|
|
|
|
uint G1CardSetTest::_max_workers = 0;
|
|
|
|
|
|
|
|
|
|
void G1CardSetTest::add_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards, G1AddCardResult* results) {
|
|
|
|
|
for (uint i = 0; i < num_cards; i++) {
|
|
|
|
|
|
|
|
|
|
uint region_idx = cards[i] / cards_per_region;
|
|
|
|
|
uint card_idx = cards[i] % cards_per_region;
|
|
|
|
|
|
|
|
|
|
G1AddCardResult res = card_set->add_card(region_idx, card_idx);
|
2024-01-29 17:12:13 +00:00
|
|
|
|
if (results != nullptr) {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
ASSERT_TRUE(res == results[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-18 16:59:41 +00:00
|
|
|
|
class G1CheckCardClosure : public G1CardSet::CardClosure {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
G1CardSet* _card_set;
|
|
|
|
|
|
|
|
|
|
uint _cards_per_region;
|
|
|
|
|
uint* _cards_to_expect;
|
|
|
|
|
uint _num_cards;
|
|
|
|
|
|
|
|
|
|
bool _wrong_region_idx;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
G1CheckCardClosure(G1CardSet* card_set, uint cards_per_region, uint* cards_to_expect, uint num_cards) :
|
|
|
|
|
_card_set(card_set),
|
|
|
|
|
_cards_per_region(cards_per_region),
|
|
|
|
|
_cards_to_expect(cards_to_expect),
|
|
|
|
|
_num_cards(num_cards),
|
|
|
|
|
_wrong_region_idx(false) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void do_card(uint region_idx, uint card_idx) override {
|
|
|
|
|
uint card = _cards_per_region * region_idx + card_idx;
|
|
|
|
|
for (uint i = 0; i < _num_cards; i++) {
|
|
|
|
|
if (_cards_to_expect[i] == card) {
|
|
|
|
|
_cards_to_expect[i] = (uint)-1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool all_found() const {
|
|
|
|
|
bool all_good = true;
|
|
|
|
|
for (uint i = 0; i < _num_cards; i++) {
|
|
|
|
|
if (_cards_to_expect[i] != (uint)-1) {
|
|
|
|
|
log_error(gc)("Could not find card %u in region %u",
|
|
|
|
|
_cards_to_expect[i] % _cards_per_region,
|
|
|
|
|
_cards_to_expect[i] / _cards_per_region);
|
|
|
|
|
all_good = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return all_good;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void G1CardSetTest::contains_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards) {
|
|
|
|
|
for (uint i = 0; i < num_cards; i++) {
|
|
|
|
|
uint region_idx = cards[i] / cards_per_region;
|
|
|
|
|
uint card_idx = cards[i] % cards_per_region;
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(card_set->contains_card(region_idx, card_idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
G1CheckCardClosure cl(card_set, cards_per_region, cards, num_cards);
|
|
|
|
|
card_set->iterate_cards(cl);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(cl.all_found());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Offsets the card indexes in the cards array by the region_idx.
|
|
|
|
|
void G1CardSetTest::translate_cards(uint cards_per_region, uint region_idx, uint* cards, uint num_cards) {
|
|
|
|
|
for (uint i = 0; i < num_cards; i++) {
|
|
|
|
|
cards[i] = cards_per_region * region_idx + cards[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-17 08:54:29 +00:00
|
|
|
|
class G1CountCardsOccupied : public G1CardSet::ContainerPtrClosure {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
size_t _num_occupied;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
G1CountCardsOccupied() : _num_occupied(0) { }
|
|
|
|
|
|
2022-03-17 08:54:29 +00:00
|
|
|
|
void do_containerptr(uint region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
_num_occupied += num_occupied;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t num_occupied() const { return _num_occupied; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void G1CardSetTest::check_iteration(G1CardSet* card_set, const size_t expected, const bool single_threaded) {
|
|
|
|
|
|
2021-11-18 16:59:41 +00:00
|
|
|
|
class CheckIterator : public G1CardSet::CardClosure {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
public:
|
|
|
|
|
G1CardSet* _card_set;
|
|
|
|
|
size_t _num_found;
|
|
|
|
|
|
|
|
|
|
CheckIterator(G1CardSet* card_set) : _card_set(card_set), _num_found(0) { }
|
|
|
|
|
|
|
|
|
|
void do_card(uint region_idx, uint card_idx) override {
|
|
|
|
|
ASSERT_TRUE(_card_set->contains_card(region_idx, card_idx));
|
|
|
|
|
_num_found++;
|
|
|
|
|
}
|
|
|
|
|
} cl(card_set);
|
|
|
|
|
|
|
|
|
|
card_set->iterate_cards(cl);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(expected == cl._num_found);
|
|
|
|
|
// We can assert this only if we are single-threaded.
|
|
|
|
|
if (single_threaded) {
|
|
|
|
|
ASSERT_EQ(card_set->occupied(), cl._num_found);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void G1CardSetTest::cardset_basic_test() {
|
|
|
|
|
|
|
|
|
|
const uint CardsPerRegion = 2048;
|
|
|
|
|
const double FullCardSetThreshold = 0.8;
|
|
|
|
|
const double BitmapCoarsenThreshold = 0.9;
|
|
|
|
|
|
2021-10-25 01:03:51 +00:00
|
|
|
|
G1CardSetConfiguration config(28,
|
|
|
|
|
BitmapCoarsenThreshold,
|
|
|
|
|
8,
|
|
|
|
|
FullCardSetThreshold,
|
2021-11-15 18:09:32 +00:00
|
|
|
|
CardsPerRegion,
|
|
|
|
|
0);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
G1CardSetFreePool free_pool(config.num_mem_object_types());
|
|
|
|
|
G1CardSetMemoryManager mm(&config, &free_pool);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
uint cards1[] = { 1, 2, 3 };
|
|
|
|
|
G1AddCardResult results1[] = { Added, Added, Added };
|
|
|
|
|
translate_cards(CardsPerRegion, 99, cards1, ARRAY_SIZE(cards1));
|
|
|
|
|
add_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1), results1);
|
|
|
|
|
contains_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1));
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
uint cards1[] = { 0, 2047, 17, 17 };
|
|
|
|
|
G1AddCardResult results1[] = { Added, Added, Added, Found };
|
|
|
|
|
translate_cards(CardsPerRegion, 100, cards1, ARRAY_SIZE(cards1));
|
|
|
|
|
add_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1), results1);
|
|
|
|
|
// -1 because of the duplicate at the end.
|
|
|
|
|
contains_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1) - 1);
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == ARRAY_SIZE(cards1) - 1);
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards == ARRAY_SIZE(cards1) - 1);
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
uint cards1[] = { 0, 2047, 17, 18 /* for region 100 */,
|
|
|
|
|
1, 128, 35, 17 /* for region 990 */
|
|
|
|
|
};
|
|
|
|
|
translate_cards(CardsPerRegion, 100, &cards1[0], 4);
|
|
|
|
|
translate_cards(CardsPerRegion, 990, &cards1[4], 4);
|
|
|
|
|
|
2024-01-29 17:12:13 +00:00
|
|
|
|
add_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1), nullptr);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
contains_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1));
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
uint cards1[100];
|
|
|
|
|
for (uint i = 0; i < ARRAY_SIZE(cards1); i++) {
|
|
|
|
|
cards1[i] = i + 3;
|
|
|
|
|
translate_cards(CardsPerRegion, i, &cards1[i], 1);
|
|
|
|
|
}
|
2024-01-29 17:12:13 +00:00
|
|
|
|
add_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1), nullptr);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
contains_cards(&card_set, CardsPerRegion, cards1, ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(card_set.num_containers() == ARRAY_SIZE(cards1));
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards == ARRAY_SIZE(cards1));
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
// Generate non-prime numbers from 1 to 1000
|
|
|
|
|
uint count = 0;
|
|
|
|
|
for (uint i = 2; i < 33; i++) {
|
|
|
|
|
if (!card_set.contains_card(100, i)) {
|
|
|
|
|
for (uint j = i * i; j < 1000; j += i) {
|
|
|
|
|
G1AddCardResult res = card_set.add_card(100, j);
|
|
|
|
|
count += (res == Added);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
G1CountCardsOccupied cl;
|
|
|
|
|
card_set.iterate_containers(&cl);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(count == card_set.occupied());
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == cl.num_occupied());
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
}
|
|
|
|
|
{ // Test coarsening to full
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
uint count = 0;
|
|
|
|
|
uint i = 10;
|
|
|
|
|
uint bitmap_threshold = config.cards_in_howl_bitmap_threshold();
|
|
|
|
|
for (; i < bitmap_threshold + 10; i++) {
|
|
|
|
|
G1AddCardResult res = card_set.add_card(99, i);
|
|
|
|
|
ASSERT_TRUE(res == Added);
|
|
|
|
|
count++;
|
|
|
|
|
ASSERT_TRUE(count == card_set.occupied());
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-29 13:10:06 +00:00
|
|
|
|
G1AddCardResult res = card_set.add_card(99, config.max_cards_in_howl_bitmap() - 1);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
// Adding above card should have coarsened Bitmap -> Full.
|
|
|
|
|
ASSERT_TRUE(res == Added);
|
2021-11-29 13:10:06 +00:00
|
|
|
|
ASSERT_TRUE(config.max_cards_in_howl_bitmap() == card_set.occupied());
|
2021-06-21 10:06:05 +00:00
|
|
|
|
|
2021-11-29 13:10:06 +00:00
|
|
|
|
res = card_set.add_card(99, config.max_cards_in_howl_bitmap() - 2);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
ASSERT_TRUE(res == Found);
|
|
|
|
|
|
|
|
|
|
uint threshold = config.cards_in_howl_threshold();
|
|
|
|
|
uint adjusted_threshold = config.cards_in_howl_bitmap_threshold() * config.num_buckets_in_howl();
|
2021-11-29 13:10:06 +00:00
|
|
|
|
i = config.max_cards_in_howl_bitmap();
|
2021-06-21 10:06:05 +00:00
|
|
|
|
count = i;
|
|
|
|
|
for (; i < threshold; i++) {
|
|
|
|
|
G1AddCardResult res = card_set.add_card(99, i);
|
|
|
|
|
ASSERT_TRUE(res == Added);
|
|
|
|
|
count++;
|
|
|
|
|
ASSERT_TRUE(count == card_set.occupied());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = card_set.add_card(99, CardsPerRegion - 1);
|
|
|
|
|
// Adding above card should have coarsened Howl -> Full.
|
|
|
|
|
ASSERT_TRUE(res == Added);
|
|
|
|
|
ASSERT_TRUE(CardsPerRegion == card_set.occupied());
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, card_set.occupied());
|
|
|
|
|
|
|
|
|
|
res = card_set.add_card(99, CardsPerRegion - 2);
|
|
|
|
|
ASSERT_TRUE(res == Found);
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards == config.max_cards_in_region());
|
|
|
|
|
|
|
|
|
|
card_set.clear();
|
|
|
|
|
ASSERT_TRUE(card_set.occupied() == 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-14 14:05:36 +00:00
|
|
|
|
class G1CardSetMtTestTask : public WorkerTask {
|
2021-06-21 10:06:05 +00:00
|
|
|
|
G1CardSet* _card_set;
|
|
|
|
|
|
|
|
|
|
size_t _added;
|
|
|
|
|
size_t _found;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
G1CardSetMtTestTask(G1CardSet* card_set) :
|
2021-10-14 14:05:36 +00:00
|
|
|
|
WorkerTask(""),
|
2021-06-21 10:06:05 +00:00
|
|
|
|
_card_set(card_set),
|
|
|
|
|
_added(0),
|
|
|
|
|
_found(0) { }
|
|
|
|
|
|
|
|
|
|
void work(uint worker_id) {
|
|
|
|
|
uint seed = worker_id;
|
|
|
|
|
size_t added = 0;
|
|
|
|
|
size_t found = 0;
|
|
|
|
|
|
|
|
|
|
for (uint i = 0; i < 100000; i++) {
|
|
|
|
|
uint region = G1CardSetTest::next_random(seed, 1000);
|
|
|
|
|
uint card = G1CardSetTest::next_random(seed, 10000);
|
|
|
|
|
|
|
|
|
|
G1AddCardResult res = _card_set->add_card(region, card);
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(res == Added || res == Found);
|
|
|
|
|
if (res == Added) {
|
|
|
|
|
added++;
|
|
|
|
|
} else if (res == Found) {
|
|
|
|
|
found++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Atomic::add(&_added, added);
|
|
|
|
|
Atomic::add(&_found, found);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t added() const { return _added; }
|
|
|
|
|
size_t found() const { return _found; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void G1CardSetTest::cardset_mt_test() {
|
|
|
|
|
const uint CardsPerRegion = 16384;
|
|
|
|
|
const double FullCardSetThreshold = 1.0;
|
|
|
|
|
const uint BitmapCoarsenThreshold = 1.0;
|
|
|
|
|
|
2021-10-25 01:03:51 +00:00
|
|
|
|
G1CardSetConfiguration config(120,
|
|
|
|
|
BitmapCoarsenThreshold,
|
|
|
|
|
8,
|
|
|
|
|
FullCardSetThreshold,
|
2021-11-15 18:09:32 +00:00
|
|
|
|
CardsPerRegion,
|
|
|
|
|
0);
|
2021-06-21 10:06:05 +00:00
|
|
|
|
G1CardSetFreePool free_pool(config.num_mem_object_types());
|
|
|
|
|
G1CardSetMemoryManager mm(&config, &free_pool);
|
|
|
|
|
|
|
|
|
|
G1CardSet card_set(&config, &mm);
|
|
|
|
|
|
|
|
|
|
const uint num_workers = workers()->active_workers();
|
|
|
|
|
|
|
|
|
|
G1CardSetMtTestTask cl(&card_set);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
GCTraceTime(Error, gc) x("Cardset test");
|
|
|
|
|
_workers->run_task(&cl, num_workers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t num_found = 0;
|
|
|
|
|
// Now check the contents of the card set.
|
|
|
|
|
for (uint i = 0; i < num_workers; i++) {
|
|
|
|
|
uint seed = i;
|
|
|
|
|
|
|
|
|
|
for (uint j = 0; j < 100000; j++) {
|
|
|
|
|
uint region = G1CardSetTest::next_random(seed, 1000);
|
|
|
|
|
uint card = G1CardSetTest::next_random(seed, 10000);
|
|
|
|
|
|
|
|
|
|
bool contains = card_set.contains_card(region, card);
|
|
|
|
|
ASSERT_TRUE(contains);
|
|
|
|
|
|
|
|
|
|
num_found += contains;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT_TRUE(num_found == cl.added() + cl.found());
|
|
|
|
|
|
|
|
|
|
G1CountCardsClosure count_cards;
|
|
|
|
|
card_set.iterate_cards(count_cards);
|
|
|
|
|
|
|
|
|
|
check_iteration(&card_set, count_cards._num_cards, false /* add_was_single_threaded */);
|
|
|
|
|
|
|
|
|
|
// During coarsening we try to unblock concurrent threads as soon as possible,
|
|
|
|
|
// so we do not add the cards from the smaller CardSetContainer to the larger
|
|
|
|
|
// one immediately, allowing addition by concurrent threads after allocating
|
|
|
|
|
// the space immediately. So the amount of "successfully added" results may be
|
|
|
|
|
// (and in case of many threads typically is) higher than the number of unique
|
|
|
|
|
// cards.
|
|
|
|
|
ASSERT_TRUE(count_cards._num_cards <= cl.added());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_VM(G1CardSetTest, basic_cardset_test) {
|
|
|
|
|
G1CardSetTest::cardset_basic_test();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_VM(G1CardSetTest, mt_cardset_test) {
|
|
|
|
|
G1CardSetTest::cardset_mt_test();
|
|
|
|
|
}
|