Thu, 12 Jun 2008 13:50:55 -0700
Merge
duke@435 | 1 | /* |
duke@435 | 2 | * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. |
duke@435 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@435 | 4 | * |
duke@435 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@435 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@435 | 7 | * published by the Free Software Foundation. |
duke@435 | 8 | * |
duke@435 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@435 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@435 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@435 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@435 | 13 | * accompanied this code). |
duke@435 | 14 | * |
duke@435 | 15 | * You should have received a copy of the GNU General Public License version |
duke@435 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@435 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@435 | 18 | * |
duke@435 | 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
duke@435 | 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
duke@435 | 21 | * have any questions. |
duke@435 | 22 | * |
duke@435 | 23 | */ |
duke@435 | 24 | |
duke@435 | 25 | class GlobalTLABStats; |
duke@435 | 26 | |
duke@435 | 27 | // ThreadLocalAllocBuffer: a descriptor for thread-local storage used by |
duke@435 | 28 | // the threads for allocation. |
duke@435 | 29 | // It is thread-private at any time, but maybe multiplexed over |
duke@435 | 30 | // time across multiple threads. The park()/unpark() pair is |
duke@435 | 31 | // used to make it avaiable for such multiplexing. |
duke@435 | 32 | class ThreadLocalAllocBuffer: public CHeapObj { |
duke@435 | 33 | friend class VMStructs; |
duke@435 | 34 | private: |
duke@435 | 35 | HeapWord* _start; // address of TLAB |
duke@435 | 36 | HeapWord* _top; // address after last allocation |
duke@435 | 37 | HeapWord* _pf_top; // allocation prefetch watermark |
duke@435 | 38 | HeapWord* _end; // allocation end (excluding alignment_reserve) |
duke@435 | 39 | size_t _desired_size; // desired size (including alignment_reserve) |
duke@435 | 40 | size_t _refill_waste_limit; // hold onto tlab if free() is larger than this |
duke@435 | 41 | |
duke@435 | 42 | static unsigned _target_refills; // expected number of refills between GCs |
duke@435 | 43 | |
duke@435 | 44 | unsigned _number_of_refills; |
duke@435 | 45 | unsigned _fast_refill_waste; |
duke@435 | 46 | unsigned _slow_refill_waste; |
duke@435 | 47 | unsigned _gc_waste; |
duke@435 | 48 | unsigned _slow_allocations; |
duke@435 | 49 | |
duke@435 | 50 | AdaptiveWeightedAverage _allocation_fraction; // fraction of eden allocated in tlabs |
duke@435 | 51 | |
duke@435 | 52 | void accumulate_statistics(); |
duke@435 | 53 | void initialize_statistics(); |
duke@435 | 54 | |
duke@435 | 55 | void set_start(HeapWord* start) { _start = start; } |
duke@435 | 56 | void set_end(HeapWord* end) { _end = end; } |
duke@435 | 57 | void set_top(HeapWord* top) { _top = top; } |
duke@435 | 58 | void set_pf_top(HeapWord* pf_top) { _pf_top = pf_top; } |
duke@435 | 59 | void set_desired_size(size_t desired_size) { _desired_size = desired_size; } |
duke@435 | 60 | void set_refill_waste_limit(size_t waste) { _refill_waste_limit = waste; } |
duke@435 | 61 | |
duke@435 | 62 | size_t initial_refill_waste_limit() { return desired_size() / TLABRefillWasteFraction; } |
duke@435 | 63 | |
duke@435 | 64 | static int target_refills() { return _target_refills; } |
duke@435 | 65 | size_t initial_desired_size(); |
duke@435 | 66 | |
duke@435 | 67 | size_t remaining() const { return end() == NULL ? 0 : pointer_delta(hard_end(), top()); } |
duke@435 | 68 | |
duke@435 | 69 | // Make parsable and release it. |
duke@435 | 70 | void reset(); |
duke@435 | 71 | |
duke@435 | 72 | // Resize based on amount of allocation, etc. |
duke@435 | 73 | void resize(); |
duke@435 | 74 | |
duke@435 | 75 | void invariants() const { assert(top() >= start() && top() <= end(), "invalid tlab"); } |
duke@435 | 76 | |
duke@435 | 77 | void initialize(HeapWord* start, HeapWord* top, HeapWord* end); |
duke@435 | 78 | |
duke@435 | 79 | void print_stats(const char* tag); |
duke@435 | 80 | |
duke@435 | 81 | Thread* myThread(); |
duke@435 | 82 | |
duke@435 | 83 | // statistics |
duke@435 | 84 | |
duke@435 | 85 | int number_of_refills() const { return _number_of_refills; } |
duke@435 | 86 | int fast_refill_waste() const { return _fast_refill_waste; } |
duke@435 | 87 | int slow_refill_waste() const { return _slow_refill_waste; } |
duke@435 | 88 | int gc_waste() const { return _gc_waste; } |
duke@435 | 89 | int slow_allocations() const { return _slow_allocations; } |
duke@435 | 90 | |
duke@435 | 91 | static GlobalTLABStats* _global_stats; |
duke@435 | 92 | static GlobalTLABStats* global_stats() { return _global_stats; } |
duke@435 | 93 | |
duke@435 | 94 | public: |
duke@435 | 95 | ThreadLocalAllocBuffer() : _allocation_fraction(TLABAllocationWeight) { |
duke@435 | 96 | // do nothing. tlabs must be inited by initialize() calls |
duke@435 | 97 | } |
duke@435 | 98 | |
duke@435 | 99 | static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); } |
duke@435 | 100 | static const size_t max_size(); |
duke@435 | 101 | |
duke@435 | 102 | HeapWord* start() const { return _start; } |
duke@435 | 103 | HeapWord* end() const { return _end; } |
duke@435 | 104 | HeapWord* hard_end() const { return _end + alignment_reserve(); } |
duke@435 | 105 | HeapWord* top() const { return _top; } |
duke@435 | 106 | HeapWord* pf_top() const { return _pf_top; } |
duke@435 | 107 | size_t desired_size() const { return _desired_size; } |
duke@435 | 108 | size_t free() const { return pointer_delta(end(), top()); } |
duke@435 | 109 | // Don't discard tlab if remaining space is larger than this. |
duke@435 | 110 | size_t refill_waste_limit() const { return _refill_waste_limit; } |
duke@435 | 111 | |
duke@435 | 112 | // Allocate size HeapWords. The memory is NOT initialized to zero. |
duke@435 | 113 | inline HeapWord* allocate(size_t size); |
duke@435 | 114 | static size_t alignment_reserve() { return align_object_size(typeArrayOopDesc::header_size(T_INT)); } |
duke@435 | 115 | static size_t alignment_reserve_in_bytes() { return alignment_reserve() * HeapWordSize; } |
duke@435 | 116 | |
duke@435 | 117 | // Return tlab size or remaining space in eden such that the |
duke@435 | 118 | // space is large enough to hold obj_size and necessary fill space. |
duke@435 | 119 | // Otherwise return 0; |
duke@435 | 120 | inline size_t compute_size(size_t obj_size); |
duke@435 | 121 | |
duke@435 | 122 | // Record slow allocation |
duke@435 | 123 | inline void record_slow_allocation(size_t obj_size); |
duke@435 | 124 | |
duke@435 | 125 | // Initialization at startup |
duke@435 | 126 | static void startup_initialization(); |
duke@435 | 127 | |
duke@435 | 128 | // Make an in-use tlab parsable, optionally also retiring it. |
duke@435 | 129 | void make_parsable(bool retire); |
duke@435 | 130 | |
duke@435 | 131 | // Retire in-use tlab before allocation of a new tlab |
duke@435 | 132 | void clear_before_allocation(); |
duke@435 | 133 | |
duke@435 | 134 | // Accumulate statistics across all tlabs before gc |
duke@435 | 135 | static void accumulate_statistics_before_gc(); |
duke@435 | 136 | |
duke@435 | 137 | // Resize tlabs for all threads |
duke@435 | 138 | static void resize_all_tlabs(); |
duke@435 | 139 | |
duke@435 | 140 | void fill(HeapWord* start, HeapWord* top, size_t new_size); |
duke@435 | 141 | void initialize(); |
duke@435 | 142 | |
duke@435 | 143 | static size_t refill_waste_limit_increment() { return TLABWasteIncrement; } |
duke@435 | 144 | |
duke@435 | 145 | // Code generation support |
duke@435 | 146 | static ByteSize start_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _start); } |
duke@435 | 147 | static ByteSize end_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _end ); } |
duke@435 | 148 | static ByteSize top_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _top ); } |
duke@435 | 149 | static ByteSize pf_top_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _pf_top ); } |
duke@435 | 150 | static ByteSize size_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _desired_size ); } |
duke@435 | 151 | static ByteSize refill_waste_limit_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _refill_waste_limit ); } |
duke@435 | 152 | |
duke@435 | 153 | static ByteSize number_of_refills_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _number_of_refills ); } |
duke@435 | 154 | static ByteSize fast_refill_waste_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _fast_refill_waste ); } |
duke@435 | 155 | static ByteSize slow_allocations_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _slow_allocations ); } |
duke@435 | 156 | |
duke@435 | 157 | void verify(); |
duke@435 | 158 | }; |
duke@435 | 159 | |
duke@435 | 160 | class GlobalTLABStats: public CHeapObj { |
duke@435 | 161 | private: |
duke@435 | 162 | |
duke@435 | 163 | // Accumulate perfdata in private variables because |
duke@435 | 164 | // PerfData should be write-only for security reasons |
duke@435 | 165 | // (see perfData.hpp) |
duke@435 | 166 | unsigned _allocating_threads; |
duke@435 | 167 | unsigned _total_refills; |
duke@435 | 168 | unsigned _max_refills; |
duke@435 | 169 | size_t _total_allocation; |
duke@435 | 170 | size_t _total_gc_waste; |
duke@435 | 171 | size_t _max_gc_waste; |
duke@435 | 172 | size_t _total_slow_refill_waste; |
duke@435 | 173 | size_t _max_slow_refill_waste; |
duke@435 | 174 | size_t _total_fast_refill_waste; |
duke@435 | 175 | size_t _max_fast_refill_waste; |
duke@435 | 176 | unsigned _total_slow_allocations; |
duke@435 | 177 | unsigned _max_slow_allocations; |
duke@435 | 178 | |
duke@435 | 179 | PerfVariable* _perf_allocating_threads; |
duke@435 | 180 | PerfVariable* _perf_total_refills; |
duke@435 | 181 | PerfVariable* _perf_max_refills; |
duke@435 | 182 | PerfVariable* _perf_allocation; |
duke@435 | 183 | PerfVariable* _perf_gc_waste; |
duke@435 | 184 | PerfVariable* _perf_max_gc_waste; |
duke@435 | 185 | PerfVariable* _perf_slow_refill_waste; |
duke@435 | 186 | PerfVariable* _perf_max_slow_refill_waste; |
duke@435 | 187 | PerfVariable* _perf_fast_refill_waste; |
duke@435 | 188 | PerfVariable* _perf_max_fast_refill_waste; |
duke@435 | 189 | PerfVariable* _perf_slow_allocations; |
duke@435 | 190 | PerfVariable* _perf_max_slow_allocations; |
duke@435 | 191 | |
duke@435 | 192 | AdaptiveWeightedAverage _allocating_threads_avg; |
duke@435 | 193 | |
duke@435 | 194 | public: |
duke@435 | 195 | GlobalTLABStats(); |
duke@435 | 196 | |
duke@435 | 197 | // Initialize all counters |
duke@435 | 198 | void initialize(); |
duke@435 | 199 | |
duke@435 | 200 | // Write all perf counters to the perf_counters |
duke@435 | 201 | void publish(); |
duke@435 | 202 | |
duke@435 | 203 | void print(); |
duke@435 | 204 | |
duke@435 | 205 | // Accessors |
duke@435 | 206 | unsigned allocating_threads_avg() { |
duke@435 | 207 | return MAX2((unsigned)(_allocating_threads_avg.average() + 0.5), 1U); |
duke@435 | 208 | } |
duke@435 | 209 | |
duke@435 | 210 | size_t allocation() { |
duke@435 | 211 | return _total_allocation; |
duke@435 | 212 | } |
duke@435 | 213 | |
duke@435 | 214 | // Update methods |
duke@435 | 215 | |
duke@435 | 216 | void update_allocating_threads() { |
duke@435 | 217 | _allocating_threads++; |
duke@435 | 218 | } |
duke@435 | 219 | void update_number_of_refills(unsigned value) { |
duke@435 | 220 | _total_refills += value; |
duke@435 | 221 | _max_refills = MAX2(_max_refills, value); |
duke@435 | 222 | } |
duke@435 | 223 | void update_allocation(size_t value) { |
duke@435 | 224 | _total_allocation += value; |
duke@435 | 225 | } |
duke@435 | 226 | void update_gc_waste(size_t value) { |
duke@435 | 227 | _total_gc_waste += value; |
duke@435 | 228 | _max_gc_waste = MAX2(_max_gc_waste, value); |
duke@435 | 229 | } |
duke@435 | 230 | void update_fast_refill_waste(size_t value) { |
duke@435 | 231 | _total_fast_refill_waste += value; |
duke@435 | 232 | _max_fast_refill_waste = MAX2(_max_fast_refill_waste, value); |
duke@435 | 233 | } |
duke@435 | 234 | void update_slow_refill_waste(size_t value) { |
duke@435 | 235 | _total_slow_refill_waste += value; |
duke@435 | 236 | _max_slow_refill_waste = MAX2(_max_slow_refill_waste, value); |
duke@435 | 237 | } |
duke@435 | 238 | void update_slow_allocations(unsigned value) { |
duke@435 | 239 | _total_slow_allocations += value; |
duke@435 | 240 | _max_slow_allocations = MAX2(_max_slow_allocations, value); |
duke@435 | 241 | } |
duke@435 | 242 | }; |