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