annotate src/share/vm/memory/threadLocalAllocBuffer.cpp @ 452:00b023ae2d78

6722113: CMS: Incorrect overflow handling during precleaning of Reference lists Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery. Reviewed-by: apetrusenko, jcoomes
author ysr
date Thu, 20 Nov 2008 12:27:41 -0800
parents a61af66fc99e
children 7d7a7c599c17
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a61af66fc99e Initial load
duke
parents:
diff changeset
1 /*
a61af66fc99e Initial load
duke
parents:
diff changeset
2 * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
a61af66fc99e Initial load
duke
parents:
diff changeset
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
a61af66fc99e Initial load
duke
parents:
diff changeset
4 *
a61af66fc99e Initial load
duke
parents:
diff changeset
5 * This code is free software; you can redistribute it and/or modify it
a61af66fc99e Initial load
duke
parents:
diff changeset
6 * under the terms of the GNU General Public License version 2 only, as
a61af66fc99e Initial load
duke
parents:
diff changeset
7 * published by the Free Software Foundation.
a61af66fc99e Initial load
duke
parents:
diff changeset
8 *
a61af66fc99e Initial load
duke
parents:
diff changeset
9 * This code is distributed in the hope that it will be useful, but WITHOUT
a61af66fc99e Initial load
duke
parents:
diff changeset
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
a61af66fc99e Initial load
duke
parents:
diff changeset
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a61af66fc99e Initial load
duke
parents:
diff changeset
12 * version 2 for more details (a copy is included in the LICENSE file that
a61af66fc99e Initial load
duke
parents:
diff changeset
13 * accompanied this code).
a61af66fc99e Initial load
duke
parents:
diff changeset
14 *
a61af66fc99e Initial load
duke
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License version
a61af66fc99e Initial load
duke
parents:
diff changeset
16 * 2 along with this work; if not, write to the Free Software Foundation,
a61af66fc99e Initial load
duke
parents:
diff changeset
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
a61af66fc99e Initial load
duke
parents:
diff changeset
18 *
a61af66fc99e Initial load
duke
parents:
diff changeset
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
a61af66fc99e Initial load
duke
parents:
diff changeset
20 * CA 95054 USA or visit www.sun.com if you need additional information or
a61af66fc99e Initial load
duke
parents:
diff changeset
21 * have any questions.
a61af66fc99e Initial load
duke
parents:
diff changeset
22 *
a61af66fc99e Initial load
duke
parents:
diff changeset
23 */
a61af66fc99e Initial load
duke
parents:
diff changeset
24
a61af66fc99e Initial load
duke
parents:
diff changeset
25 // Thread-Local Edens support
a61af66fc99e Initial load
duke
parents:
diff changeset
26
a61af66fc99e Initial load
duke
parents:
diff changeset
27 # include "incls/_precompiled.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
28 # include "incls/_threadLocalAllocBuffer.cpp.incl"
a61af66fc99e Initial load
duke
parents:
diff changeset
29
a61af66fc99e Initial load
duke
parents:
diff changeset
30 // static member initialization
a61af66fc99e Initial load
duke
parents:
diff changeset
31 unsigned ThreadLocalAllocBuffer::_target_refills = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
32 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
33
a61af66fc99e Initial load
duke
parents:
diff changeset
34 void ThreadLocalAllocBuffer::clear_before_allocation() {
a61af66fc99e Initial load
duke
parents:
diff changeset
35 _slow_refill_waste += (unsigned)remaining();
a61af66fc99e Initial load
duke
parents:
diff changeset
36 make_parsable(true); // also retire the TLAB
a61af66fc99e Initial load
duke
parents:
diff changeset
37 }
a61af66fc99e Initial load
duke
parents:
diff changeset
38
a61af66fc99e Initial load
duke
parents:
diff changeset
39 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() {
a61af66fc99e Initial load
duke
parents:
diff changeset
40 global_stats()->initialize();
a61af66fc99e Initial load
duke
parents:
diff changeset
41
a61af66fc99e Initial load
duke
parents:
diff changeset
42 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
43 thread->tlab().accumulate_statistics();
a61af66fc99e Initial load
duke
parents:
diff changeset
44 thread->tlab().initialize_statistics();
a61af66fc99e Initial load
duke
parents:
diff changeset
45 }
a61af66fc99e Initial load
duke
parents:
diff changeset
46
a61af66fc99e Initial load
duke
parents:
diff changeset
47 // Publish new stats if some allocation occurred.
a61af66fc99e Initial load
duke
parents:
diff changeset
48 if (global_stats()->allocation() != 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
49 global_stats()->publish();
a61af66fc99e Initial load
duke
parents:
diff changeset
50 if (PrintTLAB) {
a61af66fc99e Initial load
duke
parents:
diff changeset
51 global_stats()->print();
a61af66fc99e Initial load
duke
parents:
diff changeset
52 }
a61af66fc99e Initial load
duke
parents:
diff changeset
53 }
a61af66fc99e Initial load
duke
parents:
diff changeset
54 }
a61af66fc99e Initial load
duke
parents:
diff changeset
55
a61af66fc99e Initial load
duke
parents:
diff changeset
56 void ThreadLocalAllocBuffer::accumulate_statistics() {
a61af66fc99e Initial load
duke
parents:
diff changeset
57 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize;
a61af66fc99e Initial load
duke
parents:
diff changeset
58 size_t unused = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize;
a61af66fc99e Initial load
duke
parents:
diff changeset
59 size_t used = capacity - unused;
a61af66fc99e Initial load
duke
parents:
diff changeset
60
a61af66fc99e Initial load
duke
parents:
diff changeset
61 // Update allocation history if a reasonable amount of eden was allocated.
a61af66fc99e Initial load
duke
parents:
diff changeset
62 bool update_allocation_history = used > 0.5 * capacity;
a61af66fc99e Initial load
duke
parents:
diff changeset
63
a61af66fc99e Initial load
duke
parents:
diff changeset
64 _gc_waste += (unsigned)remaining();
a61af66fc99e Initial load
duke
parents:
diff changeset
65
a61af66fc99e Initial load
duke
parents:
diff changeset
66 if (PrintTLAB && (_number_of_refills > 0 || Verbose)) {
a61af66fc99e Initial load
duke
parents:
diff changeset
67 print_stats("gc");
a61af66fc99e Initial load
duke
parents:
diff changeset
68 }
a61af66fc99e Initial load
duke
parents:
diff changeset
69
a61af66fc99e Initial load
duke
parents:
diff changeset
70 if (_number_of_refills > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
71
a61af66fc99e Initial load
duke
parents:
diff changeset
72 if (update_allocation_history) {
a61af66fc99e Initial load
duke
parents:
diff changeset
73 // Average the fraction of eden allocated in a tlab by this
a61af66fc99e Initial load
duke
parents:
diff changeset
74 // thread for use in the next resize operation.
a61af66fc99e Initial load
duke
parents:
diff changeset
75 // _gc_waste is not subtracted because it's included in
a61af66fc99e Initial load
duke
parents:
diff changeset
76 // "used".
a61af66fc99e Initial load
duke
parents:
diff changeset
77 size_t allocation = _number_of_refills * desired_size();
a61af66fc99e Initial load
duke
parents:
diff changeset
78 double alloc_frac = allocation / (double) used;
a61af66fc99e Initial load
duke
parents:
diff changeset
79 _allocation_fraction.sample(alloc_frac);
a61af66fc99e Initial load
duke
parents:
diff changeset
80 }
a61af66fc99e Initial load
duke
parents:
diff changeset
81 global_stats()->update_allocating_threads();
a61af66fc99e Initial load
duke
parents:
diff changeset
82 global_stats()->update_number_of_refills(_number_of_refills);
a61af66fc99e Initial load
duke
parents:
diff changeset
83 global_stats()->update_allocation(_number_of_refills * desired_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
84 global_stats()->update_gc_waste(_gc_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
85 global_stats()->update_slow_refill_waste(_slow_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
86 global_stats()->update_fast_refill_waste(_fast_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
87
a61af66fc99e Initial load
duke
parents:
diff changeset
88 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
89 assert(_number_of_refills == 0 && _fast_refill_waste == 0 &&
a61af66fc99e Initial load
duke
parents:
diff changeset
90 _slow_refill_waste == 0 && _gc_waste == 0,
a61af66fc99e Initial load
duke
parents:
diff changeset
91 "tlab stats == 0");
a61af66fc99e Initial load
duke
parents:
diff changeset
92 }
a61af66fc99e Initial load
duke
parents:
diff changeset
93 global_stats()->update_slow_allocations(_slow_allocations);
a61af66fc99e Initial load
duke
parents:
diff changeset
94 }
a61af66fc99e Initial load
duke
parents:
diff changeset
95
a61af66fc99e Initial load
duke
parents:
diff changeset
96 // Fills the current tlab with a dummy filler array to create
a61af66fc99e Initial load
duke
parents:
diff changeset
97 // an illusion of a contiguous Eden and optionally retires the tlab.
a61af66fc99e Initial load
duke
parents:
diff changeset
98 // Waste accounting should be done in caller as appropriate; see,
a61af66fc99e Initial load
duke
parents:
diff changeset
99 // for example, clear_before_allocation().
a61af66fc99e Initial load
duke
parents:
diff changeset
100 void ThreadLocalAllocBuffer::make_parsable(bool retire) {
a61af66fc99e Initial load
duke
parents:
diff changeset
101 if (end() != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
102 invariants();
a61af66fc99e Initial load
duke
parents:
diff changeset
103 MemRegion mr(top(), hard_end());
a61af66fc99e Initial load
duke
parents:
diff changeset
104 SharedHeap::fill_region_with_object(mr);
a61af66fc99e Initial load
duke
parents:
diff changeset
105
a61af66fc99e Initial load
duke
parents:
diff changeset
106 if (retire || ZeroTLAB) { // "Reset" the TLAB
a61af66fc99e Initial load
duke
parents:
diff changeset
107 set_start(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
108 set_top(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
109 set_pf_top(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
110 set_end(NULL);
a61af66fc99e Initial load
duke
parents:
diff changeset
111 }
a61af66fc99e Initial load
duke
parents:
diff changeset
112 }
a61af66fc99e Initial load
duke
parents:
diff changeset
113 assert(!(retire || ZeroTLAB) ||
a61af66fc99e Initial load
duke
parents:
diff changeset
114 (start() == NULL && end() == NULL && top() == NULL),
a61af66fc99e Initial load
duke
parents:
diff changeset
115 "TLAB must be reset");
a61af66fc99e Initial load
duke
parents:
diff changeset
116 }
a61af66fc99e Initial load
duke
parents:
diff changeset
117
a61af66fc99e Initial load
duke
parents:
diff changeset
118 void ThreadLocalAllocBuffer::resize_all_tlabs() {
a61af66fc99e Initial load
duke
parents:
diff changeset
119 for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
a61af66fc99e Initial load
duke
parents:
diff changeset
120 thread->tlab().resize();
a61af66fc99e Initial load
duke
parents:
diff changeset
121 }
a61af66fc99e Initial load
duke
parents:
diff changeset
122 }
a61af66fc99e Initial load
duke
parents:
diff changeset
123
a61af66fc99e Initial load
duke
parents:
diff changeset
124 void ThreadLocalAllocBuffer::resize() {
a61af66fc99e Initial load
duke
parents:
diff changeset
125
a61af66fc99e Initial load
duke
parents:
diff changeset
126 if (ResizeTLAB) {
a61af66fc99e Initial load
duke
parents:
diff changeset
127 // Compute the next tlab size using expected allocation amount
a61af66fc99e Initial load
duke
parents:
diff changeset
128 size_t alloc = (size_t)(_allocation_fraction.average() *
a61af66fc99e Initial load
duke
parents:
diff changeset
129 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize));
a61af66fc99e Initial load
duke
parents:
diff changeset
130 size_t new_size = alloc / _target_refills;
a61af66fc99e Initial load
duke
parents:
diff changeset
131
a61af66fc99e Initial load
duke
parents:
diff changeset
132 new_size = MIN2(MAX2(new_size, min_size()), max_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
133
a61af66fc99e Initial load
duke
parents:
diff changeset
134 size_t aligned_new_size = align_object_size(new_size);
a61af66fc99e Initial load
duke
parents:
diff changeset
135
a61af66fc99e Initial load
duke
parents:
diff changeset
136 if (PrintTLAB && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
137 gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]"
a61af66fc99e Initial load
duke
parents:
diff changeset
138 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n",
a61af66fc99e Initial load
duke
parents:
diff changeset
139 myThread(), myThread()->osthread()->thread_id(),
a61af66fc99e Initial load
duke
parents:
diff changeset
140 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size);
a61af66fc99e Initial load
duke
parents:
diff changeset
141 }
a61af66fc99e Initial load
duke
parents:
diff changeset
142 set_desired_size(aligned_new_size);
a61af66fc99e Initial load
duke
parents:
diff changeset
143
a61af66fc99e Initial load
duke
parents:
diff changeset
144 set_refill_waste_limit(initial_refill_waste_limit());
a61af66fc99e Initial load
duke
parents:
diff changeset
145 }
a61af66fc99e Initial load
duke
parents:
diff changeset
146 }
a61af66fc99e Initial load
duke
parents:
diff changeset
147
a61af66fc99e Initial load
duke
parents:
diff changeset
148 void ThreadLocalAllocBuffer::initialize_statistics() {
a61af66fc99e Initial load
duke
parents:
diff changeset
149 _number_of_refills = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
150 _fast_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
151 _slow_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
152 _gc_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
153 _slow_allocations = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
154 }
a61af66fc99e Initial load
duke
parents:
diff changeset
155
a61af66fc99e Initial load
duke
parents:
diff changeset
156 void ThreadLocalAllocBuffer::fill(HeapWord* start,
a61af66fc99e Initial load
duke
parents:
diff changeset
157 HeapWord* top,
a61af66fc99e Initial load
duke
parents:
diff changeset
158 size_t new_size) {
a61af66fc99e Initial load
duke
parents:
diff changeset
159 _number_of_refills++;
a61af66fc99e Initial load
duke
parents:
diff changeset
160 if (PrintTLAB && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
161 print_stats("fill");
a61af66fc99e Initial load
duke
parents:
diff changeset
162 }
a61af66fc99e Initial load
duke
parents:
diff changeset
163 assert(top <= start + new_size - alignment_reserve(), "size too small");
a61af66fc99e Initial load
duke
parents:
diff changeset
164 initialize(start, top, start + new_size - alignment_reserve());
a61af66fc99e Initial load
duke
parents:
diff changeset
165
a61af66fc99e Initial load
duke
parents:
diff changeset
166 // Reset amount of internal fragmentation
a61af66fc99e Initial load
duke
parents:
diff changeset
167 set_refill_waste_limit(initial_refill_waste_limit());
a61af66fc99e Initial load
duke
parents:
diff changeset
168 }
a61af66fc99e Initial load
duke
parents:
diff changeset
169
a61af66fc99e Initial load
duke
parents:
diff changeset
170 void ThreadLocalAllocBuffer::initialize(HeapWord* start,
a61af66fc99e Initial load
duke
parents:
diff changeset
171 HeapWord* top,
a61af66fc99e Initial load
duke
parents:
diff changeset
172 HeapWord* end) {
a61af66fc99e Initial load
duke
parents:
diff changeset
173 set_start(start);
a61af66fc99e Initial load
duke
parents:
diff changeset
174 set_top(top);
a61af66fc99e Initial load
duke
parents:
diff changeset
175 set_pf_top(top);
a61af66fc99e Initial load
duke
parents:
diff changeset
176 set_end(end);
a61af66fc99e Initial load
duke
parents:
diff changeset
177 invariants();
a61af66fc99e Initial load
duke
parents:
diff changeset
178 }
a61af66fc99e Initial load
duke
parents:
diff changeset
179
a61af66fc99e Initial load
duke
parents:
diff changeset
180 void ThreadLocalAllocBuffer::initialize() {
a61af66fc99e Initial load
duke
parents:
diff changeset
181 initialize(NULL, // start
a61af66fc99e Initial load
duke
parents:
diff changeset
182 NULL, // top
a61af66fc99e Initial load
duke
parents:
diff changeset
183 NULL); // end
a61af66fc99e Initial load
duke
parents:
diff changeset
184
a61af66fc99e Initial load
duke
parents:
diff changeset
185 set_desired_size(initial_desired_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
186
a61af66fc99e Initial load
duke
parents:
diff changeset
187 // Following check is needed because at startup the main (primordial)
a61af66fc99e Initial load
duke
parents:
diff changeset
188 // thread is initialized before the heap is. The initialization for
a61af66fc99e Initial load
duke
parents:
diff changeset
189 // this thread is redone in startup_initialization below.
a61af66fc99e Initial load
duke
parents:
diff changeset
190 if (Universe::heap() != NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
191 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize;
a61af66fc99e Initial load
duke
parents:
diff changeset
192 double alloc_frac = desired_size() * target_refills() / (double) capacity;
a61af66fc99e Initial load
duke
parents:
diff changeset
193 _allocation_fraction.sample(alloc_frac);
a61af66fc99e Initial load
duke
parents:
diff changeset
194 }
a61af66fc99e Initial load
duke
parents:
diff changeset
195
a61af66fc99e Initial load
duke
parents:
diff changeset
196 set_refill_waste_limit(initial_refill_waste_limit());
a61af66fc99e Initial load
duke
parents:
diff changeset
197
a61af66fc99e Initial load
duke
parents:
diff changeset
198 initialize_statistics();
a61af66fc99e Initial load
duke
parents:
diff changeset
199 }
a61af66fc99e Initial load
duke
parents:
diff changeset
200
a61af66fc99e Initial load
duke
parents:
diff changeset
201 void ThreadLocalAllocBuffer::startup_initialization() {
a61af66fc99e Initial load
duke
parents:
diff changeset
202
a61af66fc99e Initial load
duke
parents:
diff changeset
203 // Assuming each thread's active tlab is, on average,
a61af66fc99e Initial load
duke
parents:
diff changeset
204 // 1/2 full at a GC
a61af66fc99e Initial load
duke
parents:
diff changeset
205 _target_refills = 100 / (2 * TLABWasteTargetPercent);
a61af66fc99e Initial load
duke
parents:
diff changeset
206 _target_refills = MAX2(_target_refills, (unsigned)1U);
a61af66fc99e Initial load
duke
parents:
diff changeset
207
a61af66fc99e Initial load
duke
parents:
diff changeset
208 _global_stats = new GlobalTLABStats();
a61af66fc99e Initial load
duke
parents:
diff changeset
209
a61af66fc99e Initial load
duke
parents:
diff changeset
210 // During jvm startup, the main (primordial) thread is initialized
a61af66fc99e Initial load
duke
parents:
diff changeset
211 // before the heap is initialized. So reinitialize it now.
a61af66fc99e Initial load
duke
parents:
diff changeset
212 guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread");
a61af66fc99e Initial load
duke
parents:
diff changeset
213 Thread::current()->tlab().initialize();
a61af66fc99e Initial load
duke
parents:
diff changeset
214
a61af66fc99e Initial load
duke
parents:
diff changeset
215 if (PrintTLAB && Verbose) {
a61af66fc99e Initial load
duke
parents:
diff changeset
216 gclog_or_tty->print("TLAB min: " SIZE_FORMAT " initial: " SIZE_FORMAT " max: " SIZE_FORMAT "\n",
a61af66fc99e Initial load
duke
parents:
diff changeset
217 min_size(), Thread::current()->tlab().initial_desired_size(), max_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
218 }
a61af66fc99e Initial load
duke
parents:
diff changeset
219 }
a61af66fc99e Initial load
duke
parents:
diff changeset
220
a61af66fc99e Initial load
duke
parents:
diff changeset
221 size_t ThreadLocalAllocBuffer::initial_desired_size() {
a61af66fc99e Initial load
duke
parents:
diff changeset
222 size_t init_sz;
a61af66fc99e Initial load
duke
parents:
diff changeset
223
a61af66fc99e Initial load
duke
parents:
diff changeset
224 if (TLABSize > 0) {
a61af66fc99e Initial load
duke
parents:
diff changeset
225 init_sz = MIN2(TLABSize / HeapWordSize, max_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
226 } else if (global_stats() == NULL) {
a61af66fc99e Initial load
duke
parents:
diff changeset
227 // Startup issue - main thread initialized before heap initialized.
a61af66fc99e Initial load
duke
parents:
diff changeset
228 init_sz = min_size();
a61af66fc99e Initial load
duke
parents:
diff changeset
229 } else {
a61af66fc99e Initial load
duke
parents:
diff changeset
230 // Initial size is a function of the average number of allocating threads.
a61af66fc99e Initial load
duke
parents:
diff changeset
231 unsigned nof_threads = global_stats()->allocating_threads_avg();
a61af66fc99e Initial load
duke
parents:
diff changeset
232
a61af66fc99e Initial load
duke
parents:
diff changeset
233 init_sz = (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize) /
a61af66fc99e Initial load
duke
parents:
diff changeset
234 (nof_threads * target_refills());
a61af66fc99e Initial load
duke
parents:
diff changeset
235 init_sz = align_object_size(init_sz);
a61af66fc99e Initial load
duke
parents:
diff changeset
236 init_sz = MIN2(MAX2(init_sz, min_size()), max_size());
a61af66fc99e Initial load
duke
parents:
diff changeset
237 }
a61af66fc99e Initial load
duke
parents:
diff changeset
238 return init_sz;
a61af66fc99e Initial load
duke
parents:
diff changeset
239 }
a61af66fc99e Initial load
duke
parents:
diff changeset
240
a61af66fc99e Initial load
duke
parents:
diff changeset
241 const size_t ThreadLocalAllocBuffer::max_size() {
a61af66fc99e Initial load
duke
parents:
diff changeset
242
a61af66fc99e Initial load
duke
parents:
diff changeset
243 // TLABs can't be bigger than we can fill with a int[Integer.MAX_VALUE].
a61af66fc99e Initial load
duke
parents:
diff changeset
244 // This restriction could be removed by enabling filling with multiple arrays.
a61af66fc99e Initial load
duke
parents:
diff changeset
245 // If we compute that the reasonable way as
a61af66fc99e Initial load
duke
parents:
diff changeset
246 // header_size + ((sizeof(jint) * max_jint) / HeapWordSize)
a61af66fc99e Initial load
duke
parents:
diff changeset
247 // we'll overflow on the multiply, so we do the divide first.
a61af66fc99e Initial load
duke
parents:
diff changeset
248 // We actually lose a little by dividing first,
a61af66fc99e Initial load
duke
parents:
diff changeset
249 // but that just makes the TLAB somewhat smaller than the biggest array,
a61af66fc99e Initial load
duke
parents:
diff changeset
250 // which is fine, since we'll be able to fill that.
a61af66fc99e Initial load
duke
parents:
diff changeset
251
a61af66fc99e Initial load
duke
parents:
diff changeset
252 size_t unaligned_max_size = typeArrayOopDesc::header_size(T_INT) +
a61af66fc99e Initial load
duke
parents:
diff changeset
253 sizeof(jint) *
a61af66fc99e Initial load
duke
parents:
diff changeset
254 ((juint) max_jint / (size_t) HeapWordSize);
a61af66fc99e Initial load
duke
parents:
diff changeset
255 return align_size_down(unaligned_max_size, MinObjAlignment);
a61af66fc99e Initial load
duke
parents:
diff changeset
256 }
a61af66fc99e Initial load
duke
parents:
diff changeset
257
a61af66fc99e Initial load
duke
parents:
diff changeset
258 void ThreadLocalAllocBuffer::print_stats(const char* tag) {
a61af66fc99e Initial load
duke
parents:
diff changeset
259 Thread* thrd = myThread();
a61af66fc99e Initial load
duke
parents:
diff changeset
260 size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste;
a61af66fc99e Initial load
duke
parents:
diff changeset
261 size_t alloc = _number_of_refills * _desired_size;
a61af66fc99e Initial load
duke
parents:
diff changeset
262 double waste_percent = alloc == 0 ? 0.0 :
a61af66fc99e Initial load
duke
parents:
diff changeset
263 100.0 * waste / alloc;
a61af66fc99e Initial load
duke
parents:
diff changeset
264 size_t tlab_used = Universe::heap()->tlab_capacity(thrd) -
a61af66fc99e Initial load
duke
parents:
diff changeset
265 Universe::heap()->unsafe_max_tlab_alloc(thrd);
a61af66fc99e Initial load
duke
parents:
diff changeset
266 gclog_or_tty->print("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]"
a61af66fc99e Initial load
duke
parents:
diff changeset
267 " desired_size: " SIZE_FORMAT "KB"
a61af66fc99e Initial load
duke
parents:
diff changeset
268 " slow allocs: %d refill waste: " SIZE_FORMAT "B"
a61af66fc99e Initial load
duke
parents:
diff changeset
269 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB"
a61af66fc99e Initial load
duke
parents:
diff changeset
270 " slow: %dB fast: %dB\n",
a61af66fc99e Initial load
duke
parents:
diff changeset
271 tag, thrd, thrd->osthread()->thread_id(),
a61af66fc99e Initial load
duke
parents:
diff changeset
272 _desired_size / (K / HeapWordSize),
a61af66fc99e Initial load
duke
parents:
diff changeset
273 _slow_allocations, _refill_waste_limit * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
274 _allocation_fraction.average(),
a61af66fc99e Initial load
duke
parents:
diff changeset
275 _allocation_fraction.average() * tlab_used / K,
a61af66fc99e Initial load
duke
parents:
diff changeset
276 _number_of_refills, waste_percent,
a61af66fc99e Initial load
duke
parents:
diff changeset
277 _gc_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
278 _slow_refill_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
279 _fast_refill_waste * HeapWordSize);
a61af66fc99e Initial load
duke
parents:
diff changeset
280 }
a61af66fc99e Initial load
duke
parents:
diff changeset
281
a61af66fc99e Initial load
duke
parents:
diff changeset
282 void ThreadLocalAllocBuffer::verify() {
a61af66fc99e Initial load
duke
parents:
diff changeset
283 HeapWord* p = start();
a61af66fc99e Initial load
duke
parents:
diff changeset
284 HeapWord* t = top();
a61af66fc99e Initial load
duke
parents:
diff changeset
285 HeapWord* prev_p = NULL;
a61af66fc99e Initial load
duke
parents:
diff changeset
286 while (p < t) {
a61af66fc99e Initial load
duke
parents:
diff changeset
287 oop(p)->verify();
a61af66fc99e Initial load
duke
parents:
diff changeset
288 prev_p = p;
a61af66fc99e Initial load
duke
parents:
diff changeset
289 p += oop(p)->size();
a61af66fc99e Initial load
duke
parents:
diff changeset
290 }
a61af66fc99e Initial load
duke
parents:
diff changeset
291 guarantee(p == top(), "end of last object must match end of space");
a61af66fc99e Initial load
duke
parents:
diff changeset
292 }
a61af66fc99e Initial load
duke
parents:
diff changeset
293
a61af66fc99e Initial load
duke
parents:
diff changeset
294 Thread* ThreadLocalAllocBuffer::myThread() {
a61af66fc99e Initial load
duke
parents:
diff changeset
295 return (Thread*)(((char *)this) +
a61af66fc99e Initial load
duke
parents:
diff changeset
296 in_bytes(start_offset()) -
a61af66fc99e Initial load
duke
parents:
diff changeset
297 in_bytes(Thread::tlab_start_offset()));
a61af66fc99e Initial load
duke
parents:
diff changeset
298 }
a61af66fc99e Initial load
duke
parents:
diff changeset
299
a61af66fc99e Initial load
duke
parents:
diff changeset
300
a61af66fc99e Initial load
duke
parents:
diff changeset
301 GlobalTLABStats::GlobalTLABStats() :
a61af66fc99e Initial load
duke
parents:
diff changeset
302 _allocating_threads_avg(TLABAllocationWeight) {
a61af66fc99e Initial load
duke
parents:
diff changeset
303
a61af66fc99e Initial load
duke
parents:
diff changeset
304 initialize();
a61af66fc99e Initial load
duke
parents:
diff changeset
305
a61af66fc99e Initial load
duke
parents:
diff changeset
306 _allocating_threads_avg.sample(1); // One allocating thread at startup
a61af66fc99e Initial load
duke
parents:
diff changeset
307
a61af66fc99e Initial load
duke
parents:
diff changeset
308 if (UsePerfData) {
a61af66fc99e Initial load
duke
parents:
diff changeset
309
a61af66fc99e Initial load
duke
parents:
diff changeset
310 EXCEPTION_MARK;
a61af66fc99e Initial load
duke
parents:
diff changeset
311 ResourceMark rm;
a61af66fc99e Initial load
duke
parents:
diff changeset
312
a61af66fc99e Initial load
duke
parents:
diff changeset
313 char* cname = PerfDataManager::counter_name("tlab", "allocThreads");
a61af66fc99e Initial load
duke
parents:
diff changeset
314 _perf_allocating_threads =
a61af66fc99e Initial load
duke
parents:
diff changeset
315 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
316
a61af66fc99e Initial load
duke
parents:
diff changeset
317 cname = PerfDataManager::counter_name("tlab", "fills");
a61af66fc99e Initial load
duke
parents:
diff changeset
318 _perf_total_refills =
a61af66fc99e Initial load
duke
parents:
diff changeset
319 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
320
a61af66fc99e Initial load
duke
parents:
diff changeset
321 cname = PerfDataManager::counter_name("tlab", "maxFills");
a61af66fc99e Initial load
duke
parents:
diff changeset
322 _perf_max_refills =
a61af66fc99e Initial load
duke
parents:
diff changeset
323 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
324
a61af66fc99e Initial load
duke
parents:
diff changeset
325 cname = PerfDataManager::counter_name("tlab", "alloc");
a61af66fc99e Initial load
duke
parents:
diff changeset
326 _perf_allocation =
a61af66fc99e Initial load
duke
parents:
diff changeset
327 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
328
a61af66fc99e Initial load
duke
parents:
diff changeset
329 cname = PerfDataManager::counter_name("tlab", "gcWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
330 _perf_gc_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
331 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
332
a61af66fc99e Initial load
duke
parents:
diff changeset
333 cname = PerfDataManager::counter_name("tlab", "maxGcWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
334 _perf_max_gc_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
335 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
336
a61af66fc99e Initial load
duke
parents:
diff changeset
337 cname = PerfDataManager::counter_name("tlab", "slowWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
338 _perf_slow_refill_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
339 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
340
a61af66fc99e Initial load
duke
parents:
diff changeset
341 cname = PerfDataManager::counter_name("tlab", "maxSlowWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
342 _perf_max_slow_refill_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
343 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
344
a61af66fc99e Initial load
duke
parents:
diff changeset
345 cname = PerfDataManager::counter_name("tlab", "fastWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
346 _perf_fast_refill_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
347 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
348
a61af66fc99e Initial load
duke
parents:
diff changeset
349 cname = PerfDataManager::counter_name("tlab", "maxFastWaste");
a61af66fc99e Initial load
duke
parents:
diff changeset
350 _perf_max_fast_refill_waste =
a61af66fc99e Initial load
duke
parents:
diff changeset
351 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
352
a61af66fc99e Initial load
duke
parents:
diff changeset
353 cname = PerfDataManager::counter_name("tlab", "slowAlloc");
a61af66fc99e Initial load
duke
parents:
diff changeset
354 _perf_slow_allocations =
a61af66fc99e Initial load
duke
parents:
diff changeset
355 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
356
a61af66fc99e Initial load
duke
parents:
diff changeset
357 cname = PerfDataManager::counter_name("tlab", "maxSlowAlloc");
a61af66fc99e Initial load
duke
parents:
diff changeset
358 _perf_max_slow_allocations =
a61af66fc99e Initial load
duke
parents:
diff changeset
359 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
a61af66fc99e Initial load
duke
parents:
diff changeset
360 }
a61af66fc99e Initial load
duke
parents:
diff changeset
361 }
a61af66fc99e Initial load
duke
parents:
diff changeset
362
a61af66fc99e Initial load
duke
parents:
diff changeset
363 void GlobalTLABStats::initialize() {
a61af66fc99e Initial load
duke
parents:
diff changeset
364 // Clear counters summarizing info from all threads
a61af66fc99e Initial load
duke
parents:
diff changeset
365 _allocating_threads = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
366 _total_refills = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
367 _max_refills = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
368 _total_allocation = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
369 _total_gc_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
370 _max_gc_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
371 _total_slow_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
372 _max_slow_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
373 _total_fast_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
374 _max_fast_refill_waste = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
375 _total_slow_allocations = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
376 _max_slow_allocations = 0;
a61af66fc99e Initial load
duke
parents:
diff changeset
377 }
a61af66fc99e Initial load
duke
parents:
diff changeset
378
a61af66fc99e Initial load
duke
parents:
diff changeset
379 void GlobalTLABStats::publish() {
a61af66fc99e Initial load
duke
parents:
diff changeset
380 _allocating_threads_avg.sample(_allocating_threads);
a61af66fc99e Initial load
duke
parents:
diff changeset
381 if (UsePerfData) {
a61af66fc99e Initial load
duke
parents:
diff changeset
382 _perf_allocating_threads ->set_value(_allocating_threads);
a61af66fc99e Initial load
duke
parents:
diff changeset
383 _perf_total_refills ->set_value(_total_refills);
a61af66fc99e Initial load
duke
parents:
diff changeset
384 _perf_max_refills ->set_value(_max_refills);
a61af66fc99e Initial load
duke
parents:
diff changeset
385 _perf_allocation ->set_value(_total_allocation);
a61af66fc99e Initial load
duke
parents:
diff changeset
386 _perf_gc_waste ->set_value(_total_gc_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
387 _perf_max_gc_waste ->set_value(_max_gc_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
388 _perf_slow_refill_waste ->set_value(_total_slow_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
389 _perf_max_slow_refill_waste->set_value(_max_slow_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
390 _perf_fast_refill_waste ->set_value(_total_fast_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
391 _perf_max_fast_refill_waste->set_value(_max_fast_refill_waste);
a61af66fc99e Initial load
duke
parents:
diff changeset
392 _perf_slow_allocations ->set_value(_total_slow_allocations);
a61af66fc99e Initial load
duke
parents:
diff changeset
393 _perf_max_slow_allocations ->set_value(_max_slow_allocations);
a61af66fc99e Initial load
duke
parents:
diff changeset
394 }
a61af66fc99e Initial load
duke
parents:
diff changeset
395 }
a61af66fc99e Initial load
duke
parents:
diff changeset
396
a61af66fc99e Initial load
duke
parents:
diff changeset
397 void GlobalTLABStats::print() {
a61af66fc99e Initial load
duke
parents:
diff changeset
398 size_t waste = _total_gc_waste + _total_slow_refill_waste + _total_fast_refill_waste;
a61af66fc99e Initial load
duke
parents:
diff changeset
399 double waste_percent = _total_allocation == 0 ? 0.0 :
a61af66fc99e Initial load
duke
parents:
diff changeset
400 100.0 * waste / _total_allocation;
a61af66fc99e Initial load
duke
parents:
diff changeset
401 gclog_or_tty->print("TLAB totals: thrds: %d refills: %d max: %d"
a61af66fc99e Initial load
duke
parents:
diff changeset
402 " slow allocs: %d max %d waste: %4.1f%%"
a61af66fc99e Initial load
duke
parents:
diff changeset
403 " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B"
a61af66fc99e Initial load
duke
parents:
diff changeset
404 " slow: " SIZE_FORMAT "B max: " SIZE_FORMAT "B"
a61af66fc99e Initial load
duke
parents:
diff changeset
405 " fast: " SIZE_FORMAT "B max: " SIZE_FORMAT "B\n",
a61af66fc99e Initial load
duke
parents:
diff changeset
406 _allocating_threads,
a61af66fc99e Initial load
duke
parents:
diff changeset
407 _total_refills, _max_refills,
a61af66fc99e Initial load
duke
parents:
diff changeset
408 _total_slow_allocations, _max_slow_allocations,
a61af66fc99e Initial load
duke
parents:
diff changeset
409 waste_percent,
a61af66fc99e Initial load
duke
parents:
diff changeset
410 _total_gc_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
411 _max_gc_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
412 _total_slow_refill_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
413 _max_slow_refill_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
414 _total_fast_refill_waste * HeapWordSize,
a61af66fc99e Initial load
duke
parents:
diff changeset
415 _max_fast_refill_waste * HeapWordSize);
a61af66fc99e Initial load
duke
parents:
diff changeset
416 }