< prev index next >
test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp
Print this page
rev 53142 : [mq]: tschatzl_review
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
@@ -38,12 +38,20 @@
class BufferNode::TestSupport : AllStatic {
public:
static bool try_transfer_pending(Allocator* allocator) {
return allocator->try_transfer_pending();
}
+
+ class CompletedList;
+ class AllocatorThread;
+ class ProcessorThread;
};
+typedef BufferNode::TestSupport::CompletedList CompletedList;
+typedef BufferNode::TestSupport::AllocatorThread AllocatorThread;
+typedef BufferNode::TestSupport::ProcessorThread ProcessorThread;
+
// Some basic testing of BufferNode::Allocator.
TEST_VM(PtrQueueBufferAllocatorTest, test) {
const size_t buffer_size = 256;
BufferNode::Allocator allocator("Test Buffer Allocator", buffer_size);
ASSERT_EQ(buffer_size, allocator.buffer_size());
@@ -91,62 +99,48 @@
size_t count = allocator.free_count();
ASSERT_EQ(count, allocator.reduce_free_list(count));
// destroy allocator.
}
-// Allocator API for testing. We don't use BufferNode::Allocator
-// directly so that we can add other allocators and compare them.
-// BufferNode::Allocator uses a lock-free free list. Alternatives
-// examined include (1) free list protected by lock, (2) no free list,
-// just CHeap allocate and free always. Testing the "no free list"
-// version properly requires simulating the full cycle, with the
-// allocating thread usually/always being different from the releasing
-// thread. Using the same thread for both operations is often a
-// heavily optimized path in the underlying CHeap allocator.
-class TestPtrQueueBufferAllocator {
- // Noncopyable
- TestPtrQueueBufferAllocator(const TestPtrQueueBufferAllocator&);
- TestPtrQueueBufferAllocator& operator=(const TestPtrQueueBufferAllocator&);
-
-protected:
- TestPtrQueueBufferAllocator() {}
- ~TestPtrQueueBufferAllocator() {}
+// Stress test with lock-free allocator and completed buffer list.
+// Completed buffer list pop avoids ABA by also being in a critical
+// section that is synchronized by the allocator's release.
+
+class BufferNode::TestSupport::CompletedList {
+ BufferNode::Stack _completed_list;
public:
- virtual BufferNode* allocate() = 0;
- virtual void release(BufferNode* node) = 0;
- virtual size_t free_count() const = 0;
- virtual bool try_transfer_pending() { return true; }
+ CompletedList() : _completed_list() {}
- static const size_t buffer_size = 1024;
-};
+ ~CompletedList() {
+ assert(_completed_list.empty(), "completed list not empty");
+ }
-class TestPtrQueueBufferCBL {
- // Noncopyable.
- TestPtrQueueBufferCBL(const TestPtrQueueBufferCBL&);
- TestPtrQueueBufferCBL& operator=(const TestPtrQueueBufferCBL&);
-
-protected:
- TestPtrQueueBufferCBL() {}
- ~TestPtrQueueBufferCBL() {}
+ void push(BufferNode* node) {
+ assert(node != NULL, "precondition");
+ _completed_list.push(*node);
+ }
-public:
- virtual BufferNode* pop() = 0;
- virtual void push(BufferNode* node) = 0;
+ BufferNode* pop() {
+ GlobalCounter::CriticalSection cs(Thread::current());
+ return _completed_list.pop();
+ }
};
-class PtrQueueBufferAllocatorThread : public JavaTestThread {
- TestPtrQueueBufferAllocator* _allocator;
- TestPtrQueueBufferCBL* _cbl;
+// Simulate a mutator thread, allocating buffers and adding them to
+// the completed buffer list.
+class BufferNode::TestSupport::AllocatorThread : public JavaTestThread {
+ BufferNode::Allocator* _allocator;
+ CompletedList* _cbl;
volatile size_t* _total_allocations;
volatile bool* _continue_running;
size_t _allocations;
public:
- PtrQueueBufferAllocatorThread(Semaphore* post,
- TestPtrQueueBufferAllocator* allocator,
- TestPtrQueueBufferCBL* cbl,
+ AllocatorThread(Semaphore* post,
+ BufferNode::Allocator* allocator,
+ CompletedList* cbl,
volatile size_t* total_allocations,
volatile bool* continue_running) :
JavaTestThread(post),
_allocator(allocator),
_cbl(cbl),
@@ -165,19 +159,21 @@
tty->print_cr("allocations: " SIZE_FORMAT, _allocations);
Atomic::add(_allocations, _total_allocations);
}
};
-class PtrQueueBufferProcessorThread : public JavaTestThread {
- TestPtrQueueBufferAllocator* _allocator;
- TestPtrQueueBufferCBL* _cbl;
+// Simulate a GC thread, taking buffers from the completed buffer list
+// and returning them to the allocator.
+class BufferNode::TestSupport::ProcessorThread : public JavaTestThread {
+ BufferNode::Allocator* _allocator;
+ CompletedList* _cbl;
volatile bool* _continue_running;
public:
- PtrQueueBufferProcessorThread(Semaphore* post,
- TestPtrQueueBufferAllocator* allocator,
- TestPtrQueueBufferCBL* cbl,
+ ProcessorThread(Semaphore* post,
+ BufferNode::Allocator* allocator,
+ CompletedList* cbl,
volatile bool* continue_running) :
JavaTestThread(post),
_allocator(allocator),
_cbl(cbl),
_continue_running(continue_running)
@@ -194,32 +190,31 @@
ThreadBlockInVM tbiv(this); // Safepoint check.
}
}
};
-static void run_test(TestPtrQueueBufferAllocator* allocator,
- TestPtrQueueBufferCBL* cbl) {
+static void run_test(BufferNode::Allocator* allocator, CompletedList* cbl) {
const uint nthreads = 4;
const uint milliseconds_to_run = 1000;
Semaphore post;
volatile size_t total_allocations = 0;
volatile bool allocator_running = true;
volatile bool processor_running = true;
- PtrQueueBufferProcessorThread* proc_threads[nthreads] = {};
+ ProcessorThread* proc_threads[nthreads] = {};
for (uint i = 0; i < nthreads; ++i) {
- proc_threads[i] = new PtrQueueBufferProcessorThread(&post,
+ proc_threads[i] = new ProcessorThread(&post,
allocator,
cbl,
&processor_running);
proc_threads[i]->doit();
}
- PtrQueueBufferAllocatorThread* alloc_threads[nthreads] = {};
+ AllocatorThread* alloc_threads[nthreads] = {};
for (uint i = 0; i < nthreads; ++i) {
- alloc_threads[i] = new PtrQueueBufferAllocatorThread(&post,
+ alloc_threads[i] = new AllocatorThread(&post,
allocator,
cbl,
&total_allocations,
&allocator_running);
alloc_threads[i]->doit();
@@ -239,55 +234,17 @@
OrderAccess::release_store(&processor_running, false);
for (uint i = 0; i < nthreads; ++i) {
ThreadInVMfromNative invm(this_thread);
post.wait_with_safepoint_check(this_thread);
}
- ASSERT_TRUE(allocator->try_transfer_pending());
+ ASSERT_TRUE(BufferNode::TestSupport::try_transfer_pending(allocator));
tty->print_cr("total allocations: " SIZE_FORMAT, total_allocations);
tty->print_cr("allocator free count: " SIZE_FORMAT, allocator->free_count());
}
-// Stress test with lock-free allocator and completed buffer list.
-// Completed buffer list pop avoids ABA by also being in a critical
-// section that is synchronized by the allocator's release.
-
-class FreeListPtrQueueBufferAllocator : public TestPtrQueueBufferAllocator {
- BufferNode::Allocator _allocator;
-
-public:
- FreeListPtrQueueBufferAllocator() :
- _allocator("Test Buffer Allocator", buffer_size) {}
-
- virtual BufferNode* allocate() { return _allocator.allocate(); }
- virtual void release(BufferNode* node) { _allocator.release(node); }
- virtual size_t free_count() const { return _allocator.free_count(); }
- virtual bool try_transfer_pending() {
- return BufferNode::TestSupport::try_transfer_pending(&_allocator);
- }
-};
-
-class FreeListPtrQueueBufferCompletedList : public TestPtrQueueBufferCBL {
- BufferNode::Stack _completed_list;
-
-public:
- FreeListPtrQueueBufferCompletedList() : _completed_list() {}
-
- ~FreeListPtrQueueBufferCompletedList() {
- assert(_completed_list.empty(), "completed list not empty");
- }
-
- virtual void push(BufferNode* node) {
- assert(node != NULL, "precondition");
- _completed_list.push(*node);
- }
-
- virtual BufferNode* pop() {
- GlobalCounter::CriticalSection cs(Thread::current());
- return _completed_list.pop();
- }
-};
+const size_t buffer_size = 1024;
TEST_VM(PtrQueueBufferAllocatorTest, stress_free_list_allocator) {
- FreeListPtrQueueBufferAllocator allocator;
- FreeListPtrQueueBufferCompletedList completed;
+ BufferNode::Allocator allocator("Test Allocator", buffer_size);
+ CompletedList completed;
run_test(&allocator, &completed);
}
< prev index next >