1 /* 2 * Copyright (c) 2001, 2023, 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 #ifndef SHARE_GC_SHARED_PLAB_HPP 26 #define SHARE_GC_SHARED_PLAB_HPP 27 28 #include "gc/shared/collectedHeap.hpp" 29 #include "memory/allocation.hpp" 30 #include "utilities/globalDefinitions.hpp" 31 32 // Forward declarations. 33 class PLABStats; 34 35 // A per-thread allocation buffer used during GC. 36 class PLAB: public CHeapObj<mtGC> { 37 protected: 38 char head[32]; 39 size_t _word_sz; // In HeapWord units 40 HeapWord* _bottom; 41 HeapWord* _top; 42 HeapWord* _end; // Last allocatable address + 1 43 HeapWord* _hard_end; // _end + AlignmentReserve 44 // In support of ergonomic sizing of PLAB's 45 size_t _allocated; // in HeapWord units 46 size_t _wasted; // in HeapWord units 47 size_t _undo_wasted; 48 char tail[32]; 49 50 // Force future allocations to fail and queries for contains() 51 // to return false. Returns the amount of unused space in this PLAB. 52 size_t invalidate() { 53 _end = _hard_end; 54 size_t remaining = pointer_delta(_end, _top); // Calculate remaining space. 55 _top = _end; // Force future allocations to fail. 56 _bottom = _end; // Force future contains() queries to return false. 57 return remaining; 58 } 59 60 // Fill in remaining space with a dummy object and invalidate the PLAB. Returns 61 // the amount of remaining space. 62 size_t retire_internal(); 63 64 void add_undo_waste(HeapWord* obj, size_t word_sz); 65 66 // Undo the last allocation in the buffer, which is required to be of the 67 // "obj" of the given "word_sz". 68 void undo_last_allocation(HeapWord* obj, size_t word_sz); 69 70 public: 71 static void startup_initialization(); 72 73 // Initializes the buffer to be empty, but with the given "word_sz". 74 // Must get initialized with "set_buf" for an allocation to succeed. 75 PLAB(size_t word_sz); 76 77 static size_t size_required_for_allocation(size_t word_size) { return word_size + CollectedHeap::lab_alignment_reserve(); } 78 79 // Minimum PLAB size. 80 static size_t min_size(); 81 // Maximum PLAB size. 82 static size_t max_size(); 83 84 // If an allocation of the given "word_sz" can be satisfied within the 85 // buffer, do the allocation, returning a pointer to the start of the 86 // allocated block. If the allocation request cannot be satisfied, 87 // return null. 88 HeapWord* allocate(size_t word_sz) { 89 HeapWord* res = _top; 90 if (pointer_delta(_end, _top) >= word_sz) { 91 _top = _top + word_sz; 92 return res; 93 } else { 94 return nullptr; 95 } 96 } 97 98 // Undo any allocation in the buffer, which is required to be of the 99 // "obj" of the given "word_sz". 100 void undo_allocation(HeapWord* obj, size_t word_sz); 101 102 // The total (word) size of the buffer, including both allocated and 103 // unallocated space. 104 size_t word_sz() { return _word_sz; } 105 106 size_t waste() { return _wasted; } 107 size_t undo_waste() { return _undo_wasted; } 108 109 // The number of words of unallocated space remaining in the buffer. 110 size_t words_remaining() { 111 assert(_end >= _top, "Negative buffer"); 112 return pointer_delta(_end, _top, HeapWordSize); 113 } 114 115 bool contains(void* addr) { 116 return (void*)_bottom <= addr && addr < (void*)_hard_end; 117 } 118 119 // Sets the space of the buffer to be [buf, space+word_sz()). 120 void set_buf(HeapWord* buf, size_t new_word_sz) { 121 assert(new_word_sz > CollectedHeap::lab_alignment_reserve(), "Too small"); 122 _word_sz = new_word_sz; 123 124 _bottom = buf; 125 _top = _bottom; 126 _hard_end = _bottom + word_sz(); 127 _end = _hard_end - CollectedHeap::lab_alignment_reserve(); 128 assert(_end >= _top, "Negative buffer"); 129 // In support of ergonomic sizing 130 _allocated += word_sz(); 131 } 132 133 // Flush allocation statistics into the given PLABStats supporting ergonomic 134 // sizing of PLAB's and retire the current buffer. To be called at the end of 135 // GC. 136 void flush_and_retire_stats(PLABStats* stats); 137 138 // Fills in the unallocated portion of the buffer with a garbage object and updates 139 // statistics. To be called during GC. 140 void retire(); 141 142 HeapWord* top() { 143 return _top; 144 } 145 }; 146 147 // PLAB book-keeping. 148 class PLABStats : public CHeapObj<mtGC> { 149 protected: 150 const char* _description; // Identifying string. 151 152 size_t _allocated; // Total allocated 153 size_t _wasted; // of which wasted (internal fragmentation) 154 size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) 155 size_t _unused; // Unused in last buffer 156 157 virtual void reset() { 158 _allocated = 0; 159 _wasted = 0; 160 _undo_wasted = 0; 161 _unused = 0; 162 } 163 164 public: 165 PLABStats(const char* description) : 166 _description(description), 167 _allocated(0), 168 _wasted(0), 169 _undo_wasted(0), 170 _unused(0) 171 { } 172 173 virtual ~PLABStats() { } 174 175 size_t allocated() const { return _allocated; } 176 size_t wasted() const { return _wasted; } 177 size_t unused() const { return _unused; } 178 size_t used() const { return allocated() - (wasted() + unused()); } 179 size_t undo_wasted() const { return _undo_wasted; } 180 181 static const size_t min_size() { 182 return PLAB::min_size(); 183 } 184 185 static const size_t max_size() { 186 return PLAB::max_size(); 187 } 188 189 inline void add_allocated(size_t v); 190 191 inline void add_unused(size_t v); 192 193 inline void add_wasted(size_t v); 194 195 inline void add_undo_wasted(size_t v); 196 }; 197 198 #endif // SHARE_GC_SHARED_PLAB_HPP