Mon, 19 Aug 2019 10:11:31 +0200
8229401: Fix JFR code cache test failures
8223689: Add JFR Thread Sampling Support
8223690: Add JFR BiasedLock Event Support
8223691: Add JFR G1 Region Type Change Event Support
8223692: Add JFR G1 Heap Summary Event Support
Summary: Backport JFR from JDK11, additional fixes
Reviewed-by: neugens, apetushkov
Contributed-by: denghui.ddh@alibaba-inc.com
1 /*
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
25 #include "precompiled.hpp"
26 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
27 #include "jfr/recorder/checkpoint/types/jfrThreadGroup.hpp"
28 #include "jfr/utilities/jfrResourceManager.hpp"
29 #include "jfr/utilities/jfrTypes.hpp"
30 #include "runtime/handles.inline.hpp"
31 #include "runtime/jniHandles.hpp"
32 #include "runtime/safepoint.hpp"
33 #include "runtime/semaphore.hpp"
34 #include "utilities/growableArray.hpp"
36 class ThreadGroupExclusiveAccess : public StackObj {
37 private:
38 static Semaphore _mutex_semaphore;
39 public:
40 ThreadGroupExclusiveAccess() { _mutex_semaphore.wait(); }
41 ~ThreadGroupExclusiveAccess() { _mutex_semaphore.signal(); }
42 };
44 Semaphore ThreadGroupExclusiveAccess::_mutex_semaphore(1);
45 JfrThreadGroup* JfrThreadGroup::_instance = NULL;
47 class JfrThreadGroupPointers : public ResourceObj {
48 private:
49 const Handle _thread_group_handle;
50 jweak _thread_group_weak_ref;
51 public:
52 JfrThreadGroupPointers(Handle thread_group_handle, jweak thread_group_weak_ref);
53 Handle thread_group_handle() const;
54 jweak thread_group_weak_ref() const;
55 oopDesc* const thread_group_oop() const;
56 jweak transfer_weak_global_handle_ownership();
57 void clear_weak_ref();
58 };
60 JfrThreadGroupPointers::JfrThreadGroupPointers(Handle thread_group_handle, jweak thread_group_weak_ref) :
61 _thread_group_handle(thread_group_handle),
62 _thread_group_weak_ref(thread_group_weak_ref) {}
64 Handle JfrThreadGroupPointers::thread_group_handle() const {
65 return _thread_group_handle;
66 }
68 jweak JfrThreadGroupPointers::thread_group_weak_ref() const {
69 return _thread_group_weak_ref;
70 }
72 oopDesc* const JfrThreadGroupPointers::thread_group_oop() const {
73 assert(_thread_group_weak_ref == NULL ||
74 JNIHandles::resolve_non_null(_thread_group_weak_ref) == _thread_group_handle(), "invariant");
75 return _thread_group_handle();
76 }
78 jweak JfrThreadGroupPointers::transfer_weak_global_handle_ownership() {
79 jweak temp = _thread_group_weak_ref;
80 _thread_group_weak_ref = NULL;
81 return temp;
82 }
84 void JfrThreadGroupPointers::clear_weak_ref() {
85 if (NULL != _thread_group_weak_ref) {
86 JNIHandles::destroy_weak_global(_thread_group_weak_ref);
87 }
88 }
90 class JfrThreadGroupsHelper : public ResourceObj {
91 private:
92 static const int invalid_iterator_pos = -1;
93 GrowableArray<JfrThreadGroupPointers*>* _thread_group_hierarchy;
94 int _current_iterator_pos;
96 int populate_thread_group_hierarchy(const JavaThread* jt, Thread* current);
97 JfrThreadGroupPointers& at(int index);
99 public:
100 JfrThreadGroupsHelper(const JavaThread* jt, Thread* current);
101 ~JfrThreadGroupsHelper();
102 JfrThreadGroupPointers& next();
103 bool is_valid() const;
104 bool has_next() const;
105 };
107 JfrThreadGroupsHelper::JfrThreadGroupsHelper(const JavaThread* jt, Thread* current) {
108 _thread_group_hierarchy = new GrowableArray<JfrThreadGroupPointers*>(10, false, mtTracing);
109 _current_iterator_pos = populate_thread_group_hierarchy(jt, current) - 1;
110 }
112 JfrThreadGroupsHelper::~JfrThreadGroupsHelper() {
113 assert(_current_iterator_pos == invalid_iterator_pos, "invariant");
114 for (int i = 0; i < _thread_group_hierarchy->length(); ++i) {
115 _thread_group_hierarchy->at(i)->clear_weak_ref();
116 }
117 }
119 JfrThreadGroupPointers& JfrThreadGroupsHelper::at(int index) {
120 assert(_thread_group_hierarchy != NULL, "invariant");
121 assert(index > invalid_iterator_pos && index < _thread_group_hierarchy->length(), "invariant");
122 return *(_thread_group_hierarchy->at(index));
123 }
125 bool JfrThreadGroupsHelper::has_next() const {
126 return _current_iterator_pos > invalid_iterator_pos;
127 }
129 bool JfrThreadGroupsHelper::is_valid() const {
130 return (_thread_group_hierarchy != NULL && _thread_group_hierarchy->length() > 0);
131 }
133 JfrThreadGroupPointers& JfrThreadGroupsHelper::next() {
134 assert(is_valid(), "invariant");
135 return at(_current_iterator_pos--);
136 }
138 /*
139 * If not at a safepoint, we create global weak references for
140 * all reachable threadgroups for this thread.
141 * If we are at a safepoint, the caller is the VMThread during
142 * JFR checkpointing. It can use naked oops, because nothing
143 * will move before the list of threadgroups is cleared and
144 * mutator threads restarted. The threadgroup list is cleared
145 * later by the VMThread as one of the final steps in JFR checkpointing
146 * (not here).
147 */
148 int JfrThreadGroupsHelper::populate_thread_group_hierarchy(const JavaThread* jt, Thread* current) {
149 assert(jt != NULL && jt->is_Java_thread(), "invariant");
150 assert(current != NULL, "invariant");
151 assert(_thread_group_hierarchy != NULL, "invariant");
153 // immediate thread group
154 Handle thread_group_handle(current, java_lang_Thread::threadGroup(jt->threadObj()));
155 if (thread_group_handle == NULL) {
156 return 0;
157 }
159 const bool use_weak_handles = !SafepointSynchronize::is_at_safepoint();
160 jweak thread_group_weak_ref = use_weak_handles ? JNIHandles::make_weak_global(thread_group_handle) : NULL;
162 JfrThreadGroupPointers* thread_group_pointers = new JfrThreadGroupPointers(thread_group_handle, thread_group_weak_ref);
163 _thread_group_hierarchy->append(thread_group_pointers);
164 // immediate parent thread group
165 oop parent_thread_group_obj = java_lang_ThreadGroup::parent(thread_group_handle());
166 Handle parent_thread_group_handle(current, parent_thread_group_obj);
168 // and check parents parents...
169 while (!(parent_thread_group_handle == NULL)) {
170 const jweak parent_group_weak_ref = use_weak_handles ? JNIHandles::make_weak_global(parent_thread_group_handle) : NULL;
171 thread_group_pointers = new JfrThreadGroupPointers(parent_thread_group_handle, parent_group_weak_ref);
172 _thread_group_hierarchy->append(thread_group_pointers);
173 parent_thread_group_obj = java_lang_ThreadGroup::parent(parent_thread_group_handle());
174 parent_thread_group_handle = Handle(current, parent_thread_group_obj);
175 }
176 return _thread_group_hierarchy->length();
177 }
179 static traceid next_id() {
180 static traceid _current_threadgroup_id = 0;
181 return ++_current_threadgroup_id;
182 }
184 class JfrThreadGroup::JfrThreadGroupEntry : public JfrCHeapObj {
185 friend class JfrThreadGroup;
186 private:
187 traceid _thread_group_id;
188 traceid _parent_group_id;
189 char* _thread_group_name; // utf8 format
190 // If an entry is created during a safepoint, the
191 // _thread_group_oop contains a direct oop to
192 // the java.lang.ThreadGroup object.
193 // If an entry is created on javathread exit time (not at safepoint),
194 // _thread_group_weak_ref contains a JNI weak global handle
195 // indirection to the java.lang.ThreadGroup object.
196 // Note: we cannot use a union here since CHECK_UNHANDLED_OOPS makes oop have
197 // a ctor which isn't allowed in a union by the SunStudio compiler
198 oop _thread_group_oop;
199 jweak _thread_group_weak_ref;
201 JfrThreadGroupEntry(const char* tgstr, JfrThreadGroupPointers& ptrs);
202 ~JfrThreadGroupEntry();
204 traceid thread_group_id() const { return _thread_group_id; }
205 void set_thread_group_id(traceid tgid) { _thread_group_id = tgid; }
207 const char* const thread_group_name() const { return _thread_group_name; }
208 void set_thread_group_name(const char* tgname);
210 traceid parent_group_id() const { return _parent_group_id; }
211 void set_parent_group_id(traceid pgid) { _parent_group_id = pgid; }
213 void set_thread_group(JfrThreadGroupPointers& ptrs);
214 bool is_equal(const JfrThreadGroupPointers& ptrs) const;
215 const oop thread_group() const;
216 };
218 JfrThreadGroup::JfrThreadGroupEntry::JfrThreadGroupEntry(const char* tgname, JfrThreadGroupPointers& ptrs) :
219 _thread_group_id(0),
220 _parent_group_id(0),
221 _thread_group_name(NULL),
222 _thread_group_oop(NULL),
223 _thread_group_weak_ref(NULL) {
224 set_thread_group_name(tgname);
225 set_thread_group(ptrs);
226 }
228 JfrThreadGroup::JfrThreadGroupEntry::~JfrThreadGroupEntry() {
229 if (_thread_group_name != NULL) {
230 JfrCHeapObj::free(_thread_group_name, strlen(_thread_group_name) + 1);
231 }
232 if (_thread_group_weak_ref != NULL) {
233 JNIHandles::destroy_weak_global(_thread_group_weak_ref);
234 }
235 }
237 void JfrThreadGroup::JfrThreadGroupEntry::set_thread_group_name(const char* tgname) {
238 assert(_thread_group_name == NULL, "invariant");
239 if (tgname != NULL) {
240 size_t len = strlen(tgname);
241 _thread_group_name = JfrCHeapObj::new_array<char>(len+1);
242 strncpy(_thread_group_name, tgname, len);
243 _thread_group_name[len] = '\0';
244 }
245 }
247 const oop JfrThreadGroup::JfrThreadGroupEntry::thread_group() const {
248 return _thread_group_weak_ref != NULL ? JNIHandles::resolve(_thread_group_weak_ref) : _thread_group_oop;
249 }
251 void JfrThreadGroup::JfrThreadGroupEntry::set_thread_group(JfrThreadGroupPointers& ptrs) {
252 _thread_group_weak_ref = ptrs.transfer_weak_global_handle_ownership();
253 if (_thread_group_weak_ref == NULL) {
254 _thread_group_oop = ptrs.thread_group_oop();
255 assert(_thread_group_oop != NULL, "invariant");
256 } else {
257 _thread_group_oop = NULL;
258 }
259 }
261 JfrThreadGroup::JfrThreadGroup() : _list(NULL) {
262 _list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<JfrThreadGroupEntry*>(30, true);
263 }
265 JfrThreadGroup::~JfrThreadGroup() {
266 assert(SafepointSynchronize::is_at_safepoint(), "invariant");
267 if (_list != NULL) {
268 for (int i = 0; i < _list->length(); i++) {
269 JfrThreadGroupEntry* e = _list->at(i);
270 delete e;
271 }
272 delete _list;
273 }
274 }
276 JfrThreadGroup* JfrThreadGroup::instance() {
277 return _instance;
278 }
280 void JfrThreadGroup::set_instance(JfrThreadGroup* new_instance) {
281 _instance = new_instance;
282 }
284 traceid JfrThreadGroup::thread_group_id(const JavaThread* jt, Thread* current) {
285 ResourceMark rm(current);
286 HandleMark hm(current);
287 JfrThreadGroupsHelper helper(jt, current);
288 return helper.is_valid() ? thread_group_id_internal(helper) : 0;
289 }
291 traceid JfrThreadGroup::thread_group_id(JavaThread* jt) {
292 assert(!JfrStream_lock->owned_by_self(), "holding stream lock but should not hold it here");
293 return thread_group_id(jt, jt);
294 }
296 traceid JfrThreadGroup::thread_group_id_internal(JfrThreadGroupsHelper& helper) {
297 ThreadGroupExclusiveAccess lock;
298 JfrThreadGroup* tg_instance = instance();
299 if (tg_instance == NULL) {
300 tg_instance = new JfrThreadGroup();
301 if (tg_instance == NULL) {
302 return 0;
303 }
304 set_instance(tg_instance);
305 }
307 JfrThreadGroupEntry* tge = NULL;
308 int parent_thread_group_id = 0;
309 while (helper.has_next()) {
310 JfrThreadGroupPointers& ptrs = helper.next();
311 tge = tg_instance->find_entry(ptrs);
312 if (NULL == tge) {
313 tge = tg_instance->new_entry(ptrs);
314 assert(tge != NULL, "invariant");
315 tge->set_parent_group_id(parent_thread_group_id);
316 }
317 parent_thread_group_id = tge->thread_group_id();
318 }
319 // the last entry in the hierarchy is the immediate thread group
320 return tge->thread_group_id();
321 }
323 bool JfrThreadGroup::JfrThreadGroupEntry::is_equal(const JfrThreadGroupPointers& ptrs) const {
324 return ptrs.thread_group_oop() == thread_group();
325 }
327 JfrThreadGroup::JfrThreadGroupEntry*
328 JfrThreadGroup::find_entry(const JfrThreadGroupPointers& ptrs) const {
329 for (int index = 0; index < _list->length(); ++index) {
330 JfrThreadGroupEntry* curtge = _list->at(index);
331 if (curtge->is_equal(ptrs)) {
332 return curtge;
333 }
334 }
335 return (JfrThreadGroupEntry*) NULL;
336 }
338 // Assumes you already searched for the existence
339 // of a corresponding entry in find_entry().
340 JfrThreadGroup::JfrThreadGroupEntry*
341 JfrThreadGroup::new_entry(JfrThreadGroupPointers& ptrs) {
342 typeArrayOop tg_name = java_lang_ThreadGroup::name(ptrs.thread_group_oop());
343 JfrThreadGroupEntry* const tge =
344 new JfrThreadGroupEntry(UNICODE::as_utf8((jchar*) tg_name->base(T_CHAR), tg_name->length()), ptrs);
345 add_entry(tge);
346 return tge;
347 }
349 int JfrThreadGroup::add_entry(JfrThreadGroupEntry* tge) {
350 assert(tge != NULL, "attempting to add a null entry!");
351 assert(0 == tge->thread_group_id(), "id must be unassigned!");
352 tge->set_thread_group_id(next_id());
353 return _list->append(tge);
354 }
356 void JfrThreadGroup::write_thread_group_entries(JfrCheckpointWriter& writer) const {
357 assert(_list != NULL && !_list->is_empty(), "should not need be here!");
358 const int number_of_tg_entries = _list->length();
359 writer.write_count(number_of_tg_entries);
360 for (int index = 0; index < number_of_tg_entries; ++index) {
361 const JfrThreadGroupEntry* const curtge = _list->at(index);
362 writer.write_key(curtge->thread_group_id());
363 writer.write(curtge->parent_group_id());
364 writer.write(curtge->thread_group_name());
365 }
366 }
368 void JfrThreadGroup::write_selective_thread_group(JfrCheckpointWriter* writer, traceid thread_group_id) const {
369 assert(writer != NULL, "invariant");
370 assert(_list != NULL && !_list->is_empty(), "should not need be here!");
371 const int number_of_tg_entries = _list->length();
373 // save context
374 const JfrCheckpointContext ctx = writer->context();
375 writer->write_type(TYPE_THREADGROUP);
376 const jlong count_offset = writer->reserve(sizeof(u4)); // Don't know how many yet
377 int number_of_entries_written = 0;
378 for (int index = number_of_tg_entries - 1; index >= 0; --index) {
379 const JfrThreadGroupEntry* const curtge = _list->at(index);
380 if (thread_group_id == curtge->thread_group_id()) {
381 writer->write_key(curtge->thread_group_id());
382 writer->write(curtge->parent_group_id());
383 writer->write(curtge->thread_group_name());
384 ++number_of_entries_written;
385 thread_group_id = curtge->parent_group_id();
386 }
387 }
388 if (number_of_entries_written == 0) {
389 // nothing to write, restore context
390 writer->set_context(ctx);
391 return;
392 }
393 assert(number_of_entries_written > 0, "invariant");
394 writer->write_count(number_of_entries_written, count_offset);
395 }
397 // Write out JfrThreadGroup instance and then delete it
398 void JfrThreadGroup::serialize(JfrCheckpointWriter& writer) {
399 ThreadGroupExclusiveAccess lock;
400 JfrThreadGroup* tg_instance = instance();
401 assert(tg_instance != NULL, "invariant");
402 ResourceManager<JfrThreadGroup> tg_handle(tg_instance);
403 set_instance(NULL);
404 tg_handle->write_thread_group_entries(writer);
405 }
407 // for writing a particular thread group
408 void JfrThreadGroup::serialize(JfrCheckpointWriter* writer, traceid thread_group_id) {
409 assert(writer != NULL, "invariant");
410 ThreadGroupExclusiveAccess lock;
411 JfrThreadGroup* const tg_instance = instance();
412 assert(tg_instance != NULL, "invariant");
413 tg_instance->write_selective_thread_group(writer, thread_group_id);
414 }