1 /*
2 * Copyright (c) 2012, 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 *
23 */
24
25 #include "precompiled.hpp"
26 #include "jfr/jfrEvents.hpp"
27 #include "jfr/recorder/jfrRecorder.hpp"
28 #include "jfr/periodic/sampling/jfrCallTrace.hpp"
29 #include "jfr/periodic/sampling/jfrThreadSampler.hpp"
30 #include "jfr/recorder/service/jfrOptionSet.hpp"
31 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
32 #include "jfr/support/jfrThreadId.hpp"
33 #include "jfr/utilities/jfrTime.hpp"
34 #include "logging/log.hpp"
35 #include "runtime/frame.inline.hpp"
36 #include "runtime/os.hpp"
37 #include "runtime/semaphore.hpp"
38 #include "runtime/thread.inline.hpp"
39 #include "runtime/threadSMR.hpp"
40
41 enum JfrSampleType {
42 NO_SAMPLE = 0,
43 JAVA_SAMPLE = 1,
44 NATIVE_SAMPLE = 2
45 };
46
thread_state_in_java(JavaThread * thread)47 static bool thread_state_in_java(JavaThread* thread) {
48 assert(thread != NULL, "invariant");
49 switch(thread->thread_state()) {
50 case _thread_new:
51 case _thread_uninitialized:
52 case _thread_new_trans:
53 case _thread_in_vm_trans:
54 case _thread_blocked_trans:
55 case _thread_in_native_trans:
56 case _thread_blocked:
57 case _thread_in_vm:
58 case _thread_in_native:
59 case _thread_in_Java_trans:
60 break;
61 case _thread_in_Java:
62 return true;
63 default:
64 ShouldNotReachHere();
65 break;
66 }
67 return false;
68 }
69
thread_state_in_native(JavaThread * thread)70 static bool thread_state_in_native(JavaThread* thread) {
71 assert(thread != NULL, "invariant");
72 switch(thread->thread_state()) {
73 case _thread_new:
74 case _thread_uninitialized:
75 case _thread_new_trans:
76 case _thread_blocked_trans:
77 case _thread_blocked:
78 case _thread_in_vm:
79 case _thread_in_vm_trans:
80 case _thread_in_Java_trans:
81 case _thread_in_Java:
82 case _thread_in_native_trans:
83 break;
84 case _thread_in_native:
85 return true;
86 default:
87 ShouldNotReachHere();
88 break;
89 }
90 return false;
91 }
92
93 class JfrThreadSampleClosure {
94 public:
95 JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native);
~JfrThreadSampleClosure()96 ~JfrThreadSampleClosure() {}
next_event()97 EventExecutionSample* next_event() { return &_events[_added_java++]; }
next_event_native()98 EventNativeMethodSample* next_event_native() { return &_events_native[_added_native++]; }
99 void commit_events(JfrSampleType type);
100 bool do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type);
java_entries()101 uint java_entries() { return _added_java; }
native_entries()102 uint native_entries() { return _added_native; }
103
104 private:
105 bool sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
106 bool sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
107 EventExecutionSample* _events;
108 EventNativeMethodSample* _events_native;
109 Thread* _self;
110 uint _added_java;
111 uint _added_native;
112 };
113
114 class OSThreadSampler : public os::SuspendedThreadTask {
115 public:
OSThreadSampler(JavaThread * thread,JfrThreadSampleClosure & closure,JfrStackFrame * frames,u4 max_frames)116 OSThreadSampler(JavaThread* thread,
117 JfrThreadSampleClosure& closure,
118 JfrStackFrame *frames,
119 u4 max_frames) : os::SuspendedThreadTask((Thread*)thread),
120 _success(false),
121 _stacktrace(frames, max_frames),
122 _closure(closure),
123 _suspend_time() {}
124
125 void take_sample();
126 void do_task(const os::SuspendedThreadTaskContext& context);
127 void protected_task(const os::SuspendedThreadTaskContext& context);
success() const128 bool success() const { return _success; }
stacktrace() const129 const JfrStackTrace& stacktrace() const { return _stacktrace; }
130
131 private:
132 bool _success;
133 JfrStackTrace _stacktrace;
134 JfrThreadSampleClosure& _closure;
135 JfrTicks _suspend_time;
136 };
137
138 class OSThreadSamplerCallback : public os::CrashProtectionCallback {
139 public:
OSThreadSamplerCallback(OSThreadSampler & sampler,const os::SuspendedThreadTaskContext & context)140 OSThreadSamplerCallback(OSThreadSampler& sampler, const os::SuspendedThreadTaskContext &context) :
141 _sampler(sampler), _context(context) {
142 }
call()143 virtual void call() {
144 _sampler.protected_task(_context);
145 }
146 private:
147 OSThreadSampler& _sampler;
148 const os::SuspendedThreadTaskContext& _context;
149 };
150
do_task(const os::SuspendedThreadTaskContext & context)151 void OSThreadSampler::do_task(const os::SuspendedThreadTaskContext& context) {
152 #ifndef ASSERT
153 guarantee(JfrOptionSet::sample_protection(), "Sample Protection should be on in product builds");
154 #endif
155 assert(_suspend_time.value() == 0, "already timestamped!");
156 _suspend_time = JfrTicks::now();
157
158 if (JfrOptionSet::sample_protection()) {
159 OSThreadSamplerCallback cb(*this, context);
160 os::ThreadCrashProtection crash_protection;
161 if (!crash_protection.call(cb)) {
162 log_error(jfr)("Thread method sampler crashed");
163 }
164 } else {
165 protected_task(context);
166 }
167 }
168
169 /*
170 * From this method and down the call tree we attempt to protect against crashes
171 * using a signal handler / __try block. Don't take locks, rely on destructors or
172 * leave memory (in case of signal / exception) in an inconsistent state. */
protected_task(const os::SuspendedThreadTaskContext & context)173 void OSThreadSampler::protected_task(const os::SuspendedThreadTaskContext& context) {
174 JavaThread* jth = (JavaThread*)context.thread();
175 // Skip sample if we signaled a thread that moved to other state
176 if (!thread_state_in_java(jth)) {
177 return;
178 }
179 JfrGetCallTrace trace(true, jth);
180 frame topframe;
181 if (trace.get_topframe(context.ucontext(), topframe)) {
182 if (_stacktrace.record_thread(*jth, topframe)) {
183 /* If we managed to get a topframe and a stacktrace, create an event
184 * and put it into our array. We can't call Jfr::_stacktraces.add()
185 * here since it would allocate memory using malloc. Doing so while
186 * the stopped thread is inside malloc would deadlock. */
187 _success = true;
188 EventExecutionSample *ev = _closure.next_event();
189 ev->set_starttime(_suspend_time);
190 ev->set_endtime(_suspend_time); // fake to not take an end time
191 ev->set_sampledThread(JFR_THREAD_ID(jth));
192 ev->set_state(java_lang_Thread::get_thread_status(jth->threadObj()));
193 }
194 }
195 }
196
take_sample()197 void OSThreadSampler::take_sample() {
198 run();
199 }
200
201 class JfrNativeSamplerCallback : public os::CrashProtectionCallback {
202 public:
JfrNativeSamplerCallback(JfrThreadSampleClosure & closure,JavaThread * jt,JfrStackFrame * frames,u4 max_frames)203 JfrNativeSamplerCallback(JfrThreadSampleClosure& closure, JavaThread* jt, JfrStackFrame* frames, u4 max_frames) :
204 _closure(closure), _jt(jt), _stacktrace(frames, max_frames), _success(false) {
205 }
206 virtual void call();
success()207 bool success() { return _success; }
stacktrace()208 JfrStackTrace& stacktrace() { return _stacktrace; }
209
210 private:
211 JfrThreadSampleClosure& _closure;
212 JavaThread* _jt;
213 JfrStackTrace _stacktrace;
214 bool _success;
215 };
216
write_native_event(JfrThreadSampleClosure & closure,JavaThread * jt)217 static void write_native_event(JfrThreadSampleClosure& closure, JavaThread* jt) {
218 EventNativeMethodSample *ev = closure.next_event_native();
219 ev->set_starttime(JfrTicks::now());
220 ev->set_sampledThread(JFR_THREAD_ID(jt));
221 ev->set_state(java_lang_Thread::get_thread_status(jt->threadObj()));
222 }
223
call()224 void JfrNativeSamplerCallback::call() {
225 // When a thread is only attach it will be native without a last java frame
226 if (!_jt->has_last_Java_frame()) {
227 return;
228 }
229
230 frame topframe = _jt->last_frame();
231 frame first_java_frame;
232 Method* method = NULL;
233 JfrGetCallTrace gct(false, _jt);
234 if (!gct.find_top_frame(topframe, &method, first_java_frame)) {
235 return;
236 }
237 if (method == NULL) {
238 return;
239 }
240 topframe = first_java_frame;
241 _success = _stacktrace.record_thread(*_jt, topframe);
242 if (_success) {
243 write_native_event(_closure, _jt);
244 }
245 }
246
sample_thread_in_java(JavaThread * thread,JfrStackFrame * frames,u4 max_frames)247 bool JfrThreadSampleClosure::sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
248 OSThreadSampler sampler(thread, *this, frames, max_frames);
249 sampler.take_sample();
250 /* We don't want to allocate any memory using malloc/etc while the thread
251 * is stopped, so everything is stored in stack allocated memory until this
252 * point where the thread has been resumed again, if the sampling was a success
253 * we need to store the stacktrace in the stacktrace repository and update
254 * the event with the id that was returned. */
255 if (!sampler.success()) {
256 return false;
257 }
258 EventExecutionSample *event = &_events[_added_java - 1];
259 traceid id = JfrStackTraceRepository::add(sampler.stacktrace());
260 assert(id != 0, "Stacktrace id should not be 0");
261 event->set_stackTrace(id);
262 return true;
263 }
264
sample_thread_in_native(JavaThread * thread,JfrStackFrame * frames,u4 max_frames)265 bool JfrThreadSampleClosure::sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
266 JfrNativeSamplerCallback cb(*this, thread, frames, max_frames);
267 if (JfrOptionSet::sample_protection()) {
268 os::ThreadCrashProtection crash_protection;
269 if (!crash_protection.call(cb)) {
270 log_error(jfr)("Thread method sampler crashed for native");
271 }
272 } else {
273 cb.call();
274 }
275 if (!cb.success()) {
276 return false;
277 }
278 EventNativeMethodSample *event = &_events_native[_added_native - 1];
279 traceid id = JfrStackTraceRepository::add(cb.stacktrace());
280 assert(id != 0, "Stacktrace id should not be 0");
281 event->set_stackTrace(id);
282 return true;
283 }
284
285 static const uint MAX_NR_OF_JAVA_SAMPLES = 5;
286 static const uint MAX_NR_OF_NATIVE_SAMPLES = 1;
287
commit_events(JfrSampleType type)288 void JfrThreadSampleClosure::commit_events(JfrSampleType type) {
289 if (JAVA_SAMPLE == type) {
290 assert(_added_java > 0 && _added_java <= MAX_NR_OF_JAVA_SAMPLES, "invariant");
291 for (uint i = 0; i < _added_java; ++i) {
292 _events[i].commit();
293 }
294 } else {
295 assert(NATIVE_SAMPLE == type, "invariant");
296 assert(_added_native > 0 && _added_native <= MAX_NR_OF_NATIVE_SAMPLES, "invariant");
297 for (uint i = 0; i < _added_native; ++i) {
298 _events_native[i].commit();
299 }
300 }
301 }
302
JfrThreadSampleClosure(EventExecutionSample * events,EventNativeMethodSample * events_native)303 JfrThreadSampleClosure::JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native) :
304 _events(events),
305 _events_native(events_native),
306 _self(Thread::current()),
307 _added_java(0),
308 _added_native(0) {
309 }
310
311 class JfrThreadSampler : public NonJavaThread {
312 friend class JfrThreadSampling;
313 private:
314 Semaphore _sample;
315 Thread* _sampler_thread;
316 JfrStackFrame* const _frames;
317 JavaThread* _last_thread_java;
318 JavaThread* _last_thread_native;
319 size_t _interval_java;
320 size_t _interval_native;
321 int _cur_index;
322 const u4 _max_frames;
323 volatile bool _disenrolled;
324
325 JavaThread* next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current);
326 void task_stacktrace(JfrSampleType type, JavaThread** last_thread);
327 JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames);
328 ~JfrThreadSampler();
329
330 void start_thread();
331
332 void enroll();
333 void disenroll();
set_java_interval(size_t interval)334 void set_java_interval(size_t interval) { _interval_java = interval; };
set_native_interval(size_t interval)335 void set_native_interval(size_t interval) { _interval_native = interval; };
get_java_interval()336 size_t get_java_interval() { return _interval_java; };
get_native_interval()337 size_t get_native_interval() { return _interval_native; };
338
339 public:
340 void run();
transition_block()341 static Monitor* transition_block() { return JfrThreadSampler_lock; }
342 static void on_javathread_suspend(JavaThread* thread);
343 };
344
clear_transition_block(JavaThread * jt)345 static void clear_transition_block(JavaThread* jt) {
346 jt->clear_trace_flag();
347 JfrThreadLocal* const tl = jt->jfr_thread_local();
348 if (tl->is_trace_block()) {
349 MutexLockerEx ml(JfrThreadSampler::transition_block(), Mutex::_no_safepoint_check_flag);
350 JfrThreadSampler::transition_block()->notify_all();
351 }
352 }
353
do_sample_thread(JavaThread * thread,JfrStackFrame * frames,u4 max_frames,JfrSampleType type)354 bool JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type) {
355 assert(Threads_lock->owned_by_self(), "Holding the thread table lock.");
356 if (thread->is_hidden_from_external_view() || thread->in_deopt_handler()) {
357 return false;
358 }
359
360 bool ret = false;
361 thread->set_trace_flag();
362 if (!UseMembar) {
363 os::serialize_thread_states();
364 }
365 if (JAVA_SAMPLE == type) {
366 if (thread_state_in_java(thread)) {
367 ret = sample_thread_in_java(thread, frames, max_frames);
368 }
369 } else {
370 assert(NATIVE_SAMPLE == type, "invariant");
371 if (thread_state_in_native(thread)) {
372 ret = sample_thread_in_native(thread, frames, max_frames);
373 }
374 }
375 clear_transition_block(thread);
376 return ret;
377 }
378
JfrThreadSampler(size_t interval_java,size_t interval_native,u4 max_frames)379 JfrThreadSampler::JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames) :
380 _sample(),
381 _sampler_thread(NULL),
382 _frames(JfrCHeapObj::new_array<JfrStackFrame>(max_frames)),
383 _last_thread_java(NULL),
384 _last_thread_native(NULL),
385 _interval_java(interval_java),
386 _interval_native(interval_native),
387 _cur_index(-1),
388 _max_frames(max_frames),
389 _disenrolled(true) {
390 }
391
~JfrThreadSampler()392 JfrThreadSampler::~JfrThreadSampler() {
393 JfrCHeapObj::free(_frames, sizeof(JfrStackFrame) * _max_frames);
394 }
395
on_javathread_suspend(JavaThread * thread)396 void JfrThreadSampler::on_javathread_suspend(JavaThread* thread) {
397 JfrThreadLocal* const tl = thread->jfr_thread_local();
398 tl->set_trace_block();
399 {
400 MutexLockerEx ml(transition_block(), Mutex::_no_safepoint_check_flag);
401 while (thread->is_trace_suspend()) {
402 transition_block()->wait(true);
403 }
404 tl->clear_trace_block();
405 }
406 }
407
next_thread(ThreadsList * t_list,JavaThread * first_sampled,JavaThread * current)408 JavaThread* JfrThreadSampler::next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current) {
409 assert(t_list != NULL, "invariant");
410 assert(Threads_lock->owned_by_self(), "Holding the thread table lock.");
411 assert(_cur_index >= -1 && (uint)_cur_index + 1 <= t_list->length(), "invariant");
412 assert((current == NULL && -1 == _cur_index) || (t_list->find_index_of_JavaThread(current) == _cur_index), "invariant");
413 if ((uint)_cur_index + 1 == t_list->length()) {
414 // wrap
415 _cur_index = 0;
416 } else {
417 _cur_index++;
418 }
419 assert(_cur_index >= 0 && (uint)_cur_index < t_list->length(), "invariant");
420 JavaThread* const next = t_list->thread_at(_cur_index);
421 return next != first_sampled ? next : NULL;
422 }
423
start_thread()424 void JfrThreadSampler::start_thread() {
425 if (os::create_thread(this, os::os_thread)) {
426 os::start_thread(this);
427 } else {
428 log_error(jfr)("Failed to create thread for thread sampling");
429 }
430 }
431
enroll()432 void JfrThreadSampler::enroll() {
433 if (_disenrolled) {
434 log_info(jfr)("Enrolling thread sampler");
435 _sample.signal();
436 _disenrolled = false;
437 }
438 }
439
disenroll()440 void JfrThreadSampler::disenroll() {
441 if (!_disenrolled) {
442 _sample.wait();
443 _disenrolled = true;
444 log_info(jfr)("Disenrolling thread sampler");
445 }
446 }
447
get_monotonic_ms()448 static jlong get_monotonic_ms() {
449 return os::javaTimeNanos() / 1000000;
450 }
451
run()452 void JfrThreadSampler::run() {
453 assert(_sampler_thread == NULL, "invariant");
454
455 _sampler_thread = this;
456
457 jlong last_java_ms = get_monotonic_ms();
458 jlong last_native_ms = last_java_ms;
459 while (true) {
460 if (!_sample.trywait()) {
461 // disenrolled
462 _sample.wait();
463 last_java_ms = get_monotonic_ms();
464 last_native_ms = last_java_ms;
465 }
466 _sample.signal();
467 jlong java_interval = _interval_java == 0 ? max_jlong : MAX2<jlong>(_interval_java, 1);
468 jlong native_interval = _interval_native == 0 ? max_jlong : MAX2<jlong>(_interval_native, 1);
469
470 jlong now_ms = get_monotonic_ms();
471
472 /*
473 * Let I be java_interval or native_interval.
474 * Let L be last_java_ms or last_native_ms.
475 * Let N be now_ms.
476 *
477 * Interval, I, might be max_jlong so the addition
478 * could potentially overflow without parenthesis (UB). Also note that
479 * L - N < 0. Avoid UB, by adding parenthesis.
480 */
481 jlong next_j = java_interval + (last_java_ms - now_ms);
482 jlong next_n = native_interval + (last_native_ms - now_ms);
483
484 jlong sleep_to_next = MIN2<jlong>(next_j, next_n);
485
486 if (sleep_to_next > 0) {
487 os::naked_short_sleep(sleep_to_next);
488 }
489
490 if ((next_j - sleep_to_next) <= 0) {
491 task_stacktrace(JAVA_SAMPLE, &_last_thread_java);
492 last_java_ms = get_monotonic_ms();
493 }
494 if ((next_n - sleep_to_next) <= 0) {
495 task_stacktrace(NATIVE_SAMPLE, &_last_thread_native);
496 last_native_ms = get_monotonic_ms();
497 }
498 }
499 delete this;
500 }
501
502
task_stacktrace(JfrSampleType type,JavaThread ** last_thread)503 void JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread) {
504 ResourceMark rm;
505 EventExecutionSample samples[MAX_NR_OF_JAVA_SAMPLES];
506 EventNativeMethodSample samples_native[MAX_NR_OF_NATIVE_SAMPLES];
507 JfrThreadSampleClosure sample_task(samples, samples_native);
508
509 const uint sample_limit = JAVA_SAMPLE == type ? MAX_NR_OF_JAVA_SAMPLES : MAX_NR_OF_NATIVE_SAMPLES;
510 uint num_samples = 0;
511 JavaThread* start = NULL;
512
513 {
514 elapsedTimer sample_time;
515 sample_time.start();
516 {
517 MonitorLockerEx tlock(Threads_lock, Mutex::_allow_vm_block_flag);
518 ThreadsListHandle tlh;
519 // Resolve a sample session relative start position index into the thread list array.
520 // In cases where the last sampled thread is NULL or not-NULL but stale, find_index() returns -1.
521 _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread);
522 JavaThread* current = _cur_index != -1 ? *last_thread : NULL;
523
524 while (num_samples < sample_limit) {
525 current = next_thread(tlh.list(), start, current);
526 if (current == NULL) {
527 break;
528 }
529 if (start == NULL) {
530 start = current; // remember the thread where we started to attempt sampling
531 }
532 if (current->is_Compiler_thread()) {
533 continue;
534 }
535 if (sample_task.do_sample_thread(current, _frames, _max_frames, type)) {
536 num_samples++;
537 }
538 }
539 *last_thread = current; // remember the thread we last attempted to sample
540 }
541 sample_time.stop();
542 log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples",
543 sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries());
544 }
545 if (num_samples > 0) {
546 sample_task.commit_events(type);
547 }
548 }
549
550 static JfrThreadSampling* _instance = NULL;
551
instance()552 JfrThreadSampling& JfrThreadSampling::instance() {
553 return *_instance;
554 }
555
create()556 JfrThreadSampling* JfrThreadSampling::create() {
557 assert(_instance == NULL, "invariant");
558 _instance = new JfrThreadSampling();
559 return _instance;
560 }
561
destroy()562 void JfrThreadSampling::destroy() {
563 if (_instance != NULL) {
564 delete _instance;
565 _instance = NULL;
566 }
567 }
568
JfrThreadSampling()569 JfrThreadSampling::JfrThreadSampling() : _sampler(NULL) {}
570
~JfrThreadSampling()571 JfrThreadSampling::~JfrThreadSampling() {
572 if (_sampler != NULL) {
573 _sampler->disenroll();
574 }
575 }
576
log(size_t interval_java,size_t interval_native)577 static void log(size_t interval_java, size_t interval_native) {
578 log_info(jfr)("Updated thread sampler for java: " SIZE_FORMAT " ms, native " SIZE_FORMAT " ms", interval_java, interval_native);
579 }
580
start_sampler(size_t interval_java,size_t interval_native)581 void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) {
582 assert(_sampler == NULL, "invariant");
583 log_info(jfr)("Enrolling thread sampler");
584 _sampler = new JfrThreadSampler(interval_java, interval_native, JfrOptionSet::stackdepth());
585 _sampler->start_thread();
586 _sampler->enroll();
587 }
588
set_sampling_interval(bool java_interval,size_t period)589 void JfrThreadSampling::set_sampling_interval(bool java_interval, size_t period) {
590 size_t interval_java = 0;
591 size_t interval_native = 0;
592 if (_sampler != NULL) {
593 interval_java = _sampler->get_java_interval();
594 interval_native = _sampler->get_native_interval();
595 }
596 if (java_interval) {
597 interval_java = period;
598 } else {
599 interval_native = period;
600 }
601 if (interval_java > 0 || interval_native > 0) {
602 if (_sampler == NULL) {
603 log_info(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native);
604 start_sampler(interval_java, interval_native);
605 } else {
606 _sampler->set_java_interval(interval_java);
607 _sampler->set_native_interval(interval_native);
608 _sampler->enroll();
609 }
610 assert(_sampler != NULL, "invariant");
611 log(interval_java, interval_native);
612 } else if (_sampler != NULL) {
613 _sampler->disenroll();
614 }
615 }
616
set_java_sample_interval(size_t period)617 void JfrThreadSampling::set_java_sample_interval(size_t period) {
618 if (_instance == NULL && 0 == period) {
619 return;
620 }
621 instance().set_sampling_interval(true, period);
622 }
623
set_native_sample_interval(size_t period)624 void JfrThreadSampling::set_native_sample_interval(size_t period) {
625 if (_instance == NULL && 0 == period) {
626 return;
627 }
628 instance().set_sampling_interval(false, period);
629 }
630
on_javathread_suspend(JavaThread * thread)631 void JfrThreadSampling::on_javathread_suspend(JavaThread* thread) {
632 JfrThreadSampler::on_javathread_suspend(thread);
633 }
634