42 NO_SAMPLE = 0, |
42 NO_SAMPLE = 0, |
43 JAVA_SAMPLE = 1, |
43 JAVA_SAMPLE = 1, |
44 NATIVE_SAMPLE = 2 |
44 NATIVE_SAMPLE = 2 |
45 }; |
45 }; |
46 |
46 |
47 static bool in_java_sample(JavaThread* thread) { |
47 static bool thread_state_in_java(JavaThread* thread) { |
48 switch (thread->thread_state()) { |
48 assert(thread != NULL, "invariant"); |
49 case _thread_new: |
49 switch(thread->thread_state()) { |
50 case _thread_uninitialized: |
50 case _thread_new: |
51 case _thread_new_trans: |
51 case _thread_uninitialized: |
52 case _thread_in_vm_trans: |
52 case _thread_new_trans: |
53 case _thread_blocked_trans: |
53 case _thread_in_vm_trans: |
54 case _thread_in_native_trans: |
54 case _thread_blocked_trans: |
55 case _thread_blocked: |
55 case _thread_in_native_trans: |
56 case _thread_in_vm: |
56 case _thread_blocked: |
57 case _thread_in_native: |
57 case _thread_in_vm: |
58 case _thread_in_Java_trans: |
58 case _thread_in_native: |
59 break; |
59 case _thread_in_Java_trans: |
60 case _thread_in_Java: |
60 break; |
61 return true; |
61 case _thread_in_Java: |
62 default: |
62 return true; |
63 ShouldNotReachHere(); |
63 default: |
64 break; |
64 ShouldNotReachHere(); |
|
65 break; |
65 } |
66 } |
66 return false; |
67 return false; |
67 } |
68 } |
68 |
69 |
69 static bool in_native_sample(JavaThread* thread) { |
70 static bool thread_state_in_native(JavaThread* thread) { |
70 switch (thread->thread_state()) { |
71 assert(thread != NULL, "invariant"); |
71 case _thread_new: |
72 switch(thread->thread_state()) { |
72 case _thread_uninitialized: |
73 case _thread_new: |
73 case _thread_new_trans: |
74 case _thread_uninitialized: |
74 case _thread_blocked_trans: |
75 case _thread_new_trans: |
75 case _thread_blocked: |
76 case _thread_blocked_trans: |
76 case _thread_in_vm: |
77 case _thread_blocked: |
77 case _thread_in_vm_trans: |
78 case _thread_in_vm: |
78 case _thread_in_Java_trans: |
79 case _thread_in_vm_trans: |
79 case _thread_in_Java: |
80 case _thread_in_Java_trans: |
80 case _thread_in_native_trans: |
81 case _thread_in_Java: |
81 break; |
82 case _thread_in_native_trans: |
82 case _thread_in_native: |
83 break; |
83 return true; |
84 case _thread_in_native: |
84 default: |
85 return true; |
85 ShouldNotReachHere(); |
86 default: |
86 break; |
87 ShouldNotReachHere(); |
|
88 break; |
87 } |
89 } |
88 return false; |
90 return false; |
89 } |
91 } |
90 |
92 |
91 class JfrThreadSampleClosure { |
93 class JfrThreadSampleClosure { |
92 public: |
94 public: |
93 JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native); |
95 JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native); |
94 ~JfrThreadSampleClosure() {} |
96 ~JfrThreadSampleClosure() {} |
95 EventExecutionSample* next_event() { return &_events[_added_java++]; } |
97 EventExecutionSample* next_event() { return &_events[_added_java++]; } |
96 EventNativeMethodSample* next_event_native() { return &_events_native[_added_native++]; } |
98 EventNativeMethodSample* next_event_native() { return &_events_native[_added_native++]; } |
97 void commit_events(); |
99 void commit_events(JfrSampleType type); |
98 int added() const { return _added_java; } |
100 bool do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type); |
99 JfrSampleType do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, bool java_sample, bool native_sample); |
101 uint java_entries() { return _added_java; } |
100 int java_entries() { return _added_java; } |
102 uint native_entries() { return _added_native; } |
101 int native_entries() { return _added_native; } |
|
102 |
103 |
103 private: |
104 private: |
104 bool sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames); |
105 bool sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames); |
105 bool sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames); |
106 bool sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames); |
106 EventExecutionSample* _events; |
107 EventExecutionSample* _events; |
107 EventNativeMethodSample* _events_native; |
108 EventNativeMethodSample* _events_native; |
108 Thread* _self; |
109 Thread* _self; |
109 int _added_java; |
110 uint _added_java; |
110 int _added_native; |
111 uint _added_native; |
111 }; |
112 }; |
112 |
113 |
113 class OSThreadSampler : public os::SuspendedThreadTask { |
114 class OSThreadSampler : public os::SuspendedThreadTask { |
114 public: |
115 public: |
115 OSThreadSampler(JavaThread* thread, |
116 OSThreadSampler(JavaThread* thread, |
170 * using a signal handler / __try block. Don't take locks, rely on destructors or |
171 * using a signal handler / __try block. Don't take locks, rely on destructors or |
171 * leave memory (in case of signal / exception) in an inconsistent state. */ |
172 * leave memory (in case of signal / exception) in an inconsistent state. */ |
172 void OSThreadSampler::protected_task(const os::SuspendedThreadTaskContext& context) { |
173 void OSThreadSampler::protected_task(const os::SuspendedThreadTaskContext& context) { |
173 JavaThread* jth = (JavaThread*)context.thread(); |
174 JavaThread* jth = (JavaThread*)context.thread(); |
174 // Skip sample if we signaled a thread that moved to other state |
175 // Skip sample if we signaled a thread that moved to other state |
175 if (!in_java_sample(jth)) { |
176 if (!thread_state_in_java(jth)) { |
176 return; |
177 return; |
177 } |
178 } |
178 JfrGetCallTrace trace(true, jth); |
179 JfrGetCallTrace trace(true, jth); |
179 frame topframe; |
180 frame topframe; |
180 if (trace.get_topframe(context.ucontext(), topframe)) { |
181 if (trace.get_topframe(context.ucontext(), topframe)) { |
279 assert(id != 0, "Stacktrace id should not be 0"); |
280 assert(id != 0, "Stacktrace id should not be 0"); |
280 event->set_stackTrace(id); |
281 event->set_stackTrace(id); |
281 return true; |
282 return true; |
282 } |
283 } |
283 |
284 |
284 void JfrThreadSampleClosure::commit_events() { |
285 static const uint MAX_NR_OF_JAVA_SAMPLES = 5; |
285 for (int i = 0; i < _added_java; ++i) { |
286 static const uint MAX_NR_OF_NATIVE_SAMPLES = 1; |
286 _events[i].commit(); |
287 |
287 } |
288 void JfrThreadSampleClosure::commit_events(JfrSampleType type) { |
288 for (int i = 0; i < _added_native; ++i) { |
289 if (JAVA_SAMPLE == type) { |
289 _events_native[i].commit(); |
290 assert(_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 <= MAX_NR_OF_NATIVE_SAMPLES, "invariant"); |
|
297 for (uint i = 0; i < _added_native; ++i) { |
|
298 _events_native[i].commit(); |
|
299 } |
290 } |
300 } |
291 } |
301 } |
292 |
302 |
293 JfrThreadSampleClosure::JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native) : |
303 JfrThreadSampleClosure::JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native) : |
294 _events(events), |
304 _events(events), |
342 MutexLockerEx ml(JfrThreadSampler::transition_block(), Mutex::_no_safepoint_check_flag); |
352 MutexLockerEx ml(JfrThreadSampler::transition_block(), Mutex::_no_safepoint_check_flag); |
343 JfrThreadSampler::transition_block()->notify_all(); |
353 JfrThreadSampler::transition_block()->notify_all(); |
344 } |
354 } |
345 } |
355 } |
346 |
356 |
347 JfrSampleType JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, bool java_sample, bool native_sample) { |
357 bool JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type) { |
348 assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); |
358 assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); |
349 if (thread->is_hidden_from_external_view()) { |
359 if (thread->is_hidden_from_external_view() || thread->in_deopt_handler()) { |
350 return NO_SAMPLE; |
360 return false; |
351 } |
361 } |
352 if (thread->in_deopt_handler()) { |
362 |
353 return NO_SAMPLE; |
363 bool ret = false; |
354 } |
|
355 JfrSampleType ret = NO_SAMPLE; |
|
356 thread->set_trace_flag(); |
364 thread->set_trace_flag(); |
357 if (!UseMembar) { |
365 if (!UseMembar) { |
358 os::serialize_thread_states(); |
366 os::serialize_thread_states(); |
359 } |
367 } |
360 if (in_java_sample(thread) && java_sample) { |
368 if (JAVA_SAMPLE == type) { |
361 ret = sample_thread_in_java(thread, frames, max_frames) ? JAVA_SAMPLE : NO_SAMPLE; |
369 if (thread_state_in_java(thread)) { |
362 } else if (in_native_sample(thread) && native_sample) { |
370 ret = sample_thread_in_java(thread, frames, max_frames); |
363 ret = sample_thread_in_native(thread, frames, max_frames) ? NATIVE_SAMPLE : NO_SAMPLE; |
371 } |
|
372 } else { |
|
373 assert(NATIVE_SAMPLE == type, "invariant"); |
|
374 if (thread_state_in_native(thread)) { |
|
375 ret = sample_thread_in_native(thread, frames, max_frames); |
|
376 } |
364 } |
377 } |
365 clear_transition_block(thread); |
378 clear_transition_block(thread); |
366 return ret; |
379 return ret; |
367 } |
380 } |
368 |
381 |
394 tl->clear_trace_block(); |
407 tl->clear_trace_block(); |
395 } |
408 } |
396 } |
409 } |
397 |
410 |
398 JavaThread* JfrThreadSampler::next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current) { |
411 JavaThread* JfrThreadSampler::next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current) { |
|
412 assert(t_list != NULL, "invariant"); |
399 assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); |
413 assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); |
400 if (current == NULL) { |
414 assert(_cur_index >= -1 && (uint)_cur_index + 1 <= t_list->length(), "invariant"); |
|
415 assert((current == NULL && -1 == _cur_index) || (t_list->find_index_of_JavaThread(current) == _cur_index), "invariant"); |
|
416 if ((uint)_cur_index + 1 == t_list->length()) { |
|
417 // wrap |
401 _cur_index = 0; |
418 _cur_index = 0; |
402 return t_list->thread_at(_cur_index); |
419 } else { |
403 } |
420 _cur_index++; |
404 |
421 } |
405 if (_cur_index == -1 || t_list->thread_at(_cur_index) != current) { |
422 assert(_cur_index >= 0 && (uint)_cur_index < t_list->length(), "invariant"); |
406 // 'current' is not at '_cur_index' so find it: |
423 JavaThread* const next = t_list->thread_at(_cur_index); |
407 _cur_index = t_list->find_index_of_JavaThread(current); |
424 return next != first_sampled ? next : NULL; |
408 assert(_cur_index != -1, "current JavaThread should be findable."); |
|
409 } |
|
410 _cur_index++; |
|
411 |
|
412 JavaThread* next = NULL; |
|
413 // wrap |
|
414 if ((uint)_cur_index >= t_list->length()) { |
|
415 _cur_index = 0; |
|
416 } |
|
417 next = t_list->thread_at(_cur_index); |
|
418 |
|
419 // sample wrap |
|
420 if (next == first_sampled) { |
|
421 return NULL; |
|
422 } |
|
423 return next; |
|
424 } |
425 } |
425 |
426 |
426 void JfrThreadSampler::start_thread() { |
427 void JfrThreadSampler::start_thread() { |
427 if (os::create_thread(this, os::os_thread)) { |
428 if (os::create_thread(this, os::os_thread)) { |
428 os::start_thread(this); |
429 os::start_thread(this); |
492 } |
493 } |
493 } |
494 } |
494 delete this; |
495 delete this; |
495 } |
496 } |
496 |
497 |
497 static const int MAX_NR_OF_SAMPLES = 5; |
|
498 |
498 |
499 void JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread) { |
499 void JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread) { |
500 ResourceMark rm; |
500 ResourceMark rm; |
501 EventExecutionSample samples[MAX_NR_OF_SAMPLES]; |
501 EventExecutionSample samples[MAX_NR_OF_JAVA_SAMPLES]; |
502 EventNativeMethodSample samples_native[MAX_NR_OF_SAMPLES]; |
502 EventNativeMethodSample samples_native[MAX_NR_OF_NATIVE_SAMPLES]; |
503 JfrThreadSampleClosure sample_task(samples, samples_native); |
503 JfrThreadSampleClosure sample_task(samples, samples_native); |
504 |
504 |
505 int num_samples = 0; |
505 const uint sample_limit = JAVA_SAMPLE == type ? MAX_NR_OF_JAVA_SAMPLES : MAX_NR_OF_NATIVE_SAMPLES; |
|
506 uint num_sample_attempts = 0; |
|
507 JavaThread* start = NULL; |
|
508 |
506 { |
509 { |
507 elapsedTimer sample_time; |
510 elapsedTimer sample_time; |
508 sample_time.start(); |
511 sample_time.start(); |
509 |
|
510 { |
512 { |
511 MonitorLockerEx tlock(Threads_lock, Mutex::_allow_vm_block_flag); |
513 MonitorLockerEx tlock(Threads_lock, Mutex::_allow_vm_block_flag); |
512 ThreadsListHandle tlh; |
514 ThreadsListHandle tlh; |
513 JavaThread* current = tlh.includes(*last_thread) ? *last_thread : NULL; |
515 // Resolve a sample session relative start position index into the thread list array. |
514 JavaThread* start = NULL; |
516 // In cases where the last sampled thread is NULL or not-NULL but stale, find_index() returns -1. |
515 |
517 _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread); |
516 while (num_samples < MAX_NR_OF_SAMPLES) { |
518 JavaThread* current = _cur_index != -1 ? *last_thread : NULL; |
|
519 |
|
520 while (num_sample_attempts < sample_limit) { |
517 current = next_thread(tlh.list(), start, current); |
521 current = next_thread(tlh.list(), start, current); |
518 if (current == NULL) { |
522 if (current == NULL) { |
519 break; |
523 break; |
520 } |
524 } |
521 if (start == NULL) { |
525 if (start == NULL) { |
522 start = current; // remember thread where we started sampling |
526 start = current; // remember the thread where we started to attempt sampling |
523 } |
527 } |
524 if (current->is_Compiler_thread()) { |
528 if (current->is_Compiler_thread()) { |
525 continue; |
529 continue; |
526 } |
530 } |
527 *last_thread = current; // remember thread we last sampled |
531 sample_task.do_sample_thread(current, _frames, _max_frames, type); |
528 JfrSampleType ret = sample_task.do_sample_thread(current, _frames, _max_frames, type == JAVA_SAMPLE, type == NATIVE_SAMPLE); |
532 num_sample_attempts++; |
529 switch (type) { |
|
530 case JAVA_SAMPLE: |
|
531 case NATIVE_SAMPLE: |
|
532 ++num_samples; |
|
533 break; |
|
534 default: |
|
535 break; |
|
536 } |
|
537 } |
533 } |
|
534 *last_thread = current; // remember the thread we last attempted to sample |
538 } |
535 } |
539 sample_time.stop(); |
536 sample_time.stop(); |
540 log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples", |
537 log_trace(jfr)("JFR thread sampling done in %3.7f secs with %d java %d native samples", |
541 sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries()); |
538 sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries()); |
542 } |
539 } |
543 if (num_samples > 0) { |
540 if (num_sample_attempts > 0) { |
544 sample_task.commit_events(); |
541 sample_task.commit_events(type); |
545 } |
542 } |
546 } |
543 } |
547 |
544 |
548 static JfrThreadSampling* _instance = NULL; |
545 static JfrThreadSampling* _instance = NULL; |
549 |
546 |
571 _sampler->disenroll(); |
568 _sampler->disenroll(); |
572 } |
569 } |
573 } |
570 } |
574 |
571 |
575 static void log(size_t interval_java, size_t interval_native) { |
572 static void log(size_t interval_java, size_t interval_native) { |
576 log_info(jfr)("Updated thread sampler for java: " SIZE_FORMAT" ms, native " SIZE_FORMAT " ms", interval_java, interval_native); |
573 log_info(jfr)("Updated thread sampler for java: " SIZE_FORMAT " ms, native " SIZE_FORMAT " ms", interval_java, interval_native); |
577 } |
574 } |
578 |
575 |
579 void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) { |
576 void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) { |
580 assert(_sampler == NULL, "invariant"); |
577 assert(_sampler == NULL, "invariant"); |
581 log_info(jfr)("Enrolling thread sampler"); |
578 log_info(jfr)("Enrolling thread sampler"); |
589 size_t interval_native = 0; |
586 size_t interval_native = 0; |
590 if (_sampler != NULL) { |
587 if (_sampler != NULL) { |
591 interval_java = _sampler->get_java_interval(); |
588 interval_java = _sampler->get_java_interval(); |
592 interval_native = _sampler->get_native_interval(); |
589 interval_native = _sampler->get_native_interval(); |
593 } |
590 } |
594 |
|
595 if (java_interval) { |
591 if (java_interval) { |
596 interval_java = period; |
592 interval_java = period; |
597 } else { |
593 } else { |
598 interval_native = period; |
594 interval_native = period; |
599 } |
595 } |
600 |
|
601 if (interval_java > 0 || interval_native > 0) { |
596 if (interval_java > 0 || interval_native > 0) { |
602 if (_sampler == NULL) { |
597 if (_sampler == NULL) { |
603 log_info(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native); |
598 log_info(jfr)("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native); |
604 start_sampler(interval_java, interval_native); |
599 start_sampler(interval_java, interval_native); |
605 } else { |
600 } else { |