1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/memory/threadLocalAllocBuffer.hpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,242 @@ 1.4 +/* 1.5 + * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +class GlobalTLABStats; 1.29 + 1.30 +// ThreadLocalAllocBuffer: a descriptor for thread-local storage used by 1.31 +// the threads for allocation. 1.32 +// It is thread-private at any time, but maybe multiplexed over 1.33 +// time across multiple threads. The park()/unpark() pair is 1.34 +// used to make it avaiable for such multiplexing. 1.35 +class ThreadLocalAllocBuffer: public CHeapObj { 1.36 + friend class VMStructs; 1.37 +private: 1.38 + HeapWord* _start; // address of TLAB 1.39 + HeapWord* _top; // address after last allocation 1.40 + HeapWord* _pf_top; // allocation prefetch watermark 1.41 + HeapWord* _end; // allocation end (excluding alignment_reserve) 1.42 + size_t _desired_size; // desired size (including alignment_reserve) 1.43 + size_t _refill_waste_limit; // hold onto tlab if free() is larger than this 1.44 + 1.45 + static unsigned _target_refills; // expected number of refills between GCs 1.46 + 1.47 + unsigned _number_of_refills; 1.48 + unsigned _fast_refill_waste; 1.49 + unsigned _slow_refill_waste; 1.50 + unsigned _gc_waste; 1.51 + unsigned _slow_allocations; 1.52 + 1.53 + AdaptiveWeightedAverage _allocation_fraction; // fraction of eden allocated in tlabs 1.54 + 1.55 + void accumulate_statistics(); 1.56 + void initialize_statistics(); 1.57 + 1.58 + void set_start(HeapWord* start) { _start = start; } 1.59 + void set_end(HeapWord* end) { _end = end; } 1.60 + void set_top(HeapWord* top) { _top = top; } 1.61 + void set_pf_top(HeapWord* pf_top) { _pf_top = pf_top; } 1.62 + void set_desired_size(size_t desired_size) { _desired_size = desired_size; } 1.63 + void set_refill_waste_limit(size_t waste) { _refill_waste_limit = waste; } 1.64 + 1.65 + size_t initial_refill_waste_limit() { return desired_size() / TLABRefillWasteFraction; } 1.66 + 1.67 + static int target_refills() { return _target_refills; } 1.68 + size_t initial_desired_size(); 1.69 + 1.70 + size_t remaining() const { return end() == NULL ? 0 : pointer_delta(hard_end(), top()); } 1.71 + 1.72 + // Make parsable and release it. 1.73 + void reset(); 1.74 + 1.75 + // Resize based on amount of allocation, etc. 1.76 + void resize(); 1.77 + 1.78 + void invariants() const { assert(top() >= start() && top() <= end(), "invalid tlab"); } 1.79 + 1.80 + void initialize(HeapWord* start, HeapWord* top, HeapWord* end); 1.81 + 1.82 + void print_stats(const char* tag); 1.83 + 1.84 + Thread* myThread(); 1.85 + 1.86 + // statistics 1.87 + 1.88 + int number_of_refills() const { return _number_of_refills; } 1.89 + int fast_refill_waste() const { return _fast_refill_waste; } 1.90 + int slow_refill_waste() const { return _slow_refill_waste; } 1.91 + int gc_waste() const { return _gc_waste; } 1.92 + int slow_allocations() const { return _slow_allocations; } 1.93 + 1.94 + static GlobalTLABStats* _global_stats; 1.95 + static GlobalTLABStats* global_stats() { return _global_stats; } 1.96 + 1.97 +public: 1.98 + ThreadLocalAllocBuffer() : _allocation_fraction(TLABAllocationWeight) { 1.99 + // do nothing. tlabs must be inited by initialize() calls 1.100 + } 1.101 + 1.102 + static const size_t min_size() { return align_object_size(MinTLABSize / HeapWordSize); } 1.103 + static const size_t max_size(); 1.104 + 1.105 + HeapWord* start() const { return _start; } 1.106 + HeapWord* end() const { return _end; } 1.107 + HeapWord* hard_end() const { return _end + alignment_reserve(); } 1.108 + HeapWord* top() const { return _top; } 1.109 + HeapWord* pf_top() const { return _pf_top; } 1.110 + size_t desired_size() const { return _desired_size; } 1.111 + size_t free() const { return pointer_delta(end(), top()); } 1.112 + // Don't discard tlab if remaining space is larger than this. 1.113 + size_t refill_waste_limit() const { return _refill_waste_limit; } 1.114 + 1.115 + // Allocate size HeapWords. The memory is NOT initialized to zero. 1.116 + inline HeapWord* allocate(size_t size); 1.117 + static size_t alignment_reserve() { return align_object_size(typeArrayOopDesc::header_size(T_INT)); } 1.118 + static size_t alignment_reserve_in_bytes() { return alignment_reserve() * HeapWordSize; } 1.119 + 1.120 + // Return tlab size or remaining space in eden such that the 1.121 + // space is large enough to hold obj_size and necessary fill space. 1.122 + // Otherwise return 0; 1.123 + inline size_t compute_size(size_t obj_size); 1.124 + 1.125 + // Record slow allocation 1.126 + inline void record_slow_allocation(size_t obj_size); 1.127 + 1.128 + // Initialization at startup 1.129 + static void startup_initialization(); 1.130 + 1.131 + // Make an in-use tlab parsable, optionally also retiring it. 1.132 + void make_parsable(bool retire); 1.133 + 1.134 + // Retire in-use tlab before allocation of a new tlab 1.135 + void clear_before_allocation(); 1.136 + 1.137 + // Accumulate statistics across all tlabs before gc 1.138 + static void accumulate_statistics_before_gc(); 1.139 + 1.140 + // Resize tlabs for all threads 1.141 + static void resize_all_tlabs(); 1.142 + 1.143 + void fill(HeapWord* start, HeapWord* top, size_t new_size); 1.144 + void initialize(); 1.145 + 1.146 + static size_t refill_waste_limit_increment() { return TLABWasteIncrement; } 1.147 + 1.148 + // Code generation support 1.149 + static ByteSize start_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _start); } 1.150 + static ByteSize end_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _end ); } 1.151 + static ByteSize top_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _top ); } 1.152 + static ByteSize pf_top_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _pf_top ); } 1.153 + static ByteSize size_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _desired_size ); } 1.154 + static ByteSize refill_waste_limit_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _refill_waste_limit ); } 1.155 + 1.156 + static ByteSize number_of_refills_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _number_of_refills ); } 1.157 + static ByteSize fast_refill_waste_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _fast_refill_waste ); } 1.158 + static ByteSize slow_allocations_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _slow_allocations ); } 1.159 + 1.160 + void verify(); 1.161 +}; 1.162 + 1.163 +class GlobalTLABStats: public CHeapObj { 1.164 +private: 1.165 + 1.166 + // Accumulate perfdata in private variables because 1.167 + // PerfData should be write-only for security reasons 1.168 + // (see perfData.hpp) 1.169 + unsigned _allocating_threads; 1.170 + unsigned _total_refills; 1.171 + unsigned _max_refills; 1.172 + size_t _total_allocation; 1.173 + size_t _total_gc_waste; 1.174 + size_t _max_gc_waste; 1.175 + size_t _total_slow_refill_waste; 1.176 + size_t _max_slow_refill_waste; 1.177 + size_t _total_fast_refill_waste; 1.178 + size_t _max_fast_refill_waste; 1.179 + unsigned _total_slow_allocations; 1.180 + unsigned _max_slow_allocations; 1.181 + 1.182 + PerfVariable* _perf_allocating_threads; 1.183 + PerfVariable* _perf_total_refills; 1.184 + PerfVariable* _perf_max_refills; 1.185 + PerfVariable* _perf_allocation; 1.186 + PerfVariable* _perf_gc_waste; 1.187 + PerfVariable* _perf_max_gc_waste; 1.188 + PerfVariable* _perf_slow_refill_waste; 1.189 + PerfVariable* _perf_max_slow_refill_waste; 1.190 + PerfVariable* _perf_fast_refill_waste; 1.191 + PerfVariable* _perf_max_fast_refill_waste; 1.192 + PerfVariable* _perf_slow_allocations; 1.193 + PerfVariable* _perf_max_slow_allocations; 1.194 + 1.195 + AdaptiveWeightedAverage _allocating_threads_avg; 1.196 + 1.197 +public: 1.198 + GlobalTLABStats(); 1.199 + 1.200 + // Initialize all counters 1.201 + void initialize(); 1.202 + 1.203 + // Write all perf counters to the perf_counters 1.204 + void publish(); 1.205 + 1.206 + void print(); 1.207 + 1.208 + // Accessors 1.209 + unsigned allocating_threads_avg() { 1.210 + return MAX2((unsigned)(_allocating_threads_avg.average() + 0.5), 1U); 1.211 + } 1.212 + 1.213 + size_t allocation() { 1.214 + return _total_allocation; 1.215 + } 1.216 + 1.217 + // Update methods 1.218 + 1.219 + void update_allocating_threads() { 1.220 + _allocating_threads++; 1.221 + } 1.222 + void update_number_of_refills(unsigned value) { 1.223 + _total_refills += value; 1.224 + _max_refills = MAX2(_max_refills, value); 1.225 + } 1.226 + void update_allocation(size_t value) { 1.227 + _total_allocation += value; 1.228 + } 1.229 + void update_gc_waste(size_t value) { 1.230 + _total_gc_waste += value; 1.231 + _max_gc_waste = MAX2(_max_gc_waste, value); 1.232 + } 1.233 + void update_fast_refill_waste(size_t value) { 1.234 + _total_fast_refill_waste += value; 1.235 + _max_fast_refill_waste = MAX2(_max_fast_refill_waste, value); 1.236 + } 1.237 + void update_slow_refill_waste(size_t value) { 1.238 + _total_slow_refill_waste += value; 1.239 + _max_slow_refill_waste = MAX2(_max_slow_refill_waste, value); 1.240 + } 1.241 + void update_slow_allocations(unsigned value) { 1.242 + _total_slow_allocations += value; 1.243 + _max_slow_allocations = MAX2(_max_slow_allocations, value); 1.244 + } 1.245 +};