1 /*
2 * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
59
60 if (_number_of_refills > 0) {
61 // Update allocation history if a reasonable amount of eden was allocated.
62 bool update_allocation_history = used > 0.5 * capacity;
63
64 if (update_allocation_history) {
65 // Average the fraction of eden allocated in a tlab by this
66 // thread for use in the next resize operation.
67 // _gc_waste is not subtracted because it's included in
68 // "used".
69 // The result can be larger than 1.0 due to direct to old allocations.
70 // These allocations should ideally not be counted but since it is not possible
71 // to filter them out here we just cap the fraction to be at most 1.0.
72 double alloc_frac = MIN2(1.0, (double) allocated_since_last_gc / used);
73 _allocation_fraction.sample(alloc_frac);
74 }
75
76 stats->update_fast_allocations(_number_of_refills,
77 _allocated_size,
78 _gc_waste,
79 _fast_refill_waste,
80 _slow_refill_waste);
81 } else {
82 assert(_number_of_refills == 0 && _fast_refill_waste == 0 &&
83 _slow_refill_waste == 0 && _gc_waste == 0,
84 "tlab stats == 0");
85 }
86
87 stats->update_slow_allocations(_slow_allocations);
88
89 reset_statistics();
90 }
91
92 void ThreadLocalAllocBuffer::insert_filler() {
93 assert(end() != NULL, "Must not be retired");
94 if (top() < hard_end()) {
95 Universe::heap()->fill_with_dummy_object(top(), hard_end(), true);
96 }
97 }
98
99 void ThreadLocalAllocBuffer::make_parsable() {
100 if (end() != NULL) {
101 invariants();
102 if (ZeroTLAB) {
103 retire();
104 } else {
105 insert_filler();
106 }
107 }
108 }
109
110 void ThreadLocalAllocBuffer::retire(ThreadLocalAllocStats* stats) {
111 if (stats != NULL) {
112 accumulate_and_reset_statistics(stats);
113 }
114
115 if (end() != NULL) {
116 invariants();
117 thread()->incr_allocated_bytes(used_bytes());
118 insert_filler();
119 initialize(NULL, NULL, NULL);
120 }
121 }
122
123 void ThreadLocalAllocBuffer::retire_before_allocation() {
124 _slow_refill_waste += (unsigned int)remaining();
125 retire();
126 }
127
128 void ThreadLocalAllocBuffer::resize() {
129 // Compute the next tlab size using expected allocation amount
130 assert(ResizeTLAB, "Should not call this otherwise");
131 size_t alloc = (size_t)(_allocation_fraction.average() *
132 (Universe::heap()->tlab_capacity(thread()) / HeapWordSize));
133 size_t new_size = alloc / _target_refills;
134
135 new_size = MIN2(MAX2(new_size, min_size()), max_size());
136
137 size_t aligned_new_size = align_object_size(new_size);
138
139 log_trace(gc, tlab)("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]"
140 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT,
141 p2i(thread()), thread()->osthread()->thread_id(),
142 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size);
143
144 set_desired_size(aligned_new_size);
145 set_refill_waste_limit(initial_refill_waste_limit());
146 }
147
148 void ThreadLocalAllocBuffer::reset_statistics() {
149 _number_of_refills = 0;
150 _fast_refill_waste = 0;
151 _slow_refill_waste = 0;
152 _gc_waste = 0;
153 _slow_allocations = 0;
154 _allocated_size = 0;
155 }
156
157 void ThreadLocalAllocBuffer::fill(HeapWord* start,
158 HeapWord* top,
159 size_t new_size) {
160 _number_of_refills++;
161 _allocated_size += new_size;
162 print_stats("fill");
163 assert(top <= start + new_size - alignment_reserve(), "size too small");
164
165 initialize(start, top, start + new_size - alignment_reserve());
166
167 // Reset amount of internal fragmentation
168 set_refill_waste_limit(initial_refill_waste_limit());
169 }
170
171 void ThreadLocalAllocBuffer::initialize(HeapWord* start,
245 init_sz = TLABSize / HeapWordSize;
246 } else {
247 // Initial size is a function of the average number of allocating threads.
248 unsigned int nof_threads = ThreadLocalAllocStats::allocating_threads_avg();
249
250 init_sz = (Universe::heap()->tlab_capacity(thread()) / HeapWordSize) /
251 (nof_threads * target_refills());
252 init_sz = align_object_size(init_sz);
253 }
254 init_sz = MIN2(MAX2(init_sz, min_size()), max_size());
255 return init_sz;
256 }
257
258 void ThreadLocalAllocBuffer::print_stats(const char* tag) {
259 Log(gc, tlab) log;
260 if (!log.is_trace()) {
261 return;
262 }
263
264 Thread* thrd = thread();
265 size_t waste = _gc_waste + _slow_refill_waste + _fast_refill_waste;
266 double waste_percent = percent_of(waste, _allocated_size);
267 size_t tlab_used = Universe::heap()->tlab_used(thrd);
268 log.trace("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]"
269 " desired_size: " SIZE_FORMAT "KB"
270 " slow allocs: %d refill waste: " SIZE_FORMAT "B"
271 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB"
272 " slow: %dB fast: %dB",
273 tag, p2i(thrd), thrd->osthread()->thread_id(),
274 _desired_size / (K / HeapWordSize),
275 _slow_allocations, _refill_waste_limit * HeapWordSize,
276 _allocation_fraction.average(),
277 _allocation_fraction.average() * tlab_used / K,
278 _number_of_refills, waste_percent,
279 _gc_waste * HeapWordSize,
280 _slow_refill_waste * HeapWordSize,
281 _fast_refill_waste * HeapWordSize);
282 }
283
284 void ThreadLocalAllocBuffer::set_sample_end() {
285 size_t heap_words_remaining = pointer_delta(_end, _top);
286 size_t bytes_until_sample = thread()->heap_sampler().bytes_until_sample();
287 size_t words_until_sample = bytes_until_sample / HeapWordSize;
288
289 if (heap_words_remaining > words_until_sample) {
290 HeapWord* new_end = _top + words_until_sample;
291 set_end(new_end);
292 _bytes_since_last_sample_point = bytes_until_sample;
293 } else {
294 _bytes_since_last_sample_point = heap_words_remaining * HeapWordSize;
295 }
296 }
297
298 Thread* ThreadLocalAllocBuffer::thread() {
299 return (Thread*)(((char*)this) + in_bytes(start_offset()) - in_bytes(Thread::tlab_start_offset()));
300 }
301
302 void ThreadLocalAllocBuffer::set_back_allocation_end() {
303 _end = _allocation_end;
304 }
305
306 HeapWord* ThreadLocalAllocBuffer::hard_end() {
307 return _allocation_end + alignment_reserve();
308 }
309
310 PerfVariable* ThreadLocalAllocStats::_perf_allocating_threads;
311 PerfVariable* ThreadLocalAllocStats::_perf_total_refills;
312 PerfVariable* ThreadLocalAllocStats::_perf_max_refills;
313 PerfVariable* ThreadLocalAllocStats::_perf_total_allocations;
314 PerfVariable* ThreadLocalAllocStats::_perf_total_gc_waste;
315 PerfVariable* ThreadLocalAllocStats::_perf_max_gc_waste;
316 PerfVariable* ThreadLocalAllocStats::_perf_total_slow_refill_waste;
317 PerfVariable* ThreadLocalAllocStats::_perf_max_slow_refill_waste;
318 PerfVariable* ThreadLocalAllocStats::_perf_total_fast_refill_waste;
319 PerfVariable* ThreadLocalAllocStats::_perf_max_fast_refill_waste;
320 PerfVariable* ThreadLocalAllocStats::_perf_total_slow_allocations;
321 PerfVariable* ThreadLocalAllocStats::_perf_max_slow_allocations;
322 AdaptiveWeightedAverage ThreadLocalAllocStats::_allocating_threads_avg(0);
323
324 static PerfVariable* create_perf_variable(const char* name, PerfData::Units unit, TRAPS) {
325 ResourceMark rm;
326 return PerfDataManager::create_variable(SUN_GC, PerfDataManager::counter_name("tlab", name), unit, THREAD);
327 }
328
329 void ThreadLocalAllocStats::initialize() {
330 _allocating_threads_avg = AdaptiveWeightedAverage(TLABAllocationWeight);
331 _allocating_threads_avg.sample(1); // One allocating thread at startup
332
333 if (UsePerfData) {
334 EXCEPTION_MARK;
335 _perf_allocating_threads = create_perf_variable("allocThreads", PerfData::U_None, CHECK);
336 _perf_total_refills = create_perf_variable("fills", PerfData::U_None, CHECK);
337 _perf_max_refills = create_perf_variable("maxFills", PerfData::U_None, CHECK);
338 _perf_total_allocations = create_perf_variable("alloc", PerfData::U_Bytes, CHECK);
339 _perf_total_gc_waste = create_perf_variable("gcWaste", PerfData::U_Bytes, CHECK);
340 _perf_max_gc_waste = create_perf_variable("maxGcWaste", PerfData::U_Bytes, CHECK);
341 _perf_total_slow_refill_waste = create_perf_variable("slowWaste", PerfData::U_Bytes, CHECK);
342 _perf_max_slow_refill_waste = create_perf_variable("maxSlowWaste", PerfData::U_Bytes, CHECK);
343 _perf_total_fast_refill_waste = create_perf_variable("fastWaste", PerfData::U_Bytes, CHECK);
344 _perf_max_fast_refill_waste = create_perf_variable("maxFastWaste", PerfData::U_Bytes, CHECK);
345 _perf_total_slow_allocations = create_perf_variable("slowAlloc", PerfData::U_None, CHECK);
346 _perf_max_slow_allocations = create_perf_variable("maxSlowAlloc", PerfData::U_None, CHECK);
347 }
348 }
349
350 ThreadLocalAllocStats::ThreadLocalAllocStats() :
351 _allocating_threads(0),
352 _total_refills(0),
353 _max_refills(0),
354 _total_allocations(0),
355 _total_gc_waste(0),
356 _max_gc_waste(0),
357 _total_fast_refill_waste(0),
358 _max_fast_refill_waste(0),
359 _total_slow_refill_waste(0),
360 _max_slow_refill_waste(0),
361 _total_slow_allocations(0),
362 _max_slow_allocations(0) {}
363
364 unsigned int ThreadLocalAllocStats::allocating_threads_avg() {
365 return MAX2((unsigned int)(_allocating_threads_avg.average() + 0.5), 1U);
366 }
367
368 void ThreadLocalAllocStats::update_fast_allocations(unsigned int refills,
369 size_t allocations,
370 size_t gc_waste,
371 size_t fast_refill_waste,
372 size_t slow_refill_waste) {
373 _allocating_threads += 1;
374 _total_refills += refills;
375 _max_refills = MAX2(_max_refills, refills);
376 _total_allocations += allocations;
377 _total_gc_waste += gc_waste;
378 _max_gc_waste = MAX2(_max_gc_waste, gc_waste);
379 _total_fast_refill_waste += fast_refill_waste;
380 _max_fast_refill_waste = MAX2(_max_fast_refill_waste, fast_refill_waste);
381 _total_slow_refill_waste += slow_refill_waste;
382 _max_slow_refill_waste = MAX2(_max_slow_refill_waste, slow_refill_waste);
383 }
384
385 void ThreadLocalAllocStats::update_slow_allocations(unsigned int allocations) {
386 _total_slow_allocations += allocations;
387 _max_slow_allocations = MAX2(_max_slow_allocations, allocations);
388 }
389
390 void ThreadLocalAllocStats::update(const ThreadLocalAllocStats& other) {
391 _allocating_threads += other._allocating_threads;
392 _total_refills += other._total_refills;
393 _max_refills = MAX2(_max_refills, other._max_refills);
394 _total_allocations += other._total_allocations;
395 _total_gc_waste += other._total_gc_waste;
396 _max_gc_waste = MAX2(_max_gc_waste, other._max_gc_waste);
397 _total_fast_refill_waste += other._total_fast_refill_waste;
398 _max_fast_refill_waste = MAX2(_max_fast_refill_waste, other._max_fast_refill_waste);
399 _total_slow_refill_waste += other._total_slow_refill_waste;
400 _max_slow_refill_waste = MAX2(_max_slow_refill_waste, other._max_slow_refill_waste);
401 _total_slow_allocations += other._total_slow_allocations;
402 _max_slow_allocations = MAX2(_max_slow_allocations, other._max_slow_allocations);
403 }
404
405 void ThreadLocalAllocStats::reset() {
406 _allocating_threads = 0;
407 _total_refills = 0;
408 _max_refills = 0;
409 _total_allocations = 0;
410 _total_gc_waste = 0;
411 _max_gc_waste = 0;
412 _total_fast_refill_waste = 0;
413 _max_fast_refill_waste = 0;
414 _total_slow_refill_waste = 0;
415 _max_slow_refill_waste = 0;
416 _total_slow_allocations = 0;
417 _max_slow_allocations = 0;
418 }
419
420 void ThreadLocalAllocStats::publish() {
421 if (_total_allocations == 0) {
422 return;
423 }
424
425 _allocating_threads_avg.sample(_allocating_threads);
426
427 const size_t waste = _total_gc_waste + _total_slow_refill_waste + _total_fast_refill_waste;
428 const double waste_percent = percent_of(waste, _total_allocations);
429 log_debug(gc, tlab)("TLAB totals: thrds: %d refills: %d max: %d"
430 " slow allocs: %d max %d waste: %4.1f%%"
431 " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B"
432 " slow: " SIZE_FORMAT "B max: " SIZE_FORMAT "B"
433 " fast: " SIZE_FORMAT "B max: " SIZE_FORMAT "B",
434 _allocating_threads, _total_refills, _max_refills,
435 _total_slow_allocations, _max_slow_allocations, waste_percent,
436 _total_gc_waste * HeapWordSize, _max_gc_waste * HeapWordSize,
437 _total_slow_refill_waste * HeapWordSize, _max_slow_refill_waste * HeapWordSize,
438 _total_fast_refill_waste * HeapWordSize, _max_fast_refill_waste * HeapWordSize);
439
440 if (UsePerfData) {
441 _perf_allocating_threads ->set_value(_allocating_threads);
442 _perf_total_refills ->set_value(_total_refills);
443 _perf_max_refills ->set_value(_max_refills);
444 _perf_total_allocations ->set_value(_total_allocations);
445 _perf_total_gc_waste ->set_value(_total_gc_waste);
446 _perf_max_gc_waste ->set_value(_max_gc_waste);
447 _perf_total_slow_refill_waste ->set_value(_total_slow_refill_waste);
448 _perf_max_slow_refill_waste ->set_value(_max_slow_refill_waste);
449 _perf_total_fast_refill_waste ->set_value(_total_fast_refill_waste);
450 _perf_max_fast_refill_waste ->set_value(_max_fast_refill_waste);
451 _perf_total_slow_allocations ->set_value(_total_slow_allocations);
452 _perf_max_slow_allocations ->set_value(_max_slow_allocations);
453 }
454 }
455
456 size_t ThreadLocalAllocBuffer::end_reserve() {
457 size_t reserve_size = Universe::heap()->tlab_alloc_reserve();
458 return MAX2(reserve_size, (size_t)_reserve_for_allocation_prefetch);
459 }
|
1 /*
2 * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
59
60 if (_number_of_refills > 0) {
61 // Update allocation history if a reasonable amount of eden was allocated.
62 bool update_allocation_history = used > 0.5 * capacity;
63
64 if (update_allocation_history) {
65 // Average the fraction of eden allocated in a tlab by this
66 // thread for use in the next resize operation.
67 // _gc_waste is not subtracted because it's included in
68 // "used".
69 // The result can be larger than 1.0 due to direct to old allocations.
70 // These allocations should ideally not be counted but since it is not possible
71 // to filter them out here we just cap the fraction to be at most 1.0.
72 double alloc_frac = MIN2(1.0, (double) allocated_since_last_gc / used);
73 _allocation_fraction.sample(alloc_frac);
74 }
75
76 stats->update_fast_allocations(_number_of_refills,
77 _allocated_size,
78 _gc_waste,
79 _refill_waste);
80 } else {
81 assert(_number_of_refills == 0 && _refill_waste == 0 && _gc_waste == 0,
82 "tlab stats == 0");
83 }
84
85 stats->update_slow_allocations(_slow_allocations);
86
87 reset_statistics();
88 }
89
90 void ThreadLocalAllocBuffer::insert_filler() {
91 assert(end() != NULL, "Must not be retired");
92 if (top() < hard_end()) {
93 Universe::heap()->fill_with_dummy_object(top(), hard_end(), true);
94 }
95 }
96
97 void ThreadLocalAllocBuffer::make_parsable() {
98 if (end() != NULL) {
99 invariants();
100 if (ZeroTLAB) {
101 retire();
102 } else {
103 insert_filler();
104 }
105 }
106 }
107
108 void ThreadLocalAllocBuffer::retire(ThreadLocalAllocStats* stats) {
109 if (stats != NULL) {
110 accumulate_and_reset_statistics(stats);
111 }
112
113 if (end() != NULL) {
114 invariants();
115 thread()->incr_allocated_bytes(used_bytes());
116 insert_filler();
117 initialize(NULL, NULL, NULL);
118 }
119 }
120
121 void ThreadLocalAllocBuffer::retire_before_allocation() {
122 _refill_waste += (unsigned int)remaining();
123 retire();
124 }
125
126 void ThreadLocalAllocBuffer::resize() {
127 // Compute the next tlab size using expected allocation amount
128 assert(ResizeTLAB, "Should not call this otherwise");
129 size_t alloc = (size_t)(_allocation_fraction.average() *
130 (Universe::heap()->tlab_capacity(thread()) / HeapWordSize));
131 size_t new_size = alloc / _target_refills;
132
133 new_size = MIN2(MAX2(new_size, min_size()), max_size());
134
135 size_t aligned_new_size = align_object_size(new_size);
136
137 log_trace(gc, tlab)("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]"
138 " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT,
139 p2i(thread()), thread()->osthread()->thread_id(),
140 _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size);
141
142 set_desired_size(aligned_new_size);
143 set_refill_waste_limit(initial_refill_waste_limit());
144 }
145
146 void ThreadLocalAllocBuffer::reset_statistics() {
147 _number_of_refills = 0;
148 _refill_waste = 0;
149 _gc_waste = 0;
150 _slow_allocations = 0;
151 _allocated_size = 0;
152 }
153
154 void ThreadLocalAllocBuffer::fill(HeapWord* start,
155 HeapWord* top,
156 size_t new_size) {
157 _number_of_refills++;
158 _allocated_size += new_size;
159 print_stats("fill");
160 assert(top <= start + new_size - alignment_reserve(), "size too small");
161
162 initialize(start, top, start + new_size - alignment_reserve());
163
164 // Reset amount of internal fragmentation
165 set_refill_waste_limit(initial_refill_waste_limit());
166 }
167
168 void ThreadLocalAllocBuffer::initialize(HeapWord* start,
242 init_sz = TLABSize / HeapWordSize;
243 } else {
244 // Initial size is a function of the average number of allocating threads.
245 unsigned int nof_threads = ThreadLocalAllocStats::allocating_threads_avg();
246
247 init_sz = (Universe::heap()->tlab_capacity(thread()) / HeapWordSize) /
248 (nof_threads * target_refills());
249 init_sz = align_object_size(init_sz);
250 }
251 init_sz = MIN2(MAX2(init_sz, min_size()), max_size());
252 return init_sz;
253 }
254
255 void ThreadLocalAllocBuffer::print_stats(const char* tag) {
256 Log(gc, tlab) log;
257 if (!log.is_trace()) {
258 return;
259 }
260
261 Thread* thrd = thread();
262 size_t waste = _gc_waste + _refill_waste;
263 double waste_percent = percent_of(waste, _allocated_size);
264 size_t tlab_used = Universe::heap()->tlab_used(thrd);
265 log.trace("TLAB: %s thread: " INTPTR_FORMAT " [id: %2d]"
266 " desired_size: " SIZE_FORMAT "KB"
267 " slow allocs: %d refill waste: " SIZE_FORMAT "B"
268 " alloc:%8.5f %8.0fKB refills: %d waste %4.1f%% gc: %dB"
269 " refill: %dB",
270 tag, p2i(thrd), thrd->osthread()->thread_id(),
271 _desired_size / (K / HeapWordSize),
272 _slow_allocations, _refill_waste_limit * HeapWordSize,
273 _allocation_fraction.average(),
274 _allocation_fraction.average() * tlab_used / K,
275 _number_of_refills, waste_percent,
276 _gc_waste * HeapWordSize,
277 _refill_waste * HeapWordSize);
278 }
279
280 void ThreadLocalAllocBuffer::set_sample_end() {
281 size_t heap_words_remaining = pointer_delta(_end, _top);
282 size_t bytes_until_sample = thread()->heap_sampler().bytes_until_sample();
283 size_t words_until_sample = bytes_until_sample / HeapWordSize;
284
285 if (heap_words_remaining > words_until_sample) {
286 HeapWord* new_end = _top + words_until_sample;
287 set_end(new_end);
288 _bytes_since_last_sample_point = bytes_until_sample;
289 } else {
290 _bytes_since_last_sample_point = heap_words_remaining * HeapWordSize;
291 }
292 }
293
294 Thread* ThreadLocalAllocBuffer::thread() {
295 return (Thread*)(((char*)this) + in_bytes(start_offset()) - in_bytes(Thread::tlab_start_offset()));
296 }
297
298 void ThreadLocalAllocBuffer::set_back_allocation_end() {
299 _end = _allocation_end;
300 }
301
302 HeapWord* ThreadLocalAllocBuffer::hard_end() {
303 return _allocation_end + alignment_reserve();
304 }
305
306 PerfVariable* ThreadLocalAllocStats::_perf_allocating_threads;
307 PerfVariable* ThreadLocalAllocStats::_perf_total_refills;
308 PerfVariable* ThreadLocalAllocStats::_perf_max_refills;
309 PerfVariable* ThreadLocalAllocStats::_perf_total_allocations;
310 PerfVariable* ThreadLocalAllocStats::_perf_total_gc_waste;
311 PerfVariable* ThreadLocalAllocStats::_perf_max_gc_waste;
312 PerfVariable* ThreadLocalAllocStats::_perf_total_refill_waste;
313 PerfVariable* ThreadLocalAllocStats::_perf_max_refill_waste;
314 PerfVariable* ThreadLocalAllocStats::_perf_total_slow_allocations;
315 PerfVariable* ThreadLocalAllocStats::_perf_max_slow_allocations;
316 AdaptiveWeightedAverage ThreadLocalAllocStats::_allocating_threads_avg(0);
317
318 static PerfVariable* create_perf_variable(const char* name, PerfData::Units unit, TRAPS) {
319 ResourceMark rm;
320 return PerfDataManager::create_variable(SUN_GC, PerfDataManager::counter_name("tlab", name), unit, THREAD);
321 }
322
323 void ThreadLocalAllocStats::initialize() {
324 _allocating_threads_avg = AdaptiveWeightedAverage(TLABAllocationWeight);
325 _allocating_threads_avg.sample(1); // One allocating thread at startup
326
327 if (UsePerfData) {
328 EXCEPTION_MARK;
329 _perf_allocating_threads = create_perf_variable("allocThreads", PerfData::U_None, CHECK);
330 _perf_total_refills = create_perf_variable("fills", PerfData::U_None, CHECK);
331 _perf_max_refills = create_perf_variable("maxFills", PerfData::U_None, CHECK);
332 _perf_total_allocations = create_perf_variable("alloc", PerfData::U_Bytes, CHECK);
333 _perf_total_gc_waste = create_perf_variable("gcWaste", PerfData::U_Bytes, CHECK);
334 _perf_max_gc_waste = create_perf_variable("maxGcWaste", PerfData::U_Bytes, CHECK);
335 _perf_total_refill_waste = create_perf_variable("refillWaste", PerfData::U_Bytes, CHECK);
336 _perf_max_refill_waste = create_perf_variable("maxRefillWaste", PerfData::U_Bytes, CHECK);
337 _perf_total_slow_allocations = create_perf_variable("slowAlloc", PerfData::U_None, CHECK);
338 _perf_max_slow_allocations = create_perf_variable("maxSlowAlloc", PerfData::U_None, CHECK);
339 }
340 }
341
342 ThreadLocalAllocStats::ThreadLocalAllocStats() :
343 _allocating_threads(0),
344 _total_refills(0),
345 _max_refills(0),
346 _total_allocations(0),
347 _total_gc_waste(0),
348 _max_gc_waste(0),
349 _total_refill_waste(0),
350 _max_refill_waste(0),
351 _total_slow_allocations(0),
352 _max_slow_allocations(0) {}
353
354 unsigned int ThreadLocalAllocStats::allocating_threads_avg() {
355 return MAX2((unsigned int)(_allocating_threads_avg.average() + 0.5), 1U);
356 }
357
358 void ThreadLocalAllocStats::update_fast_allocations(unsigned int refills,
359 size_t allocations,
360 size_t gc_waste,
361 size_t refill_waste) {
362 _allocating_threads += 1;
363 _total_refills += refills;
364 _max_refills = MAX2(_max_refills, refills);
365 _total_allocations += allocations;
366 _total_gc_waste += gc_waste;
367 _max_gc_waste = MAX2(_max_gc_waste, gc_waste);
368 _total_refill_waste += refill_waste;
369 _max_refill_waste = MAX2(_max_refill_waste, refill_waste);
370 }
371
372 void ThreadLocalAllocStats::update_slow_allocations(unsigned int allocations) {
373 _total_slow_allocations += allocations;
374 _max_slow_allocations = MAX2(_max_slow_allocations, allocations);
375 }
376
377 void ThreadLocalAllocStats::update(const ThreadLocalAllocStats& other) {
378 _allocating_threads += other._allocating_threads;
379 _total_refills += other._total_refills;
380 _max_refills = MAX2(_max_refills, other._max_refills);
381 _total_allocations += other._total_allocations;
382 _total_gc_waste += other._total_gc_waste;
383 _max_gc_waste = MAX2(_max_gc_waste, other._max_gc_waste);
384 _total_refill_waste += other._total_refill_waste;
385 _max_refill_waste = MAX2(_max_refill_waste, other._max_refill_waste);
386 _total_slow_allocations += other._total_slow_allocations;
387 _max_slow_allocations = MAX2(_max_slow_allocations, other._max_slow_allocations);
388 }
389
390 void ThreadLocalAllocStats::reset() {
391 _allocating_threads = 0;
392 _total_refills = 0;
393 _max_refills = 0;
394 _total_allocations = 0;
395 _total_gc_waste = 0;
396 _max_gc_waste = 0;
397 _total_refill_waste = 0;
398 _max_refill_waste = 0;
399 _total_slow_allocations = 0;
400 _max_slow_allocations = 0;
401 }
402
403 void ThreadLocalAllocStats::publish() {
404 if (_total_allocations == 0) {
405 return;
406 }
407
408 _allocating_threads_avg.sample(_allocating_threads);
409
410 const size_t waste = _total_gc_waste + _total_refill_waste;
411 const double waste_percent = percent_of(waste, _total_allocations);
412 log_debug(gc, tlab)("TLAB totals: thrds: %d refills: %d max: %d"
413 " slow allocs: %d max %d waste: %4.1f%%"
414 " gc: " SIZE_FORMAT "B max: " SIZE_FORMAT "B"
415 " refill: " SIZE_FORMAT "B max: " SIZE_FORMAT "B",
416 _allocating_threads, _total_refills, _max_refills,
417 _total_slow_allocations, _max_slow_allocations, waste_percent,
418 _total_gc_waste * HeapWordSize, _max_gc_waste * HeapWordSize,
419 _total_refill_waste * HeapWordSize, _max_refill_waste * HeapWordSize);
420
421 if (UsePerfData) {
422 _perf_allocating_threads ->set_value(_allocating_threads);
423 _perf_total_refills ->set_value(_total_refills);
424 _perf_max_refills ->set_value(_max_refills);
425 _perf_total_allocations ->set_value(_total_allocations);
426 _perf_total_gc_waste ->set_value(_total_gc_waste);
427 _perf_max_gc_waste ->set_value(_max_gc_waste);
428 _perf_total_refill_waste ->set_value(_total_refill_waste);
429 _perf_max_refill_waste ->set_value(_max_refill_waste);
430 _perf_total_slow_allocations ->set_value(_total_slow_allocations);
431 _perf_max_slow_allocations ->set_value(_max_slow_allocations);
432 }
433 }
434
435 size_t ThreadLocalAllocBuffer::end_reserve() {
436 size_t reserve_size = Universe::heap()->tlab_alloc_reserve();
437 return MAX2(reserve_size, (size_t)_reserve_for_allocation_prefetch);
438 }
|