32 #include "utilities/copy.hpp" |
32 #include "utilities/copy.hpp" |
33 |
33 |
34 // Thread-Local Edens support |
34 // Thread-Local Edens support |
35 |
35 |
36 // static member initialization |
36 // static member initialization |
|
37 size_t ThreadLocalAllocBuffer::_max_size = 0; |
37 unsigned ThreadLocalAllocBuffer::_target_refills = 0; |
38 unsigned ThreadLocalAllocBuffer::_target_refills = 0; |
38 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL; |
39 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL; |
39 |
40 |
40 void ThreadLocalAllocBuffer::clear_before_allocation() { |
41 void ThreadLocalAllocBuffer::clear_before_allocation() { |
41 _slow_refill_waste += (unsigned)remaining(); |
42 _slow_refill_waste += (unsigned)remaining(); |
43 } |
44 } |
44 |
45 |
45 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() { |
46 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() { |
46 global_stats()->initialize(); |
47 global_stats()->initialize(); |
47 |
48 |
48 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { |
49 for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { |
49 thread->tlab().accumulate_statistics(); |
50 thread->tlab().accumulate_statistics(); |
50 thread->tlab().initialize_statistics(); |
51 thread->tlab().initialize_statistics(); |
51 } |
52 } |
52 |
53 |
53 // Publish new stats if some allocation occurred. |
54 // Publish new stats if some allocation occurred. |
58 } |
59 } |
59 } |
60 } |
60 } |
61 } |
61 |
62 |
62 void ThreadLocalAllocBuffer::accumulate_statistics() { |
63 void ThreadLocalAllocBuffer::accumulate_statistics() { |
63 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize; |
64 Thread* thread = myThread(); |
64 size_t unused = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; |
65 size_t capacity = Universe::heap()->tlab_capacity(thread); |
65 size_t used = capacity - unused; |
66 size_t used = Universe::heap()->tlab_used(thread); |
66 |
|
67 // Update allocation history if a reasonable amount of eden was allocated. |
|
68 bool update_allocation_history = used > 0.5 * capacity; |
|
69 |
67 |
70 _gc_waste += (unsigned)remaining(); |
68 _gc_waste += (unsigned)remaining(); |
|
69 size_t total_allocated = thread->allocated_bytes(); |
|
70 size_t allocated_since_last_gc = total_allocated - _allocated_before_last_gc; |
|
71 _allocated_before_last_gc = total_allocated; |
71 |
72 |
72 if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { |
73 if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { |
73 print_stats("gc"); |
74 print_stats("gc"); |
74 } |
75 } |
75 |
76 |
76 if (_number_of_refills > 0) { |
77 if (_number_of_refills > 0) { |
|
78 // Update allocation history if a reasonable amount of eden was allocated. |
|
79 bool update_allocation_history = used > 0.5 * capacity; |
77 |
80 |
78 if (update_allocation_history) { |
81 if (update_allocation_history) { |
79 // Average the fraction of eden allocated in a tlab by this |
82 // Average the fraction of eden allocated in a tlab by this |
80 // thread for use in the next resize operation. |
83 // thread for use in the next resize operation. |
81 // _gc_waste is not subtracted because it's included in |
84 // _gc_waste is not subtracted because it's included in |
82 // "used". |
85 // "used". |
83 size_t allocation = _number_of_refills * desired_size(); |
86 // The result can be larger than 1.0 due to direct to old allocations. |
84 double alloc_frac = allocation / (double) used; |
87 // These allocations should ideally not be counted but since it is not possible |
|
88 // to filter them out here we just cap the fraction to be at most 1.0. |
|
89 double alloc_frac = MIN2(1.0, (double) allocated_since_last_gc / used); |
85 _allocation_fraction.sample(alloc_frac); |
90 _allocation_fraction.sample(alloc_frac); |
86 } |
91 } |
87 global_stats()->update_allocating_threads(); |
92 global_stats()->update_allocating_threads(); |
88 global_stats()->update_number_of_refills(_number_of_refills); |
93 global_stats()->update_number_of_refills(_number_of_refills); |
89 global_stats()->update_allocation(_number_of_refills * desired_size()); |
94 global_stats()->update_allocation(_number_of_refills * desired_size()); |
124 (start() == NULL && end() == NULL && top() == NULL), |
129 (start() == NULL && end() == NULL && top() == NULL), |
125 "TLAB must be reset"); |
130 "TLAB must be reset"); |
126 } |
131 } |
127 |
132 |
128 void ThreadLocalAllocBuffer::resize_all_tlabs() { |
133 void ThreadLocalAllocBuffer::resize_all_tlabs() { |
129 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { |
134 if (ResizeTLAB) { |
130 thread->tlab().resize(); |
135 for (JavaThread *thread = Threads::first(); thread != NULL; thread = thread->next()) { |
|
136 thread->tlab().resize(); |
|
137 } |
131 } |
138 } |
132 } |
139 } |
133 |
140 |
134 void ThreadLocalAllocBuffer::resize() { |
141 void ThreadLocalAllocBuffer::resize() { |
135 |
142 // Compute the next tlab size using expected allocation amount |
136 if (ResizeTLAB) { |
143 assert(ResizeTLAB, "Should not call this otherwise"); |
137 // Compute the next tlab size using expected allocation amount |
144 size_t alloc = (size_t)(_allocation_fraction.average() * |
138 size_t alloc = (size_t)(_allocation_fraction.average() * |
145 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize)); |
139 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize)); |
146 size_t new_size = alloc / _target_refills; |
140 size_t new_size = alloc / _target_refills; |
147 |
141 |
148 new_size = MIN2(MAX2(new_size, min_size()), max_size()); |
142 new_size = MIN2(MAX2(new_size, min_size()), max_size()); |
149 |
143 |
150 size_t aligned_new_size = align_object_size(new_size); |
144 size_t aligned_new_size = align_object_size(new_size); |
151 |
145 |
152 if (PrintTLAB && Verbose) { |
146 if (PrintTLAB && Verbose) { |
153 gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" |
147 gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" |
154 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", |
148 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", |
155 myThread(), myThread()->osthread()->thread_id(), |
149 myThread(), myThread()->osthread()->thread_id(), |
156 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); |
150 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); |
157 } |
151 } |
158 set_desired_size(aligned_new_size); |
152 set_desired_size(aligned_new_size); |
159 set_refill_waste_limit(initial_refill_waste_limit()); |
153 |
|
154 set_refill_waste_limit(initial_refill_waste_limit()); |
|
155 } |
|
156 } |
160 } |
157 |
161 |
158 void ThreadLocalAllocBuffer::initialize_statistics() { |
162 void ThreadLocalAllocBuffer::initialize_statistics() { |
159 _number_of_refills = 0; |
163 _number_of_refills = 0; |
160 _fast_refill_waste = 0; |
164 _fast_refill_waste = 0; |
246 init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); |
250 init_sz = MIN2(MAX2(init_sz, min_size()), max_size()); |
247 } |
251 } |
248 return init_sz; |
252 return init_sz; |
249 } |
253 } |
250 |
254 |
251 const size_t ThreadLocalAllocBuffer::max_size() { |
|
252 |
|
253 // TLABs can't be bigger than we can fill with a int[Integer.MAX_VALUE]. |
|
254 // This restriction could be removed by enabling filling with multiple arrays. |
|
255 // If we compute that the reasonable way as |
|
256 // header_size + ((sizeof(jint) * max_jint) / HeapWordSize) |
|
257 // we'll overflow on the multiply, so we do the divide first. |
|
258 // We actually lose a little by dividing first, |
|
259 // but that just makes the TLAB somewhat smaller than the biggest array, |
|
260 // which is fine, since we'll be able to fill that. |
|
261 |
|
262 size_t unaligned_max_size = typeArrayOopDesc::header_size(T_INT) + |
|
263 sizeof(jint) * |
|
264 ((juint) max_jint / (size_t) HeapWordSize); |
|
265 return align_size_down(unaligned_max_size, MinObjAlignment); |
|
266 } |
|
267 |
|
268 void ThreadLocalAllocBuffer::print_stats(const char* tag) { |
255 void ThreadLocalAllocBuffer::print_stats(const char* tag) { |
269 Thread* thrd = myThread(); |
256 Thread* thrd = myThread(); |
270 size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; |
257 size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste; |
271 size_t alloc = _number_of_refills * _desired_size; |
258 size_t alloc = _number_of_refills * _desired_size; |
272 double waste_percent = alloc == 0 ? 0.0 : |
259 double waste_percent = alloc == 0 ? 0.0 : |
273 100.0 * waste / alloc; |
260 100.0 * waste / alloc; |
274 size_t tlab_used = Universe::heap()->tlab_capacity(thrd) - |
261 size_t tlab_used = Universe::heap()->tlab_used(thrd); |
275 Universe::heap()->unsafe_max_tlab_alloc(thrd); |
|
276 gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" |
262 gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]" |
277 " desired_size: " SIZE_FORMAT "KB" |
263 " desired_size: " SIZE_FORMAT "KB" |
278 " slow allocs: %d refill waste: " SIZE_FORMAT "B" |
264 " slow allocs: %d refill waste: " SIZE_FORMAT "B" |
279 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB" |
265 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB" |
280 " slow: %dB fast: %dB\n", |
266 " slow: %dB fast: %dB\n", |