26
#include "precompiled.hpp"
27
#include "memory/metaspace/chunkManager.hpp"
28
#include "memory/metaspace/counters.hpp"
29
#include "memory/metaspace/metaspaceArena.hpp"
30
#include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
31
#include "memory/metaspace/metaspaceSettings.hpp"
32
#include "memory/metaspace/metaspaceStatistics.hpp"
33
#include "runtime/mutexLocker.hpp"
34
#include "utilities/debug.hpp"
35
#include "utilities/globalDefinitions.hpp"
37
#include "metaspaceGtestCommon.hpp"
38
#include "metaspaceGtestContexts.hpp"
39
#include "metaspaceGtestSparseArray.hpp"
41
using metaspace::AllocationAlignmentByteSize;
42
using metaspace::ArenaGrowthPolicy;
43
using metaspace::ChunkManager;
44
using metaspace::IntCounter;
45
using metaspace::MemRangeCounter;
46
using metaspace::MetaspaceArena;
47
using metaspace::SizeAtomicCounter;
48
using metaspace::ArenaStats;
49
using metaspace::InUseChunkStats;
52
static bool fifty_fifty() {
53
return IntRange(100).random_value() < 50;
58
class MetaspaceArenaTestBed : public CHeapObj<mtInternal> {
60
MetaspaceArena* _arena;
62
const SizeRange _allocation_range;
63
size_t _size_of_last_failed_allocation;
72
mark_range(p, word_size);
76
check_marked_range(p, word_size);
81
allocation_t* _allocations;
84
MemRangeCounter _alloc_count;
85
MemRangeCounter _dealloc_count;
90
void verify_arena_statistics() const {
93
_arena->add_to_statistics(&stats);
94
InUseChunkStats in_use_stats = stats.totals();
96
assert(_dealloc_count.total_size() <= _alloc_count.total_size() &&
97
_dealloc_count.count() <= _alloc_count.count(), "Sanity");
100
ASSERT_GE(in_use_stats._word_size, in_use_stats._committed_words);
101
ASSERT_EQ(in_use_stats._committed_words,
102
in_use_stats._used_words + in_use_stats._free_words + in_use_stats._waste_words);
103
ASSERT_GE(in_use_stats._used_words, stats._free_blocks_word_size);
112
const size_t at_least_allocated = _alloc_count.total_size() - _dealloc_count.total_size();
115
constexpr size_t max_word_overhead_per_alloc = 4;
116
const size_t at_most_allocated = _alloc_count.total_size() + max_word_overhead_per_alloc * _alloc_count.count();
118
ASSERT_LE(at_least_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
119
ASSERT_GE(at_most_allocated, in_use_stats._used_words - stats._free_blocks_word_size);
125
MetaspaceArena* arena() { return _arena; }
127
MetaspaceArenaTestBed(ChunkManager* cm, const ArenaGrowthPolicy* alloc_sequence,
128
SizeAtomicCounter* used_words_counter, SizeRange allocation_range) :
130
_allocation_range(allocation_range),
131
_size_of_last_failed_allocation(0),
132
_allocations(nullptr),
136
_arena = new MetaspaceArena(cm, alloc_sequence, used_words_counter, "gtest-MetaspaceArenaTestBed-sm");
139
~MetaspaceArenaTestBed() {
141
verify_arena_statistics();
143
allocation_t* a = _allocations;
144
while (a != nullptr) {
145
allocation_t* b = a->next;
151
DEBUG_ONLY(_arena->verify();)
158
size_t words_allocated() const { return _alloc_count.total_size(); }
159
int num_allocations() const { return _alloc_count.count(); }
161
size_t size_of_last_failed_allocation() const { return _size_of_last_failed_allocation; }
164
bool checked_random_allocate() {
165
size_t word_size = 1 + _allocation_range.random_value();
166
MetaWord* p = _arena->allocate(word_size);
168
EXPECT_TRUE(is_aligned(p, AllocationAlignmentByteSize));
170
allocation_t* a = NEW_C_HEAP_OBJ(allocation_t, mtInternal);
171
a->word_size = word_size;
174
a->next = _allocations;
176
_alloc_count.add(word_size);
177
if ((_alloc_count.count() % 20) == 0) {
178
verify_arena_statistics();
179
DEBUG_ONLY(_arena->verify();)
183
_size_of_last_failed_allocation = word_size;
189
void checked_random_deallocate() {
190
allocation_t* a = _allocations;
191
while (a && a->p != nullptr && os::random() % 10 != 0) {
194
if (a != nullptr && a->p != nullptr) {
196
_arena->deallocate(a->p, a->word_size);
197
_dealloc_count.add(a->word_size);
198
a->p = nullptr; a->word_size = 0;
199
if ((_dealloc_count.count() % 20) == 0) {
200
verify_arena_statistics();
201
DEBUG_ONLY(_arena->verify();)
208
class MetaspaceArenaTest {
210
MetaspaceGtestContext _context;
212
SizeAtomicCounter _used_words_counter;
214
SparseArray<MetaspaceArenaTestBed*> _testbeds;
215
IntCounter _num_beds;
219
void create_new_test_bed_at(int slotindex, const ArenaGrowthPolicy* growth_policy, SizeRange allocation_range) {
220
DEBUG_ONLY(_testbeds.check_slot_is_null(slotindex));
221
MetaspaceArenaTestBed* bed = new MetaspaceArenaTestBed(&_context.cm(), growth_policy,
222
&_used_words_counter, allocation_range);
223
_testbeds.set_at(slotindex, bed);
224
_num_beds.increment();
227
void create_random_test_bed_at(int slotindex) {
228
SizeRange allocation_range(1, 100);
229
const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(
230
(fifty_fifty() ? Metaspace::StandardMetaspaceType : Metaspace::ReflectionMetaspaceType),
232
create_new_test_bed_at(slotindex, growth_policy, allocation_range);
237
bool create_random_test_bed() {
238
const int slot = _testbeds.random_null_slot_index();
240
create_random_test_bed_at(slot);
246
void create_all_test_beds() {
247
for (int slot = 0; slot < _testbeds.size(); slot++) {
248
if (_testbeds.slot_is_null(slot)) {
249
create_random_test_bed_at(slot);
254
void delete_test_bed_at(int slotindex) {
255
DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex));
256
MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
258
_testbeds.set_at(slotindex, nullptr);
259
_num_beds.decrement();
264
bool delete_random_test_bed() {
265
const int slotindex = _testbeds.random_non_null_slot_index();
266
if (slotindex != -1) {
267
delete_test_bed_at(slotindex);
274
void delete_all_test_beds() {
275
for (int slot = _testbeds.first_non_null_slot(); slot != -1; slot = _testbeds.next_non_null_slot(slot)) {
276
delete_test_bed_at(slot);
282
bool random_allocate_from_testbed(int slotindex) {
283
DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex);)
284
MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
285
bool success = bed->checked_random_allocate();
286
if (success == false) {
288
EXPECT_LT(_context.commit_limiter().possible_expansion_words(),
289
metaspace::get_raw_word_size_for_requested_word_size(bed->size_of_last_failed_allocation()));
295
bool random_allocate_multiple_times_from_testbed(int slotindex, int num_allocations) {
298
while (success && n < num_allocations) {
299
success = random_allocate_from_testbed(slotindex);
306
bool random_allocate_random_times_from_random_testbed() {
307
int slot = _testbeds.random_non_null_slot_index();
308
bool success = false;
310
const int n = IntRange(5, 20).random_value();
311
success = random_allocate_multiple_times_from_testbed(slot, n);
318
void deallocate_from_testbed(int slotindex) {
319
DEBUG_ONLY(_testbeds.check_slot_is_not_null(slotindex);)
320
MetaspaceArenaTestBed* bed = _testbeds.at(slotindex);
321
bed->checked_random_deallocate();
324
void deallocate_from_random_testbed() {
325
int slot = _testbeds.random_non_null_slot_index();
327
deallocate_from_testbed(slot);
333
int get_total_number_of_allocations() const {
335
for (int i = _testbeds.first_non_null_slot(); i != -1; i = _testbeds.next_non_null_slot(i)) {
336
sum += _testbeds.at(i)->num_allocations();
341
size_t get_total_words_allocated() const {
343
for (int i = _testbeds.first_non_null_slot(); i != -1; i = _testbeds.next_non_null_slot(i)) {
344
sum += _testbeds.at(i)->words_allocated();
351
MetaspaceArenaTest(size_t commit_limit, int num_testbeds)
352
: _context(commit_limit),
353
_testbeds(num_testbeds),
357
~MetaspaceArenaTest () {
359
delete_all_test_beds();
373
const int iterations = 2500;
376
const size_t max_allocation_size = 8 * M;
378
bool force_bed_deletion = false;
380
for (int niter = 0; niter < iterations; niter++) {
382
const int r = IntRange(100).random_value();
384
if (force_bed_deletion || r < 10) {
386
force_bed_deletion = false;
387
delete_random_test_bed();
389
} else if (r < 20 || _num_beds.get() < (unsigned)_testbeds.size() / 2) {
391
create_random_test_bed();
396
force_bed_deletion = ! random_allocate_random_times_from_random_testbed();
401
deallocate_from_random_testbed();
406
if (_used_words_counter.get() >= max_allocation_size) {
408
force_bed_deletion = true;
419
TEST_VM(metaspace, MetaspaceArena_random_allocs_32_beds_no_commit_limit) {
420
MetaspaceArenaTest test(max_uintx, 32);
425
TEST_VM(metaspace, MetaspaceArena_random_allocs_32_beds_with_commit_limit) {
426
MetaspaceArenaTest test(2 * M, 32);
432
TEST_VM(metaspace, MetaspaceArena_random_allocs_1_bed_no_commit_limit) {
433
MetaspaceArenaTest test(max_uintx, 1);