29 #include "memory/resourceArea.hpp"
30 #include "memory/universe.hpp"
31 #include "oops/oop.inline.hpp"
32 #include "runtime/thread.inline.hpp"
33 #include "runtime/threadSMR.hpp"
34 #include "utilities/copy.hpp"
35
36 // Thread-Local Edens support
37
38 // static member initialization
39 size_t ThreadLocalAllocBuffer::_max_size = 0;
40 int ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch = 0;
41 unsigned ThreadLocalAllocBuffer::_target_refills = 0;
42 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL;
43
44 void ThreadLocalAllocBuffer::clear_before_allocation() {
45 _slow_refill_waste += (unsigned)remaining();
46 make_parsable(true); // also retire the TLAB
47 }
48
49 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() {
50 global_stats()->initialize();
51
52 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
53 thread->tlab().accumulate_statistics();
54 thread->tlab().initialize_statistics();
55 }
56
57 // Publish new stats if some allocation occurred.
58 if (global_stats()->allocation() != 0) {
59 global_stats()->publish();
60 global_stats()->print();
61 }
62 }
63
64 void ThreadLocalAllocBuffer::accumulate_statistics() {
65 Thread* thread = myThread();
66 size_t capacity = Universe::heap()->tlab_capacity(thread);
67 size_t used = Universe::heap()->tlab_used(thread);
68
91 global_stats()->update_allocating_threads();
92 global_stats()->update_number_of_refills(_number_of_refills);
93 global_stats()->update_allocation(_number_of_refills * desired_size());
94 global_stats()->update_gc_waste(_gc_waste);
95 global_stats()->update_slow_refill_waste(_slow_refill_waste);
96 global_stats()->update_fast_refill_waste(_fast_refill_waste);
97
98 } else {
99 assert(_number_of_refills == 0 && _fast_refill_waste == 0 &&
100 _slow_refill_waste == 0 && _gc_waste == 0,
101 "tlab stats == 0");
102 }
103 global_stats()->update_slow_allocations(_slow_allocations);
104 }
105
106 // Fills the current tlab with a dummy filler array to create
107 // an illusion of a contiguous Eden and optionally retires the tlab.
108 // Waste accounting should be done in caller as appropriate; see,
109 // for example, clear_before_allocation().
110 void ThreadLocalAllocBuffer::make_parsable(bool retire, bool zap) {
111 if (end() != NULL) {
112 invariants();
113
114 if (retire) {
115 myThread()->incr_allocated_bytes(used_bytes());
116 }
117
118 CollectedHeap::fill_with_object(top(), hard_end(), retire && zap);
119
120 if (retire || ZeroTLAB) { // "Reset" the TLAB
121 set_start(NULL);
122 set_top(NULL);
123 set_pf_top(NULL);
124 set_end(NULL);
125 }
126 }
127 assert(!(retire || ZeroTLAB) ||
128 (start() == NULL && end() == NULL && top() == NULL),
129 "TLAB must be reset");
130 }
131
132 void ThreadLocalAllocBuffer::resize_all_tlabs() {
133 if (ResizeTLAB) {
134 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
135 thread->tlab().resize();
136 }
137 }
138 }
139
140 void ThreadLocalAllocBuffer::resize() {
141 // Compute the next tlab size using expected allocation amount
142 assert(ResizeTLAB, "Should not call this otherwise");
143 size_t alloc = (size_t)(_allocation_fraction.average() *
144 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize));
145 size_t new_size = alloc / _target_refills;
146
147 new_size = MIN2(MAX2(new_size, min_size()), max_size());
148
154 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size);
155
156 set_desired_size(aligned_new_size);
157 set_refill_waste_limit(initial_refill_waste_limit());
158 }
159
160 void ThreadLocalAllocBuffer::initialize_statistics() {
161 _number_of_refills = 0;
162 _fast_refill_waste = 0;
163 _slow_refill_waste = 0;
164 _gc_waste = 0;
165 _slow_allocations = 0;
166 }
167
168 void ThreadLocalAllocBuffer::fill(HeapWord* start,
169 HeapWord* top,
170 size_t new_size) {
171 _number_of_refills++;
172 print_stats("fill");
173 assert(top <= start + new_size - alignment_reserve(), "size too small");
174 initialize(start, top, start + new_size - alignment_reserve());
175
176 // Reset amount of internal fragmentation
177 set_refill_waste_limit(initial_refill_waste_limit());
178 }
179
180 void ThreadLocalAllocBuffer::initialize(HeapWord* start,
181 HeapWord* top,
182 HeapWord* end) {
183 set_start(start);
184 set_top(top);
185 set_pf_top(top);
186 set_end(end);
187 invariants();
188 }
189
190 void ThreadLocalAllocBuffer::initialize() {
191 initialize(NULL, // start
192 NULL, // top
193 NULL); // end
194
195 set_desired_size(initial_desired_size());
196
197 // Following check is needed because at startup the main
198 // thread is initialized before the heap is. The initialization for
199 // this thread is redone in startup_initialization below.
200 if (Universe::heap() != NULL) {
201 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize;
202 double alloc_frac = desired_size() * target_refills() / (double) capacity;
203 _allocation_fraction.sample(alloc_frac);
204 }
205
206 set_refill_waste_limit(initial_refill_waste_limit());
289 _allocation_fraction.average(),
290 _allocation_fraction.average() * tlab_used / K,
291 _number_of_refills, waste_percent,
292 _gc_waste * HeapWordSize,
293 _slow_refill_waste * HeapWordSize,
294 _fast_refill_waste * HeapWordSize);
295 }
296
297 void ThreadLocalAllocBuffer::verify() {
298 HeapWord* p = start();
299 HeapWord* t = top();
300 HeapWord* prev_p = NULL;
301 while (p < t) {
302 oop(p)->verify();
303 prev_p = p;
304 p += oop(p)->size();
305 }
306 guarantee(p == top(), "end of last object must match end of space");
307 }
308
309 Thread* ThreadLocalAllocBuffer::myThread() {
310 return (Thread*)(((char *)this) +
311 in_bytes(start_offset()) -
312 in_bytes(Thread::tlab_start_offset()));
313 }
314
315
316 GlobalTLABStats::GlobalTLABStats() :
317 _allocating_threads_avg(TLABAllocationWeight) {
318
319 initialize();
320
321 _allocating_threads_avg.sample(1); // One allocating thread at startup
322
323 if (UsePerfData) {
324
325 EXCEPTION_MARK;
326 ResourceMark rm;
327
328 char* cname = PerfDataManager::counter_name("tlab", "allocThreads");
329 _perf_allocating_threads =
330 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
331
332 cname = PerfDataManager::counter_name("tlab", "fills");
333 _perf_total_refills =
334 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
|
29 #include "memory/resourceArea.hpp"
30 #include "memory/universe.hpp"
31 #include "oops/oop.inline.hpp"
32 #include "runtime/thread.inline.hpp"
33 #include "runtime/threadSMR.hpp"
34 #include "utilities/copy.hpp"
35
36 // Thread-Local Edens support
37
38 // static member initialization
39 size_t ThreadLocalAllocBuffer::_max_size = 0;
40 int ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch = 0;
41 unsigned ThreadLocalAllocBuffer::_target_refills = 0;
42 GlobalTLABStats* ThreadLocalAllocBuffer::_global_stats = NULL;
43
44 void ThreadLocalAllocBuffer::clear_before_allocation() {
45 _slow_refill_waste += (unsigned)remaining();
46 make_parsable(true); // also retire the TLAB
47 }
48
49 size_t ThreadLocalAllocBuffer::remaining() {
50 if (current_end() == NULL) {
51 return 0;
52 }
53
54 return pointer_delta(reserved_end(), top());
55 }
56
57 void ThreadLocalAllocBuffer::accumulate_statistics_before_gc() {
58 global_stats()->initialize();
59
60 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
61 thread->tlab().accumulate_statistics();
62 thread->tlab().initialize_statistics();
63 }
64
65 // Publish new stats if some allocation occurred.
66 if (global_stats()->allocation() != 0) {
67 global_stats()->publish();
68 global_stats()->print();
69 }
70 }
71
72 void ThreadLocalAllocBuffer::accumulate_statistics() {
73 Thread* thread = myThread();
74 size_t capacity = Universe::heap()->tlab_capacity(thread);
75 size_t used = Universe::heap()->tlab_used(thread);
76
99 global_stats()->update_allocating_threads();
100 global_stats()->update_number_of_refills(_number_of_refills);
101 global_stats()->update_allocation(_number_of_refills * desired_size());
102 global_stats()->update_gc_waste(_gc_waste);
103 global_stats()->update_slow_refill_waste(_slow_refill_waste);
104 global_stats()->update_fast_refill_waste(_fast_refill_waste);
105
106 } else {
107 assert(_number_of_refills == 0 && _fast_refill_waste == 0 &&
108 _slow_refill_waste == 0 && _gc_waste == 0,
109 "tlab stats == 0");
110 }
111 global_stats()->update_slow_allocations(_slow_allocations);
112 }
113
114 // Fills the current tlab with a dummy filler array to create
115 // an illusion of a contiguous Eden and optionally retires the tlab.
116 // Waste accounting should be done in caller as appropriate; see,
117 // for example, clear_before_allocation().
118 void ThreadLocalAllocBuffer::make_parsable(bool retire, bool zap) {
119 if (current_end() != NULL) {
120 invariants();
121
122 if (retire) {
123 myThread()->incr_allocated_bytes(used_bytes());
124 }
125
126 CollectedHeap::fill_with_object(top(), reserved_end(), retire && zap);
127
128 if (retire || ZeroTLAB) { // "Reset" the TLAB
129 set_start(NULL);
130 set_top(NULL);
131 set_pf_top(NULL);
132 set_current_end(NULL);
133 set_allocation_end(NULL);
134 }
135 }
136 assert(!(retire || ZeroTLAB) ||
137 (start() == NULL && current_end() == NULL && top() == NULL &&
138 _allocation_end == NULL),
139 "TLAB must be reset");
140 }
141
142 void ThreadLocalAllocBuffer::resize_all_tlabs() {
143 if (ResizeTLAB) {
144 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thread = jtiwh.next(); ) {
145 thread->tlab().resize();
146 }
147 }
148 }
149
150 void ThreadLocalAllocBuffer::resize() {
151 // Compute the next tlab size using expected allocation amount
152 assert(ResizeTLAB, "Should not call this otherwise");
153 size_t alloc = (size_t)(_allocation_fraction.average() *
154 (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize));
155 size_t new_size = alloc / _target_refills;
156
157 new_size = MIN2(MAX2(new_size, min_size()), max_size());
158
164 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size);
165
166 set_desired_size(aligned_new_size);
167 set_refill_waste_limit(initial_refill_waste_limit());
168 }
169
170 void ThreadLocalAllocBuffer::initialize_statistics() {
171 _number_of_refills = 0;
172 _fast_refill_waste = 0;
173 _slow_refill_waste = 0;
174 _gc_waste = 0;
175 _slow_allocations = 0;
176 }
177
178 void ThreadLocalAllocBuffer::fill(HeapWord* start,
179 HeapWord* top,
180 size_t new_size) {
181 _number_of_refills++;
182 print_stats("fill");
183 assert(top <= start + new_size - alignment_reserve(), "size too small");
184
185 initialize(start, top, start + new_size - alignment_reserve());
186
187 if (ThreadHeapSampler::enabled()) {
188 set_sample_end();
189 }
190
191 // Reset amount of internal fragmentation
192 set_refill_waste_limit(initial_refill_waste_limit());
193 }
194
195 void ThreadLocalAllocBuffer::initialize(HeapWord* start,
196 HeapWord* top,
197 HeapWord* end) {
198 set_start(start);
199 set_top(top);
200 set_pf_top(top);
201 set_current_end(end);
202 set_allocation_end(end);
203 invariants();
204 }
205
206 void ThreadLocalAllocBuffer::initialize() {
207 initialize(NULL, // start
208 NULL, // top
209 NULL); // end
210
211 set_desired_size(initial_desired_size());
212
213 // Following check is needed because at startup the main
214 // thread is initialized before the heap is. The initialization for
215 // this thread is redone in startup_initialization below.
216 if (Universe::heap() != NULL) {
217 size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize;
218 double alloc_frac = desired_size() * target_refills() / (double) capacity;
219 _allocation_fraction.sample(alloc_frac);
220 }
221
222 set_refill_waste_limit(initial_refill_waste_limit());
305 _allocation_fraction.average(),
306 _allocation_fraction.average() * tlab_used / K,
307 _number_of_refills, waste_percent,
308 _gc_waste * HeapWordSize,
309 _slow_refill_waste * HeapWordSize,
310 _fast_refill_waste * HeapWordSize);
311 }
312
313 void ThreadLocalAllocBuffer::verify() {
314 HeapWord* p = start();
315 HeapWord* t = top();
316 HeapWord* prev_p = NULL;
317 while (p < t) {
318 oop(p)->verify();
319 prev_p = p;
320 p += oop(p)->size();
321 }
322 guarantee(p == top(), "end of last object must match end of space");
323 }
324
325 void ThreadLocalAllocBuffer::set_sample_end() {
326 size_t heap_words_remaining = pointer_delta(_current_end, _top);
327 size_t bytes_until_sample = myThread()->heap_sampler().bytes_until_sample();
328 size_t words_until_sample = bytes_until_sample / HeapWordSize;;
329
330 if (heap_words_remaining > words_until_sample) {
331 HeapWord* new_end = _top + words_until_sample;
332 set_current_end(new_end);
333 _bytes_since_last_sample_point = bytes_until_sample;
334 } else {
335 _bytes_since_last_sample_point = heap_words_remaining * HeapWordSize;;
336 }
337 }
338
339 Thread* ThreadLocalAllocBuffer::myThread() {
340 return (Thread*)(((char *)this) +
341 in_bytes(start_offset()) -
342 in_bytes(Thread::tlab_start_offset()));
343 }
344
345 void ThreadLocalAllocBuffer::set_back_allocation_end() {
346 _current_end = _allocation_end;
347 }
348
349 HeapWord* ThreadLocalAllocBuffer::allocate_sampled_object(size_t size) {
350 Thread* thread = myThread();
351 thread->tlab().set_back_allocation_end();
352 HeapWord* result = thread->tlab().allocate(size);
353
354 if (result) {
355 thread->heap_sampler().check_for_sampling(result, size * HeapWordSize, _bytes_since_last_sample_point);
356 thread->tlab().set_sample_end();
357 }
358
359 return result;
360 }
361
362 HeapWord* ThreadLocalAllocBuffer::reserved_end() {
363 return _allocation_end + alignment_reserve();
364 }
365
366 GlobalTLABStats::GlobalTLABStats() :
367 _allocating_threads_avg(TLABAllocationWeight) {
368
369 initialize();
370
371 _allocating_threads_avg.sample(1); // One allocating thread at startup
372
373 if (UsePerfData) {
374
375 EXCEPTION_MARK;
376 ResourceMark rm;
377
378 char* cname = PerfDataManager::counter_name("tlab", "allocThreads");
379 _perf_allocating_threads =
380 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
381
382 cname = PerfDataManager::counter_name("tlab", "fills");
383 _perf_total_refills =
384 PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_None, CHECK);
|