< 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 >