| 1 | /* |
| 2 | * Copyright (c) 2001, 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 | #ifndef SHARE_GC_SHARED_PLAB_HPP |
| 26 | #define SHARE_GC_SHARED_PLAB_HPP |
| 27 | |
| 28 | #include "gc/shared/gcUtil.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 | static size_t AlignmentReserve; |
| 50 | |
| 51 | // Force future allocations to fail and queries for contains() |
| 52 | // to return false. Returns the amount of unused space in this PLAB. |
| 53 | size_t invalidate() { |
| 54 | _end = _hard_end; |
| 55 | size_t remaining = pointer_delta(_end, _top); // Calculate remaining space. |
| 56 | _top = _end; // Force future allocations to fail. |
| 57 | _bottom = _end; // Force future contains() queries to return false. |
| 58 | return remaining; |
| 59 | } |
| 60 | |
| 61 | // Fill in remaining space with a dummy object and invalidate the PLAB. Returns |
| 62 | // the amount of remaining space. |
| 63 | size_t retire_internal(); |
| 64 | |
| 65 | void add_undo_waste(HeapWord* obj, size_t word_sz); |
| 66 | |
| 67 | // Undo the last allocation in the buffer, which is required to be of the |
| 68 | // "obj" of the given "word_sz". |
| 69 | void undo_last_allocation(HeapWord* obj, size_t word_sz); |
| 70 | |
| 71 | public: |
| 72 | // Initializes the buffer to be empty, but with the given "word_sz". |
| 73 | // Must get initialized with "set_buf" for an allocation to succeed. |
| 74 | PLAB(size_t word_sz); |
| 75 | |
| 76 | static size_t size_required_for_allocation(size_t word_size) { return word_size + AlignmentReserve; } |
| 77 | |
| 78 | // Minimum PLAB size. |
| 79 | static size_t min_size(); |
| 80 | // Maximum PLAB size. |
| 81 | static size_t max_size(); |
| 82 | |
| 83 | // If an allocation of the given "word_sz" can be satisfied within the |
| 84 | // buffer, do the allocation, returning a pointer to the start of the |
| 85 | // allocated block. If the allocation request cannot be satisfied, |
| 86 | // return NULL. |
| 87 | HeapWord* allocate(size_t word_sz) { |
| 88 | HeapWord* res = _top; |
| 89 | if (pointer_delta(_end, _top) >= word_sz) { |
| 90 | _top = _top + word_sz; |
| 91 | return res; |
| 92 | } else { |
| 93 | return NULL; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | // Allocate the object aligned to "alignment_in_bytes". |
| 98 | inline HeapWord* allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes); |
| 99 | |
| 100 | // Undo any allocation in the buffer, which is required to be of the |
| 101 | // "obj" of the given "word_sz". |
| 102 | void undo_allocation(HeapWord* obj, size_t word_sz); |
| 103 | |
| 104 | // The total (word) size of the buffer, including both allocated and |
| 105 | // unallocated space. |
| 106 | size_t word_sz() { return _word_sz; } |
| 107 | |
| 108 | size_t waste() { return _wasted; } |
| 109 | size_t undo_waste() { return _undo_wasted; } |
| 110 | |
| 111 | // The number of words of unallocated space remaining in the buffer. |
| 112 | size_t words_remaining() { |
| 113 | assert(_end >= _top, "Negative buffer" ); |
| 114 | return pointer_delta(_end, _top, HeapWordSize); |
| 115 | } |
| 116 | |
| 117 | bool contains(void* addr) { |
| 118 | return (void*)_bottom <= addr && addr < (void*)_hard_end; |
| 119 | } |
| 120 | |
| 121 | // Sets the space of the buffer to be [buf, space+word_sz()). |
| 122 | void set_buf(HeapWord* buf, size_t new_word_sz) { |
| 123 | assert(new_word_sz > AlignmentReserve, "Too small" ); |
| 124 | _word_sz = new_word_sz; |
| 125 | |
| 126 | _bottom = buf; |
| 127 | _top = _bottom; |
| 128 | _hard_end = _bottom + word_sz(); |
| 129 | _end = _hard_end - AlignmentReserve; |
| 130 | assert(_end >= _top, "Negative buffer" ); |
| 131 | // In support of ergonomic sizing |
| 132 | _allocated += word_sz(); |
| 133 | } |
| 134 | |
| 135 | // Flush allocation statistics into the given PLABStats supporting ergonomic |
| 136 | // sizing of PLAB's and retire the current buffer. To be called at the end of |
| 137 | // GC. |
| 138 | void flush_and_retire_stats(PLABStats* stats); |
| 139 | |
| 140 | // Fills in the unallocated portion of the buffer with a garbage object and updates |
| 141 | // statistics. To be called during GC. |
| 142 | void retire(); |
| 143 | }; |
| 144 | |
| 145 | // PLAB book-keeping. |
| 146 | class PLABStats : public CHeapObj<mtGC> { |
| 147 | protected: |
| 148 | const char* _description; // Identifying string. |
| 149 | |
| 150 | size_t _allocated; // Total allocated |
| 151 | size_t _wasted; // of which wasted (internal fragmentation) |
| 152 | size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) |
| 153 | size_t _unused; // Unused in last buffer |
| 154 | size_t _desired_net_plab_sz;// Output of filter (below), suitably trimmed and quantized |
| 155 | AdaptiveWeightedAverage |
| 156 | _filter; // Integrator with decay |
| 157 | |
| 158 | virtual void reset() { |
| 159 | _allocated = 0; |
| 160 | _wasted = 0; |
| 161 | _undo_wasted = 0; |
| 162 | _unused = 0; |
| 163 | } |
| 164 | |
| 165 | virtual void log_plab_allocation(); |
| 166 | virtual void log_sizing(size_t calculated, size_t net_desired); |
| 167 | |
| 168 | // helper for adjust_desired_plab_sz(). |
| 169 | virtual size_t compute_desired_plab_sz(); |
| 170 | |
| 171 | public: |
| 172 | PLABStats(const char* description, size_t desired_net_plab_sz_, unsigned wt) : |
| 173 | _description(description), |
| 174 | _allocated(0), |
| 175 | _wasted(0), |
| 176 | _undo_wasted(0), |
| 177 | _unused(0), |
| 178 | _desired_net_plab_sz(desired_net_plab_sz_), |
| 179 | _filter(wt) |
| 180 | { } |
| 181 | |
| 182 | virtual ~PLABStats() { } |
| 183 | |
| 184 | size_t allocated() const { return _allocated; } |
| 185 | size_t wasted() const { return _wasted; } |
| 186 | size_t unused() const { return _unused; } |
| 187 | size_t used() const { return allocated() - (wasted() + unused()); } |
| 188 | size_t undo_wasted() const { return _undo_wasted; } |
| 189 | |
| 190 | static const size_t min_size() { |
| 191 | return PLAB::min_size(); |
| 192 | } |
| 193 | |
| 194 | static const size_t max_size() { |
| 195 | return PLAB::max_size(); |
| 196 | } |
| 197 | |
| 198 | // Calculates plab size for current number of gc worker threads. |
| 199 | size_t desired_plab_sz(uint no_of_gc_workers); |
| 200 | |
| 201 | // Updates the current desired PLAB size. Computes the new desired PLAB size with one gc worker thread, |
| 202 | // updates _desired_plab_sz and clears sensor accumulators. |
| 203 | void adjust_desired_plab_sz(); |
| 204 | |
| 205 | inline void add_allocated(size_t v); |
| 206 | |
| 207 | inline void add_unused(size_t v); |
| 208 | |
| 209 | inline void add_wasted(size_t v); |
| 210 | |
| 211 | inline void add_undo_wasted(size_t v); |
| 212 | }; |
| 213 | |
| 214 | #endif // SHARE_GC_SHARED_PLAB_HPP |
| 215 | |