1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "gc/g1/g1FreeIdSet.hpp" 27 #include "memory/allocation.hpp" 28 #include "runtime/atomic.hpp" 29 #include "runtime/interfaceSupport.inline.hpp" 30 #include "runtime/semaphore.inline.hpp" 31 #include "runtime/thread.hpp" 32 #include "utilities/debug.hpp" 33 #include "utilities/globalDefinitions.hpp" 34 #include "utilities/ostream.hpp" 35 #include "threadHelper.inline.hpp" 36 #include "unittest.hpp" 37 38 struct G1FreeIdSet::TestSupport : AllStatic { 39 static uint next(const G1FreeIdSet& set, uint index) { 40 assert(index < set._size, "precondition"); 41 return set._next[index]; 42 } 43 44 static uint start(const G1FreeIdSet& set) { return set._start; } 45 static uint size(const G1FreeIdSet& set) { return set._size; } 46 static uintx mask(const G1FreeIdSet& set) { return set._head_index_mask; } 47 static uintx head(const G1FreeIdSet& set) { return Atomic::load(&set._head); } 48 49 static uint head_index(const G1FreeIdSet& set, uintx head) { 50 return set.head_index(head); 51 } 52 }; 53 54 typedef G1FreeIdSet::TestSupport TestSupport; 55 56 TEST_VM(G1FreeIdSetTest, initial_state) { 57 const uint start = 5; 58 const uint size = 4; 59 G1FreeIdSet set(start, size); 60 61 ASSERT_EQ(start, TestSupport::start(set)); 62 ASSERT_EQ(size, TestSupport::size(set)); 63 ASSERT_EQ(7u, TestSupport::mask(set)); 64 ASSERT_EQ(0u, TestSupport::head(set)); 65 for (uint i = 0; i < size; ++i) { 66 ASSERT_EQ(i + 1, TestSupport::next(set, i)); 67 } 68 } 69 70 TEST_VM(G1FreeIdSetTest, non_blocking_ops) { 71 const uint start = 5; 72 const uint size = 3; 73 G1FreeIdSet set(start, size); 74 75 ASSERT_EQ(5u, set.claim_par_id()); 76 ASSERT_EQ(1u, TestSupport::head_index(set, TestSupport::head(set))); 77 ASSERT_EQ(6u, set.claim_par_id()); 78 ASSERT_EQ(2u, TestSupport::head_index(set, TestSupport::head(set))); 79 ASSERT_EQ(7u, set.claim_par_id()); 80 ASSERT_EQ(3u, TestSupport::head_index(set, TestSupport::head(set))); 81 82 set.release_par_id(5u); 83 set.release_par_id(6u); 84 ASSERT_EQ(6u, set.claim_par_id()); 85 ASSERT_EQ(5u, set.claim_par_id()); 86 } 87 88 class TestG1FreeIdSetThread : public JavaTestThread { 89 G1FreeIdSet* _set; 90 volatile size_t* _total_allocations; 91 volatile bool* _continue_running; 92 size_t _allocations; 93 uint _thread_number; 94 95 public: 96 TestG1FreeIdSetThread(uint thread_number, 97 Semaphore* post, 98 G1FreeIdSet* set, 99 volatile size_t* total_allocations, 100 volatile bool* continue_running) : 101 JavaTestThread(post), 102 _set(set), 103 _total_allocations(total_allocations), 104 _continue_running(continue_running), 105 _allocations(0), 106 _thread_number(thread_number) 107 {} 108 109 virtual void main_run() { 110 while (Atomic::load_acquire(_continue_running)) { 111 uint id = _set->claim_par_id(); 112 _set->release_par_id(id); 113 ++_allocations; 114 ThreadBlockInVM tbiv(this); // Safepoint check. 115 } 116 tty->print_cr("%u allocations: " SIZE_FORMAT, _thread_number, _allocations); 117 Atomic::add(_allocations, _total_allocations); 118 } 119 }; 120 121 TEST_VM(G1FreeIdSetTest, stress) { 122 const uint start = 5; 123 const uint size = 3; 124 const uint nthreads = size + 1; 125 const uint milliseconds_to_run = 1000; 126 127 Semaphore post; 128 volatile size_t total_allocations = 0; 129 volatile bool continue_running = true; 130 131 G1FreeIdSet set(start, size); 132 133 TestG1FreeIdSetThread* threads[nthreads] = {}; 134 for (uint i = 0; i < nthreads; ++i) { 135 threads[i] = new TestG1FreeIdSetThread(i, 136 &post, 137 &set, 138 &total_allocations, 139 &continue_running); 140 threads[i]->doit(); 141 } 142 143 JavaThread* this_thread = JavaThread::current(); 144 tty->print_cr("Stressing G1FreeIdSet for %u ms", milliseconds_to_run); 145 { 146 ThreadInVMfromNative invm(this_thread); 147 this_thread->sleep(milliseconds_to_run); 148 } 149 Atomic::release_store(&continue_running, false); 150 for (uint i = 0; i < nthreads; ++i) { 151 ThreadInVMfromNative invm(this_thread); 152 post.wait_with_safepoint_check(this_thread); 153 } 154 tty->print_cr("total allocations: " SIZE_FORMAT, total_allocations); 155 tty->print_cr("final free list: "); 156 uint ids[size] = {}; 157 for (uint i = 0; i < size; ++i) { 158 uint id = set.claim_par_id(); 159 uint index = id - TestSupport::start(set); 160 ASSERT_LT(index, TestSupport::size(set)); 161 tty->print_cr(" %u: %u", i, index); 162 } 163 ASSERT_EQ(size, TestSupport::head_index(set, TestSupport::head(set))); 164 }