Bug Summary

File:jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
Warning:line 602, column 3
Returning null reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name jfrThreadSampler.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/libjvm/objs/precompiled -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D _GNU_SOURCE -D _REENTRANT -D LIBC=gnu -D LINUX -D VM_LITTLE_ENDIAN -D _LP64=1 -D ASSERT -D CHECK_UNHANDLED_OOPS -D TARGET_ARCH_x86 -D INCLUDE_SUFFIX_OS=_linux -D INCLUDE_SUFFIX_CPU=_x86 -D INCLUDE_SUFFIX_COMPILER=_gcc -D TARGET_COMPILER_gcc -D AMD64 -D HOTSPOT_LIB_ARCH="amd64" -D COMPILER1 -D COMPILER2 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -I /home/daniel/Projects/java/jdk/src/hotspot/share/precompiled -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjimage -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc/adfiles -I /home/daniel/Projects/java/jdk/src/hotspot/share -I /home/daniel/Projects/java/jdk/src/hotspot/os/linux -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix -I /home/daniel/Projects/java/jdk/src/hotspot/cpu/x86 -I /home/daniel/Projects/java/jdk/src/hotspot/os_cpu/linux_x86 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/hotspot/variant-server/gensrc -D _FORTIFY_SOURCE=2 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-format-zero-length -Wno-unused-parameter -Wno-unused -Wno-parentheses -Wno-comment -Wno-unknown-pragmas -Wno-address -Wno-delete-non-virtual-dtor -Wno-char-subscripts -Wno-array-bounds -Wno-int-in-bool-context -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-empty-body -Wno-strict-overflow -Wno-sequence-point -Wno-maybe-uninitialized -Wno-misleading-indentation -Wno-cast-function-type -Wno-shift-negative-value -std=c++14 -fdeprecated-macro -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make/hotspot -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -stack-protector 1 -fno-rtti -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c++ /home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp
1/*
2 * Copyright (c) 2012, 2021, 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/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp"
31#include "jfr/recorder/service/jfrOptionSet.hpp"
32#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
33#include "jfr/recorder/storage/jfrBuffer.hpp"
34#include "jfr/support/jfrThreadId.hpp"
35#include "jfr/support/jfrThreadLocal.hpp"
36#include "jfr/utilities/jfrTime.hpp"
37#include "jfrfiles/jfrEventClasses.hpp"
38#include "logging/log.hpp"
39#include "runtime/frame.inline.hpp"
40#include "runtime/os.hpp"
41#include "runtime/semaphore.hpp"
42#include "runtime/thread.inline.hpp"
43#include "runtime/threadSMR.hpp"
44
45enum JfrSampleType {
46 NO_SAMPLE = 0,
47 JAVA_SAMPLE = 1,
48 NATIVE_SAMPLE = 2
49};
50
51static bool thread_state_in_java(JavaThread* thread) {
52 assert(thread != NULL, "invariant")do { if (!(thread != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 52, "assert(" "thread != __null" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
53 switch(thread->thread_state()) {
54 case _thread_new:
55 case _thread_uninitialized:
56 case _thread_new_trans:
57 case _thread_in_vm_trans:
58 case _thread_blocked_trans:
59 case _thread_in_native_trans:
60 case _thread_blocked:
61 case _thread_in_vm:
62 case _thread_in_native:
63 case _thread_in_Java_trans:
64 break;
65 case _thread_in_Java:
66 return true;
67 default:
68 ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 68); ::breakpoint(); } while (0)
;
69 break;
70 }
71 return false;
72}
73
74static bool thread_state_in_native(JavaThread* thread) {
75 assert(thread != NULL, "invariant")do { if (!(thread != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 75, "assert(" "thread != __null" ") failed", "invariant"); ::
breakpoint(); } } while (0)
;
76 switch(thread->thread_state()) {
77 case _thread_new:
78 case _thread_uninitialized:
79 case _thread_new_trans:
80 case _thread_blocked_trans:
81 case _thread_blocked:
82 case _thread_in_vm:
83 case _thread_in_vm_trans:
84 case _thread_in_Java_trans:
85 case _thread_in_Java:
86 case _thread_in_native_trans:
87 break;
88 case _thread_in_native:
89 return true;
90 default:
91 ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here(
"/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 91); ::breakpoint(); } while (0)
;
92 break;
93 }
94 return false;
95}
96
97class JfrThreadSampleClosure {
98 public:
99 JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native);
100 ~JfrThreadSampleClosure() {}
101 EventExecutionSample* next_event() { return &_events[_added_java++]; }
102 EventNativeMethodSample* next_event_native() { return &_events_native[_added_native++]; }
103 void commit_events(JfrSampleType type);
104 bool do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type);
105 uint java_entries() { return _added_java; }
106 uint native_entries() { return _added_native; }
107
108 private:
109 bool sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
110 bool sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames);
111 EventExecutionSample* _events;
112 EventNativeMethodSample* _events_native;
113 Thread* _self;
114 uint _added_java;
115 uint _added_native;
116};
117
118class OSThreadSampler : public os::SuspendedThreadTask {
119 public:
120 OSThreadSampler(JavaThread* thread,
121 JfrThreadSampleClosure& closure,
122 JfrStackFrame *frames,
123 u4 max_frames) : os::SuspendedThreadTask((Thread*)thread),
124 _success(false),
125 _thread_oop(thread->threadObj()),
126 _stacktrace(frames, max_frames),
127 _closure(closure),
128 _suspend_time() {}
129
130 void take_sample();
131 void do_task(const os::SuspendedThreadTaskContext& context);
132 void protected_task(const os::SuspendedThreadTaskContext& context);
133 bool success() const { return _success; }
134 const JfrStackTrace& stacktrace() const { return _stacktrace; }
135
136 private:
137 bool _success;
138 oop _thread_oop;
139 JfrStackTrace _stacktrace;
140 JfrThreadSampleClosure& _closure;
141 JfrTicks _suspend_time;
142};
143
144class OSThreadSamplerCallback : public os::CrashProtectionCallback {
145 public:
146 OSThreadSamplerCallback(OSThreadSampler& sampler, const os::SuspendedThreadTaskContext &context) :
147 _sampler(sampler), _context(context) {
148 }
149 virtual void call() {
150 _sampler.protected_task(_context);
151 }
152 private:
153 OSThreadSampler& _sampler;
154 const os::SuspendedThreadTaskContext& _context;
155};
156
157void OSThreadSampler::do_task(const os::SuspendedThreadTaskContext& context) {
158#ifndef ASSERT1
159 guarantee(JfrOptionSet::sample_protection(), "Sample Protection should be on in product builds")do { if (!(JfrOptionSet::sample_protection())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 159, "guarantee(" "JfrOptionSet::sample_protection()" ") failed"
, "Sample Protection should be on in product builds"); ::breakpoint
(); } } while (0)
;
160#endif
161 assert(_suspend_time.value() == 0, "already timestamped!")do { if (!(_suspend_time.value() == 0)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 161, "assert(" "_suspend_time.value() == 0" ") failed", "already timestamped!"
); ::breakpoint(); } } while (0)
;
162 _suspend_time = JfrTicks::now();
163
164 if (JfrOptionSet::sample_protection()) {
165 OSThreadSamplerCallback cb(*this, context);
166 os::ThreadCrashProtection crash_protection;
167 if (!crash_protection.call(cb)) {
168 log_error(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Thread method sampler crashed");
169 }
170 } else {
171 protected_task(context);
172 }
173}
174
175/*
176* From this method and down the call tree we attempt to protect against crashes
177* using a signal handler / __try block. Don't take locks, rely on destructors or
178* leave memory (in case of signal / exception) in an inconsistent state. */
179void OSThreadSampler::protected_task(const os::SuspendedThreadTaskContext& context) {
180 JavaThread* jth = JavaThread::cast(context.thread());
181 // Skip sample if we signaled a thread that moved to other state
182 if (!thread_state_in_java(jth)) {
183 return;
184 }
185 JfrGetCallTrace trace(true, jth);
186 frame topframe;
187 if (trace.get_topframe(context.ucontext(), topframe)) {
188 if (_stacktrace.record_thread(*jth, topframe)) {
189 /* If we managed to get a topframe and a stacktrace, create an event
190 * and put it into our array. We can't call Jfr::_stacktraces.add()
191 * here since it would allocate memory using malloc. Doing so while
192 * the stopped thread is inside malloc would deadlock. */
193 _success = true;
194 EventExecutionSample *ev = _closure.next_event();
195 ev->set_starttime(_suspend_time);
196 ev->set_endtime(_suspend_time); // fake to not take an end time
197 ev->set_sampledThread(JFR_THREAD_ID(jth)((jth)->jfr_thread_local()->thread_id()));
198 ev->set_state(static_cast<u8>(java_lang_Thread::get_thread_status(_thread_oop)));
199 }
200 }
201}
202
203void OSThreadSampler::take_sample() {
204 run();
205}
206
207class JfrNativeSamplerCallback : public os::CrashProtectionCallback {
208 public:
209 JfrNativeSamplerCallback(JfrThreadSampleClosure& closure, JavaThread* jt, JfrStackFrame* frames, u4 max_frames) :
210 _closure(closure), _jt(jt), _thread_oop(jt->threadObj()), _stacktrace(frames, max_frames), _success(false) {
211 }
212 virtual void call();
213 bool success() { return _success; }
214 JfrStackTrace& stacktrace() { return _stacktrace; }
215
216 private:
217 JfrThreadSampleClosure& _closure;
218 JavaThread* _jt;
219 oop _thread_oop;
220 JfrStackTrace _stacktrace;
221 bool _success;
222};
223
224static void write_native_event(JfrThreadSampleClosure& closure, JavaThread* jt, oop thread_oop) {
225 EventNativeMethodSample *ev = closure.next_event_native();
226 ev->set_starttime(JfrTicks::now());
227 ev->set_sampledThread(JFR_THREAD_ID(jt)((jt)->jfr_thread_local()->thread_id()));
228 ev->set_state(static_cast<u8>(java_lang_Thread::get_thread_status(thread_oop)));
229}
230
231void JfrNativeSamplerCallback::call() {
232 // When a thread is only attach it will be native without a last java frame
233 if (!_jt->has_last_Java_frame()) {
234 return;
235 }
236
237 frame topframe = _jt->last_frame();
238 frame first_java_frame;
239 Method* method = NULL__null;
240 JfrGetCallTrace gct(false, _jt);
241 if (!gct.find_top_frame(topframe, &method, first_java_frame)) {
242 return;
243 }
244 if (method == NULL__null) {
245 return;
246 }
247 topframe = first_java_frame;
248 _success = _stacktrace.record_thread(*_jt, topframe);
249 if (_success) {
250 write_native_event(_closure, _jt, _thread_oop);
251 }
252}
253
254bool JfrThreadSampleClosure::sample_thread_in_java(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
255 OSThreadSampler sampler(thread, *this, frames, max_frames);
256 sampler.take_sample();
257 /* We don't want to allocate any memory using malloc/etc while the thread
258 * is stopped, so everything is stored in stack allocated memory until this
259 * point where the thread has been resumed again, if the sampling was a success
260 * we need to store the stacktrace in the stacktrace repository and update
261 * the event with the id that was returned. */
262 if (!sampler.success()) {
263 return false;
264 }
265 EventExecutionSample *event = &_events[_added_java - 1];
266 traceid id = JfrStackTraceRepository::add(sampler.stacktrace());
267 assert(id != 0, "Stacktrace id should not be 0")do { if (!(id != 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 267, "assert(" "id != 0" ") failed", "Stacktrace id should not be 0"
); ::breakpoint(); } } while (0)
;
268 event->set_stackTrace(id);
269 return true;
270}
271
272bool JfrThreadSampleClosure::sample_thread_in_native(JavaThread* thread, JfrStackFrame* frames, u4 max_frames) {
273 JfrNativeSamplerCallback cb(*this, thread, frames, max_frames);
274 if (JfrOptionSet::sample_protection()) {
275 os::ThreadCrashProtection crash_protection;
276 if (!crash_protection.call(cb)) {
277 log_error(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Thread method sampler crashed for native");
278 }
279 } else {
280 cb.call();
281 }
282 if (!cb.success()) {
283 return false;
284 }
285 EventNativeMethodSample *event = &_events_native[_added_native - 1];
286 traceid id = JfrStackTraceRepository::add(cb.stacktrace());
287 assert(id != 0, "Stacktrace id should not be 0")do { if (!(id != 0)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 287, "assert(" "id != 0" ") failed", "Stacktrace id should not be 0"
); ::breakpoint(); } } while (0)
;
288 event->set_stackTrace(id);
289 return true;
290}
291
292static const uint MAX_NR_OF_JAVA_SAMPLES = 5;
293static const uint MAX_NR_OF_NATIVE_SAMPLES = 1;
294
295void JfrThreadSampleClosure::commit_events(JfrSampleType type) {
296 if (JAVA_SAMPLE == type) {
297 assert(_added_java > 0 && _added_java <= MAX_NR_OF_JAVA_SAMPLES, "invariant")do { if (!(_added_java > 0 && _added_java <= MAX_NR_OF_JAVA_SAMPLES
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 297, "assert(" "_added_java > 0 && _added_java <= MAX_NR_OF_JAVA_SAMPLES"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
298 for (uint i = 0; i < _added_java; ++i) {
299 _events[i].commit();
300 }
301 } else {
302 assert(NATIVE_SAMPLE == type, "invariant")do { if (!(NATIVE_SAMPLE == type)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 302, "assert(" "NATIVE_SAMPLE == type" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
303 assert(_added_native > 0 && _added_native <= MAX_NR_OF_NATIVE_SAMPLES, "invariant")do { if (!(_added_native > 0 && _added_native <=
MAX_NR_OF_NATIVE_SAMPLES)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 303, "assert(" "_added_native > 0 && _added_native <= MAX_NR_OF_NATIVE_SAMPLES"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
304 for (uint i = 0; i < _added_native; ++i) {
305 _events_native[i].commit();
306 }
307 }
308}
309
310JfrThreadSampleClosure::JfrThreadSampleClosure(EventExecutionSample* events, EventNativeMethodSample* events_native) :
311 _events(events),
312 _events_native(events_native),
313 _self(Thread::current()),
314 _added_java(0),
315 _added_native(0) {
316}
317
318class JfrThreadSampler : public NonJavaThread {
319 friend class JfrThreadSampling;
320 private:
321 Semaphore _sample;
322 Thread* _sampler_thread;
323 JfrStackFrame* const _frames;
324 JavaThread* _last_thread_java;
325 JavaThread* _last_thread_native;
326 size_t _interval_java;
327 size_t _interval_native;
328 const size_t _min_size; // for enqueue buffer monitoring
329 const size_t _renew_size;
330 int _cur_index;
331 const u4 _max_frames;
332 volatile bool _disenrolled;
333
334 const JfrBuffer* get_enqueue_buffer();
335 const JfrBuffer* renew_if_full(const JfrBuffer* enqueue_buffer);
336
337 JavaThread* next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current);
338 void task_stacktrace(JfrSampleType type, JavaThread** last_thread);
339 JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames);
340 ~JfrThreadSampler();
341
342 void start_thread();
343
344 void enroll();
345 void disenroll();
346 void set_java_interval(size_t interval) { _interval_java = interval; };
347 void set_native_interval(size_t interval) { _interval_native = interval; };
348 size_t get_java_interval() { return _interval_java; };
349 size_t get_native_interval() { return _interval_native; };
350 protected:
351 virtual void post_run();
352 public:
353 virtual const char* name() const { return "JFR Thread Sampler"; }
354 virtual const char* type_name() const { return "JfrThreadSampler"; }
355 bool is_JfrSampler_thread() const { return true; }
356 void run();
357 static Monitor* transition_block() { return JfrThreadSampler_lock; }
358 static void on_javathread_suspend(JavaThread* thread);
359};
360
361static void clear_transition_block(JavaThread* jt) {
362 assert(Threads_lock->owned_by_self(), "Holding the thread table lock.")do { if (!(Threads_lock->owned_by_self())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 362, "assert(" "Threads_lock->owned_by_self()" ") failed"
, "Holding the thread table lock."); ::breakpoint(); } } while
(0)
;
363 jt->clear_trace_flag();
364 JfrThreadLocal* const tl = jt->jfr_thread_local();
365 MutexLocker ml(JfrThreadSampler::transition_block(), Mutex::_no_safepoint_check_flag);
366 if (tl->is_trace_block()) {
367 JfrThreadSampler::transition_block()->notify();
368 }
369}
370
371static bool is_excluded(JavaThread* thread) {
372 assert(thread != NULL, "invariant")do { if (!(thread != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 372, "assert(" "thread != __null" ") failed", "invariant");
::breakpoint(); } } while (0)
;
373 return thread->is_hidden_from_external_view() || thread->in_deopt_handler() || thread->jfr_thread_local()->is_excluded();
374}
375
376bool JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type) {
377 assert(Threads_lock->owned_by_self(), "Holding the thread table lock.")do { if (!(Threads_lock->owned_by_self())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 377, "assert(" "Threads_lock->owned_by_self()" ") failed"
, "Holding the thread table lock."); ::breakpoint(); } } while
(0)
;
378 if (is_excluded(thread)) {
379 return false;
380 }
381
382 bool ret = false;
383 thread->set_trace_flag(); // Provides StoreLoad, needed to keep read of thread state from floating up.
384 if (JAVA_SAMPLE == type) {
385 if (thread_state_in_java(thread)) {
386 ret = sample_thread_in_java(thread, frames, max_frames);
387 }
388 } else {
389 assert(NATIVE_SAMPLE == type, "invariant")do { if (!(NATIVE_SAMPLE == type)) { (*g_assert_poison) = 'X'
;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 389, "assert(" "NATIVE_SAMPLE == type" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
390 if (thread_state_in_native(thread)) {
391 ret = sample_thread_in_native(thread, frames, max_frames);
392 }
393 }
394 clear_transition_block(thread);
395 return ret;
396}
397
398JfrThreadSampler::JfrThreadSampler(size_t interval_java, size_t interval_native, u4 max_frames) :
399 _sample(),
400 _sampler_thread(NULL__null),
401 _frames(JfrCHeapObj::new_array<JfrStackFrame>(max_frames)),
402 _last_thread_java(NULL__null),
403 _last_thread_native(NULL__null),
404 _interval_java(interval_java),
405 _interval_native(interval_native),
406 _min_size(JfrOptionSet::stackdepth() * sizeof(intptr_t)),
407 _renew_size(_min_size * 2),
408 _cur_index(-1),
409 _max_frames(max_frames),
410 _disenrolled(true) {
411}
412
413JfrThreadSampler::~JfrThreadSampler() {
414 JfrCHeapObj::free(_frames, sizeof(JfrStackFrame) * _max_frames);
415}
416
417static inline bool is_released(JavaThread* jt) {
418 return !jt->is_trace_suspend();
419}
420
421void JfrThreadSampler::on_javathread_suspend(JavaThread* thread) {
422 if (is_released(thread)) {
423 return;
424 }
425 JfrThreadLocal* const tl = thread->jfr_thread_local();
426 MonitorLocker ml(transition_block(), Mutex::_no_safepoint_check_flag);
427 tl->set_trace_block();
428 while (!is_released(thread)) {
429 ml.wait();
430 }
431 tl->clear_trace_block();
432}
433
434JavaThread* JfrThreadSampler::next_thread(ThreadsList* t_list, JavaThread* first_sampled, JavaThread* current) {
435 assert(t_list != NULL, "invariant")do { if (!(t_list != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 435, "assert(" "t_list != __null" ") failed", "invariant");
::breakpoint(); } } while (0)
;
436 assert(Threads_lock->owned_by_self(), "Holding the thread table lock.")do { if (!(Threads_lock->owned_by_self())) { (*g_assert_poison
) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 436, "assert(" "Threads_lock->owned_by_self()" ") failed"
, "Holding the thread table lock."); ::breakpoint(); } } while
(0)
;
437 assert(_cur_index >= -1 && (uint)_cur_index + 1 <= t_list->length(), "invariant")do { if (!(_cur_index >= -1 && (uint)_cur_index + 1
<= t_list->length())) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 437, "assert(" "_cur_index >= -1 && (uint)_cur_index + 1 <= t_list->length()"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
438 assert((current == NULL && -1 == _cur_index) || (t_list->find_index_of_JavaThread(current) == _cur_index), "invariant")do { if (!((current == __null && -1 == _cur_index) ||
(t_list->find_index_of_JavaThread(current) == _cur_index)
)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 438, "assert(" "(current == __null && -1 == _cur_index) || (t_list->find_index_of_JavaThread(current) == _cur_index)"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
439 if ((uint)_cur_index + 1 == t_list->length()) {
440 // wrap
441 _cur_index = 0;
442 } else {
443 _cur_index++;
444 }
445 assert(_cur_index >= 0 && (uint)_cur_index < t_list->length(), "invariant")do { if (!(_cur_index >= 0 && (uint)_cur_index <
t_list->length())) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 445, "assert(" "_cur_index >= 0 && (uint)_cur_index < t_list->length()"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
446 JavaThread* const next = t_list->thread_at(_cur_index);
447 return next != first_sampled ? next : NULL__null;
448}
449
450void JfrThreadSampler::start_thread() {
451 if (os::create_thread(this, os::os_thread)) {
452 os::start_thread(this);
453 } else {
454 log_error(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Error))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Error>
("Failed to create thread for thread sampling");
455 }
456}
457
458void JfrThreadSampler::enroll() {
459 if (_disenrolled) {
460 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("Enrolling thread sampler");
461 _sample.signal();
462 _disenrolled = false;
463 }
464}
465
466void JfrThreadSampler::disenroll() {
467 if (!_disenrolled) {
468 _sample.wait();
469 _disenrolled = true;
470 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("Disenrolling thread sampler");
471 }
472}
473
474static jlong get_monotonic_ms() {
475 return os::javaTimeNanos() / 1000000;
476}
477
478void JfrThreadSampler::run() {
479 assert(_sampler_thread == NULL, "invariant")do { if (!(_sampler_thread == __null)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 479, "assert(" "_sampler_thread == __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
480
481 _sampler_thread = this;
482
483 jlong last_java_ms = get_monotonic_ms();
484 jlong last_native_ms = last_java_ms;
485 while (true) {
486 if (!_sample.trywait()) {
487 // disenrolled
488 _sample.wait();
489 last_java_ms = get_monotonic_ms();
490 last_native_ms = last_java_ms;
491 }
492 _sample.signal();
493 jlong java_interval = _interval_java == 0 ? max_jlong : MAX2<jlong>(_interval_java, 1);
494 jlong native_interval = _interval_native == 0 ? max_jlong : MAX2<jlong>(_interval_native, 1);
495
496 jlong now_ms = get_monotonic_ms();
497
498 /*
499 * Let I be java_interval or native_interval.
500 * Let L be last_java_ms or last_native_ms.
501 * Let N be now_ms.
502 *
503 * Interval, I, might be max_jlong so the addition
504 * could potentially overflow without parenthesis (UB). Also note that
505 * L - N < 0. Avoid UB, by adding parenthesis.
506 */
507 jlong next_j = java_interval + (last_java_ms - now_ms);
508 jlong next_n = native_interval + (last_native_ms - now_ms);
509
510 jlong sleep_to_next = MIN2<jlong>(next_j, next_n);
511
512 if (sleep_to_next > 0) {
513 os::naked_short_sleep(sleep_to_next);
514 }
515
516 if ((next_j - sleep_to_next) <= 0) {
517 task_stacktrace(JAVA_SAMPLE, &_last_thread_java);
518 last_java_ms = get_monotonic_ms();
519 }
520 if ((next_n - sleep_to_next) <= 0) {
521 task_stacktrace(NATIVE_SAMPLE, &_last_thread_native);
522 last_native_ms = get_monotonic_ms();
523 }
524 }
525}
526
527void JfrThreadSampler::post_run() {
528 this->NonJavaThread::post_run();
529 delete this;
530}
531
532const JfrBuffer* JfrThreadSampler::get_enqueue_buffer() {
533 const JfrBuffer* buffer = JfrTraceIdLoadBarrier::get_enqueue_buffer(this);
534 return buffer != nullptr ? renew_if_full(buffer) : JfrTraceIdLoadBarrier::renew_enqueue_buffer(_renew_size, this);
535}
536
537const JfrBuffer* JfrThreadSampler::renew_if_full(const JfrBuffer* enqueue_buffer) {
538 assert(enqueue_buffer != nullptr, "invariant")do { if (!(enqueue_buffer != nullptr)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 538, "assert(" "enqueue_buffer != nullptr" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
539 return enqueue_buffer->free_size() < _min_size ? JfrTraceIdLoadBarrier::renew_enqueue_buffer(_renew_size, this) : enqueue_buffer;
540}
541
542void JfrThreadSampler::task_stacktrace(JfrSampleType type, JavaThread** last_thread) {
543 ResourceMark rm;
544 EventExecutionSample samples[MAX_NR_OF_JAVA_SAMPLES];
545 EventNativeMethodSample samples_native[MAX_NR_OF_NATIVE_SAMPLES];
546 JfrThreadSampleClosure sample_task(samples, samples_native);
547
548 const uint sample_limit = JAVA_SAMPLE == type ? MAX_NR_OF_JAVA_SAMPLES : MAX_NR_OF_NATIVE_SAMPLES;
549 uint num_samples = 0;
550 JavaThread* start = NULL__null;
551 {
552 elapsedTimer sample_time;
553 sample_time.start();
554 {
555 MutexLocker tlock(Threads_lock);
556 ThreadsListHandle tlh;
557 // Resolve a sample session relative start position index into the thread list array.
558 // In cases where the last sampled thread is NULL or not-NULL but stale, find_index() returns -1.
559 _cur_index = tlh.list()->find_index_of_JavaThread(*last_thread);
560 JavaThread* current = _cur_index != -1 ? *last_thread : NULL__null;
561
562 // Explicitly monitor the available space of the thread-local buffer used by the load barrier
563 // for enqueuing klasses as part of tagging methods. We do this because if space becomes sparse,
564 // we cannot rely on the implicit allocation of a new buffer as part of the regular tag mechanism.
565 // If the free list is empty, a malloc could result, and the problem with that is that the thread
566 // we have suspended could be the holder of the malloc lock. Instead, the buffer is pre-emptively
567 // renewed before thread suspension.
568 const JfrBuffer* enqueue_buffer = get_enqueue_buffer();
569 assert(enqueue_buffer != nullptr, "invariant")do { if (!(enqueue_buffer != nullptr)) { (*g_assert_poison) =
'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 569, "assert(" "enqueue_buffer != nullptr" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
570
571 while (num_samples < sample_limit) {
572 current = next_thread(tlh.list(), start, current);
573 if (current == NULL__null) {
574 break;
575 }
576 if (start == NULL__null) {
577 start = current; // remember the thread where we started to attempt sampling
578 }
579 if (current->is_Compiler_thread()) {
580 continue;
581 }
582 assert(enqueue_buffer->free_size() >= _min_size, "invariant")do { if (!(enqueue_buffer->free_size() >= _min_size)) {
(*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 582, "assert(" "enqueue_buffer->free_size() >= _min_size"
") failed", "invariant"); ::breakpoint(); } } while (0)
;
583 if (sample_task.do_sample_thread(current, _frames, _max_frames, type)) {
584 num_samples++;
585 }
586 enqueue_buffer = renew_if_full(enqueue_buffer);
587 }
588 *last_thread = current; // remember the thread we last attempted to sample
589 }
590 sample_time.stop();
591 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("JFR thread sampling done in %3.7f secs with %d java %d native samples",
592 sample_time.seconds(), sample_task.java_entries(), sample_task.native_entries());
593 }
594 if (num_samples > 0) {
595 sample_task.commit_events(type);
596 }
597}
598
599static JfrThreadSampling* _instance = NULL__null;
600
601JfrThreadSampling& JfrThreadSampling::instance() {
602 return *_instance;
5
Returning null reference
603}
604
605JfrThreadSampling* JfrThreadSampling::create() {
606 assert(_instance == NULL, "invariant")do { if (!(_instance == __null)) { (*g_assert_poison) = 'X';;
report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 606, "assert(" "_instance == __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
607 _instance = new JfrThreadSampling();
608 return _instance;
609}
610
611void JfrThreadSampling::destroy() {
612 if (_instance != NULL__null) {
613 delete _instance;
614 _instance = NULL__null;
615 }
616}
617
618JfrThreadSampling::JfrThreadSampling() : _sampler(NULL__null) {}
619
620JfrThreadSampling::~JfrThreadSampling() {
621 if (_sampler != NULL__null) {
622 _sampler->disenroll();
623 }
624}
625
626static void log(size_t interval_java, size_t interval_native) {
627 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("Updated thread sampler for java: " SIZE_FORMAT"%" "l" "u" " ms, native " SIZE_FORMAT"%" "l" "u" " ms", interval_java, interval_native);
628}
629
630void JfrThreadSampling::start_sampler(size_t interval_java, size_t interval_native) {
631 assert(_sampler == NULL, "invariant")do { if (!(_sampler == __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 631, "assert(" "_sampler == __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
632 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("Enrolling thread sampler");
633 _sampler = new JfrThreadSampler(interval_java, interval_native, JfrOptionSet::stackdepth());
634 _sampler->start_thread();
635 _sampler->enroll();
636}
637
638void JfrThreadSampling::set_sampling_interval(bool java_interval, size_t period) {
639 size_t interval_java = 0;
640 size_t interval_native = 0;
641 if (_sampler != NULL__null) {
642 interval_java = _sampler->get_java_interval();
643 interval_native = _sampler->get_native_interval();
644 }
645 if (java_interval) {
646 interval_java = period;
647 } else {
648 interval_native = period;
649 }
650 if (interval_java > 0 || interval_native > 0) {
651 if (_sampler == NULL__null) {
652 log_trace(jfr)(!(LogImpl<(LogTag::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)
>::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag
::_jfr), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG
), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel
::Trace>
("Creating thread sampler for java:%zu ms, native %zu ms", interval_java, interval_native);
653 start_sampler(interval_java, interval_native);
654 } else {
655 _sampler->set_java_interval(interval_java);
656 _sampler->set_native_interval(interval_native);
657 _sampler->enroll();
658 }
659 assert(_sampler != NULL, "invariant")do { if (!(_sampler != __null)) { (*g_assert_poison) = 'X';; report_vm_error
("/home/daniel/Projects/java/jdk/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp"
, 659, "assert(" "_sampler != __null" ") failed", "invariant"
); ::breakpoint(); } } while (0)
;
660 log(interval_java, interval_native);
661 } else if (_sampler != NULL__null) {
662 _sampler->disenroll();
663 }
664}
665
666void JfrThreadSampling::set_java_sample_interval(size_t period) {
667 if (_instance == NULL__null && 0 == period) {
668 return;
669 }
670 instance().set_sampling_interval(true, period);
671}
672
673void JfrThreadSampling::set_native_sample_interval(size_t period) {
674 if (_instance == NULL__null && 0 == period) {
1
Assuming '_instance' is equal to NULL
2
Assuming 'period' is not equal to 0
3
Taking false branch
675 return;
676 }
677 instance().set_sampling_interval(false, period);
4
Calling 'JfrThreadSampling::instance'
678}
679
680void JfrThreadSampling::on_javathread_suspend(JavaThread* thread) {
681 JfrThreadSampler::on_javathread_suspend(thread);
682}