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 143 // PLAB book-keeping. 144 class PLABStats : public CHeapObj<mtGC> { 145 protected: 146 const char* _description; // Identifying string. 147 148 size_t _allocated; // Total allocated 149 size_t _wasted; // of which wasted (internal fragmentation) 150 size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) 151 size_t _unused; // Unused in last buffer 152 153 virtual void reset() { 154 _allocated = 0; 155 _wasted = 0; 156 _undo_wasted = 0; 157 _unused = 0; 158 } 159 160 public: 161 PLABStats(const char* description) : 162 _description(description), 163 _allocated(0), 164 _wasted(0), 165 _undo_wasted(0), 166 _unused(0) 167 { } 168 169 virtual ~PLABStats() { } 170 171 size_t allocated() const { return _allocated; } 172 size_t wasted() const { return _wasted; } 173 size_t unused() const { return _unused; } 174 size_t used() const { return allocated() - (wasted() + unused()); } 175 size_t undo_wasted() const { return _undo_wasted; } 176 177 static const size_t min_size() { 178 return PLAB::min_size(); 179 } 180 181 static const size_t max_size() { 182 return PLAB::max_size(); 183 } 184 185 inline void add_allocated(size_t v); 186 187 inline void add_unused(size_t v); 188 189 inline void add_wasted(size_t v); 190 191 inline void add_undo_wasted(size_t v); 192 }; 193 194 #endif // SHARE_GC_SHARED_PLAB_HPP