8295013: OopStorage should derive from CHeapObjBase
Reviewed-by: stefank, tschatzl
This commit is contained in:
parent
3a980b972f
commit
94a9b048af
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -805,6 +805,10 @@ void OopStorage::release(const oop* const* ptrs, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
OopStorage* OopStorage::create(const char* name, MEMFLAGS memflags) {
|
||||
return new (memflags) OopStorage(name, memflags);
|
||||
}
|
||||
|
||||
const size_t initial_active_array_size = 8;
|
||||
|
||||
static Mutex* make_oopstorage_mutex(const char* storage_name,
|
||||
@ -815,15 +819,6 @@ static Mutex* make_oopstorage_mutex(const char* storage_name,
|
||||
return new PaddedMutex(rank, name);
|
||||
}
|
||||
|
||||
void* OopStorage::operator new(size_t size, MEMFLAGS memflags) {
|
||||
assert(size >= sizeof(OopStorage), "precondition");
|
||||
return NEW_C_HEAP_ARRAY(char, size, memflags);
|
||||
}
|
||||
|
||||
void OopStorage::operator delete(void* obj, MEMFLAGS /* memflags */) {
|
||||
FREE_C_HEAP_ARRAY(char, obj);
|
||||
}
|
||||
|
||||
OopStorage::OopStorage(const char* name, MEMFLAGS memflags) :
|
||||
_name(os::strdup(name)),
|
||||
_active_array(ActiveArray::create(initial_active_array_size, memflags)),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -72,14 +72,11 @@ class outputStream;
|
||||
// interactions for this protocol. Similarly, see the allocate() function for
|
||||
// a discussion of allocation.
|
||||
|
||||
class OopStorage {
|
||||
class OopStorage : public CHeapObjBase {
|
||||
public:
|
||||
explicit OopStorage(const char* name, MEMFLAGS memflags);
|
||||
static OopStorage* create(const char* name, MEMFLAGS memflags);
|
||||
~OopStorage();
|
||||
|
||||
void* operator new(size_t size, MEMFLAGS memflags);
|
||||
void operator delete(void* obj, MEMFLAGS memflags);
|
||||
|
||||
// These count and usage accessors are racy unless at a safepoint.
|
||||
|
||||
// The number of allocated and not yet released entries.
|
||||
@ -282,6 +279,10 @@ private:
|
||||
// Flag indicating this storage object is a candidate for empty block deletion.
|
||||
volatile bool _needs_cleanup;
|
||||
|
||||
// Clients construct via "create" factory function.
|
||||
OopStorage(const char* name, MEMFLAGS memflags);
|
||||
NONCOPYABLE(OopStorage);
|
||||
|
||||
bool try_add_block();
|
||||
Block* block_for_allocation();
|
||||
void log_block_transition(Block* block, const char* new_state) const;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@ OopStorage* OopStorageSet::_storages[all_count] = {};
|
||||
OopStorage* OopStorageSet::create_strong(const char* name, MEMFLAGS memflags) {
|
||||
static uint registered_strong = 0;
|
||||
assert(registered_strong < strong_count, "More registered strong storages than slots");
|
||||
OopStorage* storage = new (memflags) OopStorage(name, memflags);
|
||||
OopStorage* storage = OopStorage::create(name, memflags);
|
||||
_storages[strong_start + registered_strong++] = storage;
|
||||
return storage;
|
||||
}
|
||||
@ -42,7 +42,7 @@ OopStorage* OopStorageSet::create_strong(const char* name, MEMFLAGS memflags) {
|
||||
OopStorage* OopStorageSet::create_weak(const char* name, MEMFLAGS memflags) {
|
||||
static uint registered_weak = 0;
|
||||
assert(registered_weak < weak_count, "More registered strong storages than slots");
|
||||
OopStorage* storage = new (memflags) OopStorage(name, memflags);
|
||||
OopStorage* storage = OopStorage::create(name, memflags);
|
||||
_storages[weak_start + registered_weak++] = storage;
|
||||
return storage;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -172,22 +172,25 @@ static OopBlock* active_head(const OopStorage& storage) {
|
||||
}
|
||||
|
||||
class OopStorageTest : public ::testing::Test {
|
||||
OopStorage* _storage;
|
||||
|
||||
public:
|
||||
OopStorageTest();
|
||||
~OopStorageTest();
|
||||
|
||||
OopStorage _storage;
|
||||
OopStorage& storage() const { return *_storage; }
|
||||
|
||||
class CountingIterateClosure;
|
||||
template<bool is_const> class VM_CountAtSafepoint;
|
||||
};
|
||||
|
||||
OopStorageTest::OopStorageTest() :
|
||||
_storage("Test Storage", mtGC)
|
||||
_storage(OopStorage::create("Test Storage", mtGC))
|
||||
{ }
|
||||
|
||||
OopStorageTest::~OopStorageTest() {
|
||||
clear_list(TestAccess::allocation_list(_storage));
|
||||
clear_list(TestAccess::allocation_list(storage()));
|
||||
delete _storage;
|
||||
}
|
||||
|
||||
class OopStorageTestWithAllocation : public OopStorageTest {
|
||||
@ -200,9 +203,9 @@ public:
|
||||
|
||||
OopStorageTestWithAllocation::OopStorageTestWithAllocation() {
|
||||
for (size_t i = 0; i < _max_entries; ++i) {
|
||||
_entries[i] = _storage.allocate();
|
||||
_entries[i] = storage().allocate();
|
||||
EXPECT_TRUE(_entries[i] != NULL);
|
||||
EXPECT_EQ(i + 1, _storage.allocation_count());
|
||||
EXPECT_EQ(i + 1, storage().allocation_count());
|
||||
}
|
||||
};
|
||||
|
||||
@ -233,38 +236,38 @@ static size_t total_allocation_count(const OopStorage& storage) {
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTest, allocate_one) {
|
||||
EXPECT_EQ(0u, active_count(_storage));
|
||||
EXPECT_TRUE(is_list_empty(TestAccess::allocation_list(_storage)));
|
||||
EXPECT_EQ(0u, active_count(storage()));
|
||||
EXPECT_TRUE(is_list_empty(TestAccess::allocation_list(storage())));
|
||||
|
||||
oop* ptr = _storage.allocate();
|
||||
oop* ptr = storage().allocate();
|
||||
EXPECT_TRUE(ptr != NULL);
|
||||
EXPECT_EQ(1u, _storage.allocation_count());
|
||||
EXPECT_EQ(1u, storage().allocation_count());
|
||||
|
||||
EXPECT_EQ(1u, active_count(_storage));
|
||||
EXPECT_EQ(1u, _storage.block_count());
|
||||
EXPECT_EQ(1u, list_length(TestAccess::allocation_list(_storage)));
|
||||
EXPECT_EQ(1u, active_count(storage()));
|
||||
EXPECT_EQ(1u, storage().block_count());
|
||||
EXPECT_EQ(1u, list_length(TestAccess::allocation_list(storage())));
|
||||
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
const OopBlock* block = TestAccess::allocation_list(_storage).chead();
|
||||
const OopBlock* block = TestAccess::allocation_list(storage()).chead();
|
||||
EXPECT_NE(block, (OopBlock*)NULL);
|
||||
EXPECT_EQ(block, active_head(_storage));
|
||||
EXPECT_EQ(block, active_head(storage()));
|
||||
EXPECT_FALSE(TestAccess::block_is_empty(*block));
|
||||
EXPECT_FALSE(TestAccess::block_is_full(*block));
|
||||
EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));
|
||||
|
||||
release_entry(_storage, ptr);
|
||||
EXPECT_EQ(0u, _storage.allocation_count());
|
||||
release_entry(storage(), ptr);
|
||||
EXPECT_EQ(0u, storage().allocation_count());
|
||||
|
||||
EXPECT_EQ(1u, active_count(_storage));
|
||||
EXPECT_EQ(1u, _storage.block_count());
|
||||
EXPECT_EQ(1u, list_length(TestAccess::allocation_list(_storage)));
|
||||
EXPECT_EQ(1u, active_count(storage()));
|
||||
EXPECT_EQ(1u, storage().block_count());
|
||||
EXPECT_EQ(1u, list_length(TestAccess::allocation_list(storage())));
|
||||
|
||||
EXPECT_EQ(1u, empty_block_count(_storage));
|
||||
EXPECT_EQ(1u, empty_block_count(storage()));
|
||||
|
||||
const OopBlock* new_block = TestAccess::allocation_list(_storage).chead();
|
||||
const OopBlock* new_block = TestAccess::allocation_list(storage()).chead();
|
||||
EXPECT_EQ(block, new_block);
|
||||
EXPECT_EQ(block, active_head(_storage));
|
||||
EXPECT_EQ(block, active_head(storage()));
|
||||
EXPECT_TRUE(TestAccess::block_is_empty(*block));
|
||||
EXPECT_FALSE(TestAccess::block_is_full(*block));
|
||||
EXPECT_EQ(0u, TestAccess::block_allocation_count(*block));
|
||||
@ -274,19 +277,19 @@ TEST_VM_F(OopStorageTest, allocation_count) {
|
||||
static const size_t max_entries = 1000;
|
||||
oop* entries[max_entries];
|
||||
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(_storage);
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(storage());
|
||||
|
||||
EXPECT_EQ(0u, active_count(_storage));
|
||||
EXPECT_EQ(0u, _storage.block_count());
|
||||
EXPECT_EQ(0u, active_count(storage()));
|
||||
EXPECT_EQ(0u, storage().block_count());
|
||||
EXPECT_TRUE(is_list_empty(allocation_list));
|
||||
|
||||
size_t allocated = 0;
|
||||
for ( ; allocated < max_entries; ++allocated) {
|
||||
EXPECT_EQ(allocated, _storage.allocation_count());
|
||||
if (active_count(_storage) != 0) {
|
||||
EXPECT_EQ(1u, active_count(_storage));
|
||||
EXPECT_EQ(1u, _storage.block_count());
|
||||
const OopBlock& block = *TestAccess::active_array(_storage).at(0);
|
||||
EXPECT_EQ(allocated, storage().allocation_count());
|
||||
if (active_count(storage()) != 0) {
|
||||
EXPECT_EQ(1u, active_count(storage()));
|
||||
EXPECT_EQ(1u, storage().block_count());
|
||||
const OopBlock& block = *TestAccess::active_array(storage()).at(0);
|
||||
EXPECT_EQ(allocated, TestAccess::block_allocation_count(block));
|
||||
if (TestAccess::block_is_full(block)) {
|
||||
break;
|
||||
@ -295,22 +298,22 @@ TEST_VM_F(OopStorageTest, allocation_count) {
|
||||
EXPECT_EQ(&block, allocation_list.chead());
|
||||
}
|
||||
}
|
||||
entries[allocated] = _storage.allocate();
|
||||
entries[allocated] = storage().allocate();
|
||||
}
|
||||
|
||||
EXPECT_EQ(allocated, _storage.allocation_count());
|
||||
EXPECT_EQ(1u, active_count(_storage));
|
||||
EXPECT_EQ(1u, _storage.block_count());
|
||||
EXPECT_EQ(allocated, storage().allocation_count());
|
||||
EXPECT_EQ(1u, active_count(storage()));
|
||||
EXPECT_EQ(1u, storage().block_count());
|
||||
EXPECT_TRUE(is_list_empty(allocation_list));
|
||||
const OopBlock& block = *TestAccess::active_array(_storage).at(0);
|
||||
const OopBlock& block = *TestAccess::active_array(storage()).at(0);
|
||||
EXPECT_TRUE(TestAccess::block_is_full(block));
|
||||
EXPECT_EQ(allocated, TestAccess::block_allocation_count(block));
|
||||
|
||||
for (size_t i = 0; i < allocated; ++i) {
|
||||
release_entry(_storage, entries[i]);
|
||||
release_entry(storage(), entries[i]);
|
||||
size_t remaining = allocated - (i + 1);
|
||||
EXPECT_EQ(remaining, TestAccess::block_allocation_count(block));
|
||||
EXPECT_EQ(remaining, _storage.allocation_count());
|
||||
EXPECT_EQ(remaining, storage().allocation_count());
|
||||
EXPECT_FALSE(is_list_empty(allocation_list));
|
||||
}
|
||||
}
|
||||
@ -319,40 +322,40 @@ TEST_VM_F(OopStorageTest, allocate_many) {
|
||||
static const size_t max_entries = 1000;
|
||||
oop* entries[max_entries];
|
||||
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(_storage);
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(storage());
|
||||
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
entries[0] = _storage.allocate();
|
||||
entries[0] = storage().allocate();
|
||||
ASSERT_TRUE(entries[0] != NULL);
|
||||
EXPECT_EQ(1u, active_count(_storage));
|
||||
EXPECT_EQ(1u, _storage.block_count());
|
||||
EXPECT_EQ(1u, active_count(storage()));
|
||||
EXPECT_EQ(1u, storage().block_count());
|
||||
EXPECT_EQ(1u, list_length(allocation_list));
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
const OopBlock* block = TestAccess::active_array(_storage).at(0);
|
||||
const OopBlock* block = TestAccess::active_array(storage()).at(0);
|
||||
EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));
|
||||
EXPECT_EQ(block, allocation_list.chead());
|
||||
|
||||
for (size_t i = 1; i < max_entries; ++i) {
|
||||
entries[i] = _storage.allocate();
|
||||
EXPECT_EQ(i + 1, _storage.allocation_count());
|
||||
entries[i] = storage().allocate();
|
||||
EXPECT_EQ(i + 1, storage().allocation_count());
|
||||
ASSERT_TRUE(entries[i] != NULL);
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
if (block == NULL) {
|
||||
ASSERT_FALSE(is_list_empty(allocation_list));
|
||||
EXPECT_EQ(1u, list_length(allocation_list));
|
||||
block = allocation_list.chead();
|
||||
EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));
|
||||
EXPECT_EQ(block, active_head(_storage));
|
||||
EXPECT_EQ(block, active_head(storage()));
|
||||
} else if (TestAccess::block_is_full(*block)) {
|
||||
EXPECT_TRUE(is_list_empty(allocation_list));
|
||||
block = NULL;
|
||||
} else {
|
||||
EXPECT_FALSE(is_list_empty(allocation_list));
|
||||
EXPECT_EQ(block, allocation_list.chead());
|
||||
EXPECT_EQ(block, active_head(_storage));
|
||||
EXPECT_EQ(block, active_head(storage()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,18 +363,18 @@ TEST_VM_F(OopStorageTest, allocate_many) {
|
||||
EXPECT_NE(0u, TestAccess::block_allocation_count(*block));
|
||||
EXPECT_FALSE(is_list_empty(allocation_list));
|
||||
EXPECT_EQ(block, allocation_list.chead());
|
||||
EXPECT_EQ(block, active_head(_storage));
|
||||
EXPECT_EQ(block, active_head(storage()));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < max_entries; ++i) {
|
||||
release_entry(_storage, entries[i]);
|
||||
EXPECT_TRUE(is_allocation_list_sorted(_storage));
|
||||
EXPECT_EQ(max_entries - (i + 1), total_allocation_count(_storage));
|
||||
release_entry(storage(), entries[i]);
|
||||
EXPECT_TRUE(is_allocation_list_sorted(storage()));
|
||||
EXPECT_EQ(max_entries - (i + 1), total_allocation_count(storage()));
|
||||
}
|
||||
|
||||
EXPECT_EQ(active_count(_storage), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(_storage), _storage.block_count());
|
||||
EXPECT_EQ(active_count(_storage), empty_block_count(_storage));
|
||||
EXPECT_EQ(active_count(storage()), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(storage()), storage().block_count());
|
||||
EXPECT_EQ(active_count(storage()), empty_block_count(storage()));
|
||||
for (const OopBlock* block = allocation_list.chead();
|
||||
block != NULL;
|
||||
block = allocation_list.next(*block)) {
|
||||
@ -383,29 +386,29 @@ TEST_VM_F(OopStorageTestWithAllocation, random_release) {
|
||||
static const size_t step = 11;
|
||||
ASSERT_NE(0u, _max_entries % step); // max_entries and step are mutually prime
|
||||
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(_storage);
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(storage());
|
||||
|
||||
EXPECT_EQ(_max_entries, total_allocation_count(_storage));
|
||||
EXPECT_EQ(_max_entries, total_allocation_count(storage()));
|
||||
EXPECT_GE(1u, list_length(allocation_list));
|
||||
|
||||
// Release all entries in "random" order.
|
||||
size_t released = 0;
|
||||
for (size_t i = 0; released < _max_entries; i = (i + step) % _max_entries) {
|
||||
if (_entries[i] != NULL) {
|
||||
release_entry(_storage, _entries[i]);
|
||||
release_entry(storage(), _entries[i]);
|
||||
_entries[i] = NULL;
|
||||
++released;
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(_storage));
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(storage()));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(storage()));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(active_count(_storage), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(_storage), _storage.block_count());
|
||||
EXPECT_EQ(0u, total_allocation_count(_storage));
|
||||
EXPECT_EQ(list_length(allocation_list), empty_block_count(_storage));
|
||||
EXPECT_EQ(active_count(storage()), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(storage()), storage().block_count());
|
||||
EXPECT_EQ(0u, total_allocation_count(storage()));
|
||||
EXPECT_EQ(list_length(allocation_list), empty_block_count(storage()));
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) {
|
||||
@ -413,11 +416,11 @@ TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) {
|
||||
static const size_t allocate_step = 5;
|
||||
ASSERT_NE(0u, _max_entries % release_step); // max_entries and step are mutually prime
|
||||
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(_storage);
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(storage());
|
||||
|
||||
EXPECT_EQ(_max_entries, total_allocation_count(_storage));
|
||||
EXPECT_EQ(_max_entries, total_allocation_count(storage()));
|
||||
EXPECT_GE(1u, list_length(allocation_list));
|
||||
|
||||
// Release all entries in "random" order, "randomly" interspersed
|
||||
@ -426,25 +429,25 @@ TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) {
|
||||
size_t total_released = 0;
|
||||
for (size_t i = 0; released < _max_entries; i = (i + release_step) % _max_entries) {
|
||||
if (_entries[i] != NULL) {
|
||||
release_entry(_storage, _entries[i]);
|
||||
release_entry(storage(), _entries[i]);
|
||||
_entries[i] = NULL;
|
||||
++released;
|
||||
++total_released;
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(_storage));
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(storage()));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(storage()));
|
||||
if (total_released % allocate_step == 0) {
|
||||
_entries[i] = _storage.allocate();
|
||||
_entries[i] = storage().allocate();
|
||||
--released;
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(_storage));
|
||||
EXPECT_EQ(_max_entries - released, total_allocation_count(storage()));
|
||||
EXPECT_TRUE(is_allocation_list_sorted(storage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(active_count(_storage), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(_storage), _storage.block_count());
|
||||
EXPECT_EQ(0u, total_allocation_count(_storage));
|
||||
EXPECT_EQ(list_length(allocation_list), empty_block_count(_storage));
|
||||
EXPECT_EQ(active_count(storage()), list_length(allocation_list));
|
||||
EXPECT_EQ(active_count(storage()), storage().block_count());
|
||||
EXPECT_EQ(0u, total_allocation_count(storage()));
|
||||
EXPECT_EQ(list_length(allocation_list), empty_block_count(storage()));
|
||||
}
|
||||
|
||||
template<bool sorted>
|
||||
@ -462,16 +465,16 @@ public:
|
||||
QuickSort::sort(to_release, nrelease, PointerCompare(), false);
|
||||
}
|
||||
|
||||
_storage.release(to_release, nrelease);
|
||||
EXPECT_EQ(_max_entries - nrelease, _storage.allocation_count());
|
||||
storage().release(to_release, nrelease);
|
||||
EXPECT_EQ(_max_entries - nrelease, storage().allocation_count());
|
||||
|
||||
for (size_t i = 0; i < nrelease; ++i) {
|
||||
release_entry(_storage, _entries[2 * i + 1], false);
|
||||
EXPECT_EQ(_max_entries - nrelease - (i + 1), _storage.allocation_count());
|
||||
release_entry(storage(), _entries[2 * i + 1], false);
|
||||
EXPECT_EQ(_max_entries - nrelease - (i + 1), storage().allocation_count());
|
||||
}
|
||||
EXPECT_TRUE(process_deferred_updates(_storage));
|
||||
EXPECT_TRUE(process_deferred_updates(storage()));
|
||||
|
||||
EXPECT_EQ(_storage.block_count(), empty_block_count(_storage));
|
||||
EXPECT_EQ(storage().block_count(), empty_block_count(storage()));
|
||||
|
||||
FREE_C_HEAP_ARRAY(oop*, to_release);
|
||||
}
|
||||
@ -494,25 +497,25 @@ TEST_VM_F(OopStorageTest, bulk_allocation) {
|
||||
static const size_t zero = 0;
|
||||
oop* entries[max_entries] = {};
|
||||
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(_storage);
|
||||
AllocationList& allocation_list = TestAccess::allocation_list(storage());
|
||||
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
size_t allocated = _storage.allocate(entries, max_entries);
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
size_t allocated = storage().allocate(entries, max_entries);
|
||||
ASSERT_NE(allocated, zero);
|
||||
// ASSERT_LE would ODR-use the OopStorage constant.
|
||||
size_t bulk_allocate_limit = OopStorage::bulk_allocate_limit;
|
||||
ASSERT_LE(allocated, bulk_allocate_limit);
|
||||
ASSERT_LE(allocated, max_entries);
|
||||
for (size_t i = 0; i < allocated; ++i) {
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(entries[i]));
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, storage().allocation_status(entries[i]));
|
||||
}
|
||||
for (size_t i = allocated; i < max_entries; ++i) {
|
||||
EXPECT_EQ(NULL, entries[i]);
|
||||
}
|
||||
_storage.release(entries, allocated);
|
||||
EXPECT_EQ(0u, _storage.allocation_count());
|
||||
storage().release(entries, allocated);
|
||||
EXPECT_EQ(0u, storage().allocation_count());
|
||||
for (size_t i = 0; i < allocated; ++i) {
|
||||
EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, _storage.allocation_status(entries[i]));
|
||||
EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, storage().allocation_status(entries[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,7 +525,7 @@ TEST_VM_F(OopStorageTest, invalid_pointer) {
|
||||
char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal);
|
||||
oop* ptr = reinterpret_cast<oop*>(align_down(mem + 250, sizeof(oop)));
|
||||
// Predicate returns false for some malloc'ed block.
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(ptr));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
|
||||
FREE_C_HEAP_ARRAY(char, mem);
|
||||
}
|
||||
|
||||
@ -530,7 +533,7 @@ TEST_VM_F(OopStorageTest, invalid_pointer) {
|
||||
oop obj;
|
||||
oop* ptr = &obj;
|
||||
// Predicate returns false for some "random" location.
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(ptr));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr));
|
||||
}
|
||||
}
|
||||
#endif // DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS
|
||||
@ -594,7 +597,7 @@ TEST_VM_F(OopStorageTest, simple_iterate) {
|
||||
size_t entries_with_values = 0;
|
||||
for (size_t i = 0; i < max_entries; i += 10) {
|
||||
for ( ; allocated < i; ++allocated) {
|
||||
entries[allocated] = _storage.allocate();
|
||||
entries[allocated] = storage().allocate();
|
||||
ASSERT_TRUE(entries[allocated] != NULL);
|
||||
if ((allocated % 3) != 0) {
|
||||
*entries[allocated] = dummy_oop;
|
||||
@ -604,7 +607,7 @@ TEST_VM_F(OopStorageTest, simple_iterate) {
|
||||
|
||||
{
|
||||
CountingIterateClosure cl;
|
||||
VM_CountAtSafepoint<false> op(&_storage, &cl);
|
||||
VM_CountAtSafepoint<false> op(&storage(), &cl);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
@ -617,7 +620,7 @@ TEST_VM_F(OopStorageTest, simple_iterate) {
|
||||
|
||||
{
|
||||
CountingIterateClosure cl;
|
||||
VM_CountAtSafepoint<true> op(&_storage, &cl);
|
||||
VM_CountAtSafepoint<true> op(&storage(), &cl);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
@ -630,9 +633,9 @@ TEST_VM_F(OopStorageTest, simple_iterate) {
|
||||
}
|
||||
|
||||
while (allocated > 0) {
|
||||
release_entry(_storage, entries[--allocated], false);
|
||||
release_entry(storage(), entries[--allocated], false);
|
||||
}
|
||||
process_deferred_updates(_storage);
|
||||
process_deferred_updates(storage());
|
||||
}
|
||||
|
||||
class OopStorageTestIteration : public OopStorageTestWithAllocation {
|
||||
@ -651,17 +654,17 @@ public:
|
||||
memset(_states, 0, sizeof(_states));
|
||||
|
||||
size_t initial_release = 0;
|
||||
for ( ; empty_block_count(_storage) < 2; ++initial_release) {
|
||||
for ( ; empty_block_count(storage()) < 2; ++initial_release) {
|
||||
ASSERT_GT(_max_entries, initial_release);
|
||||
release_entry(_storage, _entries[initial_release]);
|
||||
release_entry(storage(), _entries[initial_release]);
|
||||
_states[0][initial_release] = mark_released;
|
||||
}
|
||||
|
||||
for (size_t i = initial_release; i < _max_entries; i += 3) {
|
||||
release_entry(_storage, _entries[i], false);
|
||||
release_entry(storage(), _entries[i], false);
|
||||
_states[0][i] = mark_released;
|
||||
}
|
||||
process_deferred_updates(_storage);
|
||||
process_deferred_updates(storage());
|
||||
}
|
||||
|
||||
class VerifyState;
|
||||
@ -831,7 +834,7 @@ private:
|
||||
|
||||
TEST_VM_F(OopStorageTestIteration, iterate_safepoint) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
VM_Verify<false> op(&_storage, &vstate);
|
||||
VM_Verify<false> op(&storage(), &vstate);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
@ -842,7 +845,7 @@ TEST_VM_F(OopStorageTestIteration, iterate_safepoint) {
|
||||
|
||||
TEST_VM_F(OopStorageTestIteration, const_iterate_safepoint) {
|
||||
VerifyState vstate(mark_const, _entries, _states);
|
||||
VM_Verify<true> op(&_storage, &vstate);
|
||||
VM_Verify<true> op(&storage(), &vstate);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
@ -853,7 +856,7 @@ TEST_VM_F(OopStorageTestIteration, const_iterate_safepoint) {
|
||||
|
||||
TEST_VM_F(OopStorageTestIteration, oops_do) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
VM_VerifyUsingOopsDo op(&_storage, &vstate);
|
||||
VM_VerifyUsingOopsDo op(&storage(), &vstate);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
@ -946,7 +949,7 @@ private:
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_iterate) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
Task<false, false> task("test", &_storage, &vstate);
|
||||
Task<false, false> task("test", &storage(), &vstate);
|
||||
VM_ParStateVerify op(workers(), &task);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
@ -957,7 +960,7 @@ TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_iterate) {
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_iterate) {
|
||||
VerifyState vstate(mark_const, _entries, _states);
|
||||
Task<false, true> task("test", &_storage, &vstate);
|
||||
Task<false, true> task("test", &storage(), &vstate);
|
||||
VM_ParStateVerify op(workers(), &task);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
@ -968,7 +971,7 @@ TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_iterate) {
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_oops_do) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
TaskUsingOopsDo<false, false> task("test", &_storage, &vstate);
|
||||
TaskUsingOopsDo<false, false> task("test", &storage(), &vstate);
|
||||
VM_ParStateVerify op(workers(), &task);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
@ -979,7 +982,7 @@ TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_oops_do) {
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_oops_do) {
|
||||
VerifyState vstate(mark_const, _entries, _states);
|
||||
TaskUsingOopsDo<false, true> task("test", &_storage, &vstate);
|
||||
TaskUsingOopsDo<false, true> task("test", &storage(), &vstate);
|
||||
VM_ParStateVerify op(workers(), &task);
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
@ -990,78 +993,78 @@ TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_oops_do) {
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_iterate) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
Task<true, false> task("test", &_storage, &vstate);
|
||||
Task<true, false> task("test", &storage(), &vstate);
|
||||
workers()->run_task(&task);
|
||||
vstate.check();
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_const_iterate) {
|
||||
VerifyState vstate(mark_const, _entries, _states);
|
||||
Task<true, true> task("test", &_storage, &vstate);
|
||||
Task<true, true> task("test", &storage(), &vstate);
|
||||
workers()->run_task(&task);
|
||||
vstate.check();
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_oops_do) {
|
||||
VerifyState vstate(mark_non_const, _entries, _states);
|
||||
TaskUsingOopsDo<true, false> task("test", &_storage, &vstate);
|
||||
TaskUsingOopsDo<true, false> task("test", &storage(), &vstate);
|
||||
workers()->run_task(&task);
|
||||
vstate.check();
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_const_oops_do) {
|
||||
VerifyState vstate(mark_const, _entries, _states);
|
||||
TaskUsingOopsDo<true, true> task("test", &_storage, &vstate);
|
||||
TaskUsingOopsDo<true, true> task("test", &storage(), &vstate);
|
||||
workers()->run_task(&task);
|
||||
vstate.check();
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestWithAllocation, delete_empty_blocks) {
|
||||
size_t initial_active_size = active_count(_storage);
|
||||
EXPECT_EQ(initial_active_size, _storage.block_count());
|
||||
size_t initial_active_size = active_count(storage());
|
||||
EXPECT_EQ(initial_active_size, storage().block_count());
|
||||
ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test
|
||||
|
||||
for (size_t i = 0; empty_block_count(_storage) < 3; ++i) {
|
||||
for (size_t i = 0; empty_block_count(storage()) < 3; ++i) {
|
||||
ASSERT_GT(_max_entries, i);
|
||||
release_entry(_storage, _entries[i]);
|
||||
release_entry(storage(), _entries[i]);
|
||||
}
|
||||
|
||||
EXPECT_EQ(initial_active_size, active_count(_storage));
|
||||
EXPECT_EQ(initial_active_size, _storage.block_count());
|
||||
EXPECT_EQ(3u, empty_block_count(_storage));
|
||||
EXPECT_EQ(initial_active_size, active_count(storage()));
|
||||
EXPECT_EQ(initial_active_size, storage().block_count());
|
||||
EXPECT_EQ(3u, empty_block_count(storage()));
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
while (_storage.delete_empty_blocks()) {}
|
||||
while (storage().delete_empty_blocks()) {}
|
||||
}
|
||||
EXPECT_EQ(0u, empty_block_count(_storage));
|
||||
EXPECT_EQ(initial_active_size - 3, active_count(_storage));
|
||||
EXPECT_EQ(initial_active_size - 3, _storage.block_count());
|
||||
EXPECT_EQ(0u, empty_block_count(storage()));
|
||||
EXPECT_EQ(initial_active_size - 3, active_count(storage()));
|
||||
EXPECT_EQ(initial_active_size - 3, storage().block_count());
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTestWithAllocation, allocation_status) {
|
||||
oop* retained = _entries[200];
|
||||
oop* released = _entries[300];
|
||||
oop* garbage = reinterpret_cast<oop*>(1024 * 1024);
|
||||
release_entry(_storage, released);
|
||||
release_entry(storage(), released);
|
||||
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained));
|
||||
EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, _storage.allocation_status(released));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(garbage));
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, storage().allocation_status(retained));
|
||||
EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, storage().allocation_status(released));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(garbage));
|
||||
|
||||
for (size_t i = 0; i < _max_entries; ++i) {
|
||||
if ((_entries[i] != retained) && (_entries[i] != released)) {
|
||||
// Leave deferred release updates to block deletion.
|
||||
release_entry(_storage, _entries[i], false);
|
||||
release_entry(storage(), _entries[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
while (_storage.delete_empty_blocks()) {}
|
||||
while (storage().delete_empty_blocks()) {}
|
||||
}
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(released));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(garbage));
|
||||
EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, storage().allocation_status(retained));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(released));
|
||||
EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(garbage));
|
||||
}
|
||||
|
||||
TEST_VM_F(OopStorageTest, usage_info) {
|
||||
@ -1069,24 +1072,24 @@ TEST_VM_F(OopStorageTest, usage_info) {
|
||||
oop* entries[1000];
|
||||
size_t allocated = 0;
|
||||
|
||||
EXPECT_EQ(0u, _storage.block_count());
|
||||
EXPECT_EQ(0u, storage().block_count());
|
||||
// There is non-block overhead, so always some usage.
|
||||
EXPECT_LT(0u, _storage.total_memory_usage());
|
||||
EXPECT_LT(0u, storage().total_memory_usage());
|
||||
|
||||
while (_storage.block_count() < goal_blocks) {
|
||||
size_t this_count = _storage.block_count();
|
||||
while (_storage.block_count() == this_count) {
|
||||
while (storage().block_count() < goal_blocks) {
|
||||
size_t this_count = storage().block_count();
|
||||
while (storage().block_count() == this_count) {
|
||||
ASSERT_GT(ARRAY_SIZE(entries), allocated);
|
||||
entries[allocated] = _storage.allocate();
|
||||
entries[allocated] = storage().allocate();
|
||||
ASSERT_TRUE(entries[allocated] != NULL);
|
||||
++allocated;
|
||||
}
|
||||
EXPECT_NE(0u, _storage.block_count());
|
||||
EXPECT_NE(0u, _storage.total_memory_usage());
|
||||
EXPECT_NE(0u, storage().block_count());
|
||||
EXPECT_NE(0u, storage().total_memory_usage());
|
||||
}
|
||||
|
||||
EXPECT_LT(TestAccess::memory_per_block() * _storage.block_count(),
|
||||
_storage.total_memory_usage());
|
||||
EXPECT_LT(TestAccess::memory_per_block() * storage().block_count(),
|
||||
storage().total_memory_usage());
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -1095,22 +1098,22 @@ TEST_VM_F(OopStorageTestWithAllocation, print_storage) {
|
||||
// Release the first 1/2
|
||||
for (size_t i = 0; i < (_max_entries / 2); ++i) {
|
||||
// Deferred updates don't affect print output.
|
||||
release_entry(_storage, _entries[i], false);
|
||||
release_entry(storage(), _entries[i], false);
|
||||
_entries[i] = NULL;
|
||||
}
|
||||
// Release every other remaining
|
||||
for (size_t i = _max_entries / 2; i < _max_entries; i += 2) {
|
||||
// Deferred updates don't affect print output.
|
||||
release_entry(_storage, _entries[i], false);
|
||||
release_entry(storage(), _entries[i], false);
|
||||
_entries[i] = NULL;
|
||||
}
|
||||
|
||||
size_t expected_entries = _max_entries / 4;
|
||||
EXPECT_EQ(expected_entries, _storage.allocation_count());
|
||||
EXPECT_EQ(expected_entries, storage().allocation_count());
|
||||
|
||||
size_t entries_per_block = BitsPerWord;
|
||||
size_t expected_blocks = (_max_entries + entries_per_block - 1) / entries_per_block;
|
||||
EXPECT_EQ(expected_blocks, _storage.block_count());
|
||||
EXPECT_EQ(expected_blocks, storage().block_count());
|
||||
|
||||
double expected_usage = (100.0 * expected_entries) / (expected_blocks * entries_per_block);
|
||||
|
||||
@ -1123,9 +1126,9 @@ TEST_VM_F(OopStorageTestWithAllocation, print_storage) {
|
||||
expected_entries,
|
||||
expected_blocks,
|
||||
expected_usage,
|
||||
_storage.total_memory_usage());
|
||||
storage().total_memory_usage());
|
||||
stringStream st;
|
||||
_storage.print_on(&st);
|
||||
storage().print_on(&st);
|
||||
EXPECT_STREQ(expected_st.as_string(), st.as_string());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -52,6 +52,8 @@ static uint _num_workers = 0;
|
||||
const size_t _storage_entries = 1000000;
|
||||
|
||||
class OopStorageParIterPerf : public ::testing::Test {
|
||||
OopStorage* _storage;
|
||||
|
||||
public:
|
||||
OopStorageParIterPerf();
|
||||
~OopStorageParIterPerf();
|
||||
@ -62,13 +64,13 @@ public:
|
||||
class Task;
|
||||
class Closure;
|
||||
|
||||
OopStorage& storage() const { return *_storage; }
|
||||
Tickspan run_task(Task* task, uint nthreads);
|
||||
void show_task(const Task* task, Tickspan duration, uint nthreads);
|
||||
void run_test(uint nthreads);
|
||||
|
||||
static WorkerThreads* _workers;
|
||||
|
||||
OopStorage _storage;
|
||||
oop* _entries[_storage_entries];
|
||||
};
|
||||
|
||||
@ -85,16 +87,17 @@ WorkerThreads* OopStorageParIterPerf::workers() const {
|
||||
}
|
||||
|
||||
OopStorageParIterPerf::OopStorageParIterPerf() :
|
||||
_storage("Test Storage", mtGC)
|
||||
_storage(OopStorage::create("Test Storage", mtGC))
|
||||
{
|
||||
for (size_t i = 0; i < _storage_entries; ++i) {
|
||||
_entries[i] = _storage.allocate();
|
||||
_entries[i] = storage().allocate();
|
||||
}
|
||||
_num_workers = MIN2(_max_workers, (uint)os::processor_count());
|
||||
}
|
||||
|
||||
OopStorageParIterPerf::~OopStorageParIterPerf() {
|
||||
_storage.release(_entries, ARRAY_SIZE(_entries));
|
||||
storage().release(_entries, ARRAY_SIZE(_entries));
|
||||
delete _storage;
|
||||
}
|
||||
|
||||
class OopStorageParIterPerf::VM_ParStateTime : public VM_GTestExecuteAtSafepoint {
|
||||
@ -177,7 +180,7 @@ void OopStorageParIterPerf::run_test(uint nthreads) {
|
||||
if (nthreads <= _num_workers) {
|
||||
SCOPED_TRACE(err_msg("Running test with %u threads", nthreads).buffer());
|
||||
Closure closure;
|
||||
Task task(&_storage, &closure, nthreads);
|
||||
Task task(&storage(), &closure, nthreads);
|
||||
Tickspan t = run_task(&task, nthreads);
|
||||
show_task(&task, t, nthreads);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user