Skip to content

Commit c3e9f4f

Browse files
committed
WIP
1 parent c306677 commit c3e9f4f

11 files changed

+196
-45
lines changed

src/hotspot/share/gc/shared/allocTracer.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#endif
3333

3434
void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, JavaThread* thread) {
35-
JFR_ONLY(JfrAllocationTracer tracer(klass, obj, alloc_size, true, thread);)
3635
EventObjectAllocationOutsideTLAB event;
3736
if (event.should_commit()) {
3837
event.set_objectClass(klass);
@@ -42,7 +41,6 @@ void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size
4241
}
4342

4443
void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, JavaThread* thread) {
45-
JFR_ONLY(JfrAllocationTracer tracer(klass, obj, alloc_size, false, thread);)
4644
EventObjectAllocationInNewTLAB event;
4745
if (event.should_commit()) {
4846
event.set_objectClass(klass);
@@ -52,6 +50,10 @@ void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_
5250
}
5351
}
5452

53+
void AllocTracer::send_allocation_sample(Klass* klass, HeapWord* obj, size_t alloc_size, size_t weight, bool large_allocation, JavaThread* thread) {
54+
JFR_ONLY(JfrAllocationTracer tracer(klass, obj, alloc_size, large_allocation, thread);)
55+
}
56+
5557
void AllocTracer::send_allocation_requiring_gc_event(size_t size, uint gcId) {
5658
EventAllocationRequiringGC event;
5759
if (event.should_commit()) {

src/hotspot/share/gc/shared/allocTracer.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class AllocTracer : AllStatic {
3232
public:
3333
static void send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, JavaThread* thread);
3434
static void send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, JavaThread* thread);
35+
static void send_allocation_sample(Klass* klass, HeapWord* obj, size_t alloc_size, size_t weight, bool large_allocation, JavaThread* thread);
3536
static void send_allocation_requiring_gc_event(size_t size, uint gcId);
3637
};
3738

src/hotspot/share/gc/shared/memAllocator.cpp

+38-12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "gc/shared/memAllocator.hpp"
3131
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
3232
#include "gc/shared/tlab_globals.hpp"
33+
#include "jfr/jfrEvents.hpp"
3334
#include "memory/universe.hpp"
3435
#include "oops/arrayOop.hpp"
3536
#include "oops/oop.inline.hpp"
@@ -41,6 +42,7 @@
4142
#include "services/lowMemoryDetector.hpp"
4243
#include "utilities/align.hpp"
4344
#include "utilities/copy.hpp"
45+
#include "utilities/dtrace.hpp"
4446
#include "utilities/globalDefinitions.hpp"
4547

4648
class MemAllocator::Allocation: StackObj {
@@ -52,7 +54,8 @@ class MemAllocator::Allocation: StackObj {
5254
bool _overhead_limit_exceeded;
5355
bool _allocated_outside_tlab;
5456
size_t _allocated_tlab_size;
55-
bool _tlab_end_reset_for_sample;
57+
bool _tlab_end_reset_for_jvmti_sample;
58+
bool _tlab_end_reset_for_jfr_sample;
5659

5760
bool check_out_of_memory();
5861
void verify_before();
@@ -76,7 +79,8 @@ class MemAllocator::Allocation: StackObj {
7679
_overhead_limit_exceeded(false),
7780
_allocated_outside_tlab(false),
7881
_allocated_tlab_size(0),
79-
_tlab_end_reset_for_sample(false)
82+
_tlab_end_reset_for_jvmti_sample(false),
83+
_tlab_end_reset_for_jfr_sample(false)
8084
{
8185
assert(Thread::current() == allocator._thread, "do not pass MemAllocator across threads");
8286
verify_before();
@@ -171,7 +175,7 @@ void MemAllocator::Allocation::notify_allocation_jvmti_sampler() {
171175
return;
172176
}
173177

174-
if (!_allocated_outside_tlab && _allocated_tlab_size == 0 && !_tlab_end_reset_for_sample) {
178+
if (!_allocated_outside_tlab && _allocated_tlab_size == 0 && !_tlab_end_reset_for_jvmti_sample) {
175179
// Sample if it's a non-TLAB allocation, or a TLAB allocation that either refills the TLAB
176180
// or expands it due to taking a sampler induced slow path.
177181
return;
@@ -181,23 +185,21 @@ void MemAllocator::Allocation::notify_allocation_jvmti_sampler() {
181185
// before doing the callback. The callback is done in the destructor of
182186
// the JvmtiSampledObjectAllocEventCollector.
183187
size_t bytes_since_last = 0;
184-
188+
size_t bytes_since_allocation = 0;
185189
{
186190
PreserveObj obj_h(_thread, _obj_ptr);
187191
JvmtiSampledObjectAllocEventCollector collector;
188192
size_t size_in_bytes = _allocator._word_size * HeapWordSize;
189-
ThreadLocalAllocBuffer& tlab = _thread->tlab();
190193

191-
if (!_allocated_outside_tlab) {
192-
bytes_since_last = tlab.bytes_since_last_sample_point();
194+
if (_thread->heap_samplers().jvmti().check_for_sampling(&bytes_since_allocation, size_in_bytes, !_allocated_outside_tlab)) {
195+
// HOTSPOT_GC_ALLOCOBJECT_SAMPLE(obj_h->klass()->name()->as_C_string(), size_in_bytes, bytes_since_allocation);
196+
JvmtiExport::sampled_object_alloc_event_collector(obj_h());
193197
}
194-
195-
_thread->heap_sampler().check_for_sampling(obj_h(), size_in_bytes, bytes_since_last);
196198
}
197199

198-
if (_tlab_end_reset_for_sample || _allocated_tlab_size != 0) {
200+
if (_tlab_end_reset_for_jvmti_sample || _allocated_tlab_size != 0) {
199201
// Tell tlab to forget bytes_since_last if we passed it to the heap sampler.
200-
_thread->tlab().set_sample_end(bytes_since_last != 0);
202+
_thread->tlab().set_jvmti_sample_end(!_allocated_outside_tlab);
201203
}
202204
}
203205

@@ -217,6 +219,30 @@ void MemAllocator::Allocation::notify_allocation_jfr_sampler() {
217219
AllocTracer::send_allocation_in_new_tlab(obj()->klass(), mem, _allocated_tlab_size * HeapWordSize,
218220
size_in_bytes, _thread);
219221
}
222+
223+
EventObjectAllocationSample event;
224+
if (!event.should_commit()) {
225+
return;
226+
}
227+
228+
bool hit_mark = _allocated_tlab_size != 0 || _tlab_end_reset_for_jfr_sample;
229+
if (!_allocated_outside_tlab && !hit_mark) {
230+
// Sample if it's a non-TLAB allocation, or a TLAB allocation that either refills the TLAB
231+
// or expands it due to taking a sampler induced slow path.
232+
return;
233+
}
234+
235+
size_t bytes_since_allocation = 0;
236+
if (_thread->heap_samplers().jfr().check_for_sampling(&bytes_since_allocation, size_in_bytes, !_allocated_outside_tlab)) {
237+
size_t weight = bytes_since_allocation == 0 ? size_in_bytes : bytes_since_allocation;
238+
AllocTracer::send_allocation_sample(obj()->klass(), mem, size_in_bytes, weight, _allocated_outside_tlab, _thread);
239+
HOTSPOT_GC_ALLOCOBJECT_SAMPLE(obj()->klass()->name()->as_C_string(), size_in_bytes, weight);
240+
}
241+
242+
if (hit_mark) {
243+
// Tell tlab to forget bytes_since_last if we passed it to the heap sampler.
244+
_thread->tlab().set_jfr_sample_end(!_allocated_outside_tlab);
245+
}
220246
}
221247

222248
void MemAllocator::Allocation::notify_allocation_dtrace_sampler() {
@@ -264,7 +290,7 @@ HeapWord* MemAllocator::mem_allocate_inside_tlab_slow(Allocation& allocation) co
264290

265291
// We set back the allocation sample point to try to allocate this, reset it
266292
// when done.
267-
allocation._tlab_end_reset_for_sample = true;
293+
allocation._tlab_end_reset_for_jvmti_sample = true;
268294

269295
if (mem != nullptr) {
270296
return mem;

src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp

+35-7
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() :
5050
_desired_size(0),
5151
_refill_waste_limit(0),
5252
_allocated_before_last_gc(0),
53-
_bytes_since_last_sample_point(0),
5453
_number_of_refills(0),
5554
_refill_waste(0),
5655
_gc_waste(0),
@@ -203,6 +202,7 @@ void ThreadLocalAllocBuffer::initialize(HeapWord* start,
203202
set_end(end);
204203
set_allocation_end(end);
205204
invariants();
205+
_end_backup = nullptr;
206206
}
207207

208208
void ThreadLocalAllocBuffer::initialize() {
@@ -313,21 +313,49 @@ void ThreadLocalAllocBuffer::print_stats(const char* tag) {
313313
_refill_waste * HeapWordSize);
314314
}
315315

316-
void ThreadLocalAllocBuffer::set_sample_end(bool reset_byte_accumulation) {
316+
void ThreadLocalAllocBuffer::set_jvmti_sample_end(bool reset_byte_accumulation) {
317+
ThreadHeapSampler& sampler = thread()->heap_samplers().jvmti();
317318
size_t heap_words_remaining = pointer_delta(_end, _top);
318-
size_t bytes_until_sample = thread()->heap_sampler().bytes_until_sample();
319+
size_t bytes_until_sample = sampler.bytes_until_sample();
319320
size_t words_until_sample = bytes_until_sample / HeapWordSize;
320321

321-
if (reset_byte_accumulation) {
322-
_bytes_since_last_sample_point = 0;
322+
if (heap_words_remaining > words_until_sample) {
323+
HeapWord* new_end = _top + words_until_sample;
324+
if (_end_backup != nullptr) {
325+
if (new_end > _end_backup) {
326+
HeapWord* tmp = new_end;
327+
new_end = _end_backup;
328+
_end_backup = tmp;
329+
} else {
330+
_end_backup = nullptr;
331+
}
332+
}
333+
set_end(new_end);
334+
sampler.update_bytes(bytes_until_sample, reset_byte_accumulation);
335+
} else {
336+
sampler.update_bytes(heap_words_remaining * HeapWordSize, reset_byte_accumulation);
323337
}
338+
}
339+
340+
void ThreadLocalAllocBuffer::set_jfr_sample_end(bool reset_byte_accumulation) {
341+
ThreadHeapSampler& sampler = thread()->heap_samplers().jfr();
342+
size_t heap_words_remaining = pointer_delta(_end, _top);
343+
size_t bytes_until_sample = sampler.bytes_until_sample();
344+
size_t words_until_sample = bytes_until_sample / HeapWordSize;
324345

325346
if (heap_words_remaining > words_until_sample) {
326347
HeapWord* new_end = _top + words_until_sample;
348+
if (_end_backup != nullptr) {
349+
if (new_end > _end_backup) {
350+
HeapWord* tmp = new_end;
351+
new_end = _end_backup;
352+
_end_backup = tmp;
353+
}
354+
}
327355
set_end(new_end);
328-
_bytes_since_last_sample_point += bytes_until_sample;
356+
sampler.update_bytes(bytes_until_sample, reset_byte_accumulation);
329357
} else {
330-
_bytes_since_last_sample_point += heap_words_remaining * HeapWordSize;
358+
sampler.update_bytes(heap_words_remaining * HeapWordSize, reset_byte_accumulation);
331359
}
332360
}
333361

src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
5151
HeapWord* _top; // address after last allocation
5252
HeapWord* _pf_top; // allocation prefetch watermark
5353
HeapWord* _end; // allocation end (can be the sampling end point or _allocation_end)
54+
HeapWord* _end_backup; // backup of _end for interleaved jvmti and jfr sampling
5455
HeapWord* _allocation_end; // end for allocations (actual TLAB end, excluding alignment_reserve)
5556

5657
size_t _desired_size; // desired size (including alignment_reserve)
5758
size_t _refill_waste_limit; // hold onto tlab if free() is larger than this
5859
size_t _allocated_before_last_gc; // total bytes allocated up until the last gc
59-
size_t _bytes_since_last_sample_point; // bytes since last sample point.
6060

6161
static size_t _max_size; // maximum size of any TLAB
6262
static int _reserve_for_allocation_prefetch; // Reserve at the end of the TLAB
@@ -124,7 +124,6 @@ class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
124124
size_t free() const { return pointer_delta(end(), top()); }
125125
// Don't discard tlab if remaining space is larger than this.
126126
size_t refill_waste_limit() const { return _refill_waste_limit; }
127-
size_t bytes_since_last_sample_point() const { return _bytes_since_last_sample_point; }
128127

129128
// For external inspection.
130129
const HeapWord* start_relaxed() const;
@@ -168,7 +167,8 @@ class ThreadLocalAllocBuffer: public CHeapObj<mtThread> {
168167
void initialize();
169168

170169
void set_back_allocation_end();
171-
void set_sample_end(bool reset_byte_accumulation);
170+
void set_jvmti_sample_end(bool reset_byte_accumulation);
171+
void set_jfr_sample_end(bool reset_byte_accumulation);
172172

173173
static size_t refill_waste_limit_increment();
174174

src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "jfr/recorder/service/jfrEventThrottler.hpp"
2828
#include "jfr/utilities/jfrSpinlockHelper.hpp"
2929
#include "logging/log.hpp"
30+
#include "runtime/threadHeapSampler.hpp"
3031

3132
constexpr static const JfrSamplerParams _disabled_params = {
3233
0, // sample points per window
@@ -72,6 +73,9 @@ void JfrEventThrottler::configure(JfrEventId event_id, int64_t sample_size, int6
7273
}
7374
assert(_throttler != nullptr, "JfrEventThrottler has not been properly initialized");
7475
_throttler->configure(sample_size, period_ms);
76+
77+
// TODO: Hack to get the allocation sampler going
78+
ThreadHeapSamplers::set_jfr_sampling_interval(512 * 1024);
7579
}
7680

7781
/*

src/hotspot/share/prims/jvmtiEnv.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3760,7 +3760,7 @@ JvmtiEnv::SetHeapSamplingInterval(jint sampling_interval) {
37603760
if (sampling_interval < 0) {
37613761
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
37623762
}
3763-
ThreadHeapSampler::set_sampling_interval(sampling_interval);
3763+
ThreadHeapSamplers::set_jvmti_sampling_interval(sampling_interval);
37643764
return JVMTI_ERROR_NONE;
37653765
} /* end SetHeapSamplingInterval */
37663766

src/hotspot/share/runtime/thread.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ THREAD_LOCAL Thread* Thread::_thr_current = nullptr;
6464

6565
DEBUG_ONLY(Thread* Thread::_starting_thread = nullptr;)
6666

67-
Thread::Thread(MEMFLAGS flags) {
67+
Thread::Thread(MEMFLAGS flags) : _heap_samplers(&_tlab) {
6868

6969
DEBUG_ONLY(_run_state = PRE_CALL_RUN;)
7070

src/hotspot/share/runtime/thread.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ class Thread: public ThreadShadow {
267267
ThreadLocalAllocBuffer _tlab; // Thread-local eden
268268
jlong _allocated_bytes; // Cumulative number of bytes allocated on
269269
// the Java heap
270-
ThreadHeapSampler _heap_sampler; // For use when sampling the memory.
270+
ThreadHeapSamplers _heap_samplers; // Used by the JVMTI allocation sampler
271271

272272
ThreadStatisticalInfo _statistical_info; // Statistics about the thread
273273

@@ -418,7 +418,7 @@ class Thread: public ThreadShadow {
418418
void incr_allocated_bytes(jlong size) { _allocated_bytes += size; }
419419
inline jlong cooked_allocated_bytes();
420420

421-
ThreadHeapSampler& heap_sampler() { return _heap_sampler; }
421+
ThreadHeapSamplers& heap_samplers() { return _heap_samplers; }
422422

423423
ThreadStatisticalInfo& statistical_info() { return _statistical_info; }
424424

0 commit comments

Comments
 (0)