1 /* 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "jfr/metadata/jfrSerializer.hpp" 27 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" 28 #include "jfr/recorder/repository/jfrChunkWriter.hpp" 29 #include "jfr/recorder/service/jfrOptionSet.hpp" 30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 31 #include "jfr/utilities/jfrTypes.hpp" 32 #include "memory/allocation.inline.hpp" 33 #include "runtime/mutexLocker.hpp" 34 #include "runtime/os.inline.hpp" 35 #include "runtime/safepoint.hpp" 36 #include "runtime/task.hpp" 37 #include "runtime/vframe.inline.hpp" 38 39 class vframeStreamSamples : public vframeStreamCommon { 40 public: 41 // constructor that starts with sender of frame fr (top_frame) 42 vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub); 43 void samples_next(); 44 void stop() {} 45 }; 46 47 vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) { 48 _stop_at_java_call_stub = stop_at_java_call_stub; 49 _frame = fr; 50 51 // We must always have a valid frame to start filling 52 bool filled_in = fill_from_frame(); 53 assert(filled_in, "invariant"); 54 } 55 56 // Solaris SPARC Compiler1 needs an additional check on the grandparent 57 // of the top_frame when the parent of the top_frame is interpreted and 58 // the grandparent is compiled. However, in this method we do not know 59 // the relationship of the current _frame relative to the top_frame so 60 // we implement a more broad sanity check. When the previous callee is 61 // interpreted and the current sender is compiled, we verify that the 62 // current sender is also walkable. If it is not walkable, then we mark 63 // the current vframeStream as at the end. 64 void vframeStreamSamples::samples_next() { 65 // handle frames with inlining 66 if (_mode == compiled_mode && 67 vframeStreamCommon::fill_in_compiled_inlined_sender()) { 68 return; 69 } 70 71 // handle general case 72 u4 loop_count = 0; 73 u4 loop_max = MAX_STACK_DEPTH * 2; 74 do { 75 loop_count++; 76 // By the time we get here we should never see unsafe but better safe then segv'd 77 if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) { 78 _mode = at_end_mode; 79 return; 80 } 81 _frame = _frame.sender(&_reg_map); 82 } while (!fill_from_frame()); 83 } 84 85 static JfrStackTraceRepository* _instance = NULL; 86 87 JfrStackTraceRepository& JfrStackTraceRepository::instance() { 88 return *_instance; 89 } 90 91 JfrStackTraceRepository* JfrStackTraceRepository::create() { 92 assert(_instance == NULL, "invariant"); 93 _instance = new JfrStackTraceRepository(); 94 return _instance; 95 } 96 97 void JfrStackTraceRepository::destroy() { 98 assert(_instance != NULL, "invarinat"); 99 delete _instance; 100 _instance = NULL; 101 } 102 103 JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) { 104 memset(_table, 0, sizeof(_table)); 105 } 106 class JfrFrameType : public JfrSerializer { 107 public: 108 void serialize(JfrCheckpointWriter& writer) { 109 writer.write_count(JfrStackFrame::NUM_FRAME_TYPES); 110 writer.write_key(JfrStackFrame::FRAME_INTERPRETER); 111 writer.write("Interpreted"); 112 writer.write_key(JfrStackFrame::FRAME_JIT); 113 writer.write("JIT compiled"); 114 writer.write_key(JfrStackFrame::FRAME_INLINE); 115 writer.write("Inlined"); 116 writer.write_key(JfrStackFrame::FRAME_NATIVE); 117 writer.write("Native"); 118 } 119 }; 120 121 bool JfrStackTraceRepository::initialize() { 122 return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType()); 123 } 124 125 size_t JfrStackTraceRepository::clear() { 126 MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 127 if (_entries == 0) { 128 return 0; 129 } 130 for (u4 i = 0; i < TABLE_SIZE; ++i) { 131 JfrStackTraceRepository::StackTrace* stacktrace = _table[i]; 132 while (stacktrace != NULL) { 133 JfrStackTraceRepository::StackTrace* next = stacktrace->next(); 134 delete stacktrace; 135 stacktrace = next; 136 } 137 } 138 memset(_table, 0, sizeof(_table)); 139 const size_t processed = _entries; 140 _entries = 0; 141 return processed; 142 } 143 144 traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) { 145 MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 146 const size_t index = stacktrace._hash % TABLE_SIZE; 147 const StackTrace* table_entry = _table[index]; 148 149 while (table_entry != NULL) { 150 if (table_entry->equals(stacktrace)) { 151 return table_entry->id(); 152 } 153 table_entry = table_entry->next(); 154 } 155 156 if (!stacktrace.have_lineno()) { 157 return 0; 158 } 159 160 traceid id = ++_next_id; 161 _table[index] = new StackTrace(id, stacktrace, _table[index]); 162 ++_entries; 163 return id; 164 } 165 166 traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) { 167 return instance().add_trace(stacktrace); 168 } 169 170 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) { 171 assert(thread == Thread::current(), "invariant"); 172 JfrThreadLocal* const tl = thread->jfr_thread_local(); 173 assert(tl != NULL, "invariant"); 174 if (tl->has_cached_stack_trace()) { 175 return tl->cached_stack_trace_id(); 176 } 177 if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) { 178 return 0; 179 } 180 JfrStackFrame* frames = tl->stackframes(); 181 if (frames == NULL) { 182 // pending oom 183 return 0; 184 } 185 assert(frames != NULL, "invariant"); 186 assert(tl->stackframes() == frames, "invariant"); 187 return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth()); 188 } 189 190 traceid JfrStackTraceRepository::record(Thread* thread, int skip, unsigned int* hash) { 191 assert(thread == Thread::current(), "invariant"); 192 JfrThreadLocal* const tl = thread->jfr_thread_local(); 193 assert(tl != NULL, "invariant"); 194 195 if (tl->has_cached_stack_trace()) { 196 *hash = tl->cached_stack_trace_hash(); 197 return tl->cached_stack_trace_id(); 198 } 199 if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) { 200 return 0; 201 } 202 JfrStackFrame* frames = tl->stackframes(); 203 if (frames == NULL) { 204 // pending oom 205 return 0; 206 } 207 assert(frames != NULL, "invariant"); 208 assert(tl->stackframes() == frames, "invariant"); 209 return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth(), hash); 210 } 211 212 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) { 213 JfrStackTrace stacktrace(frames, max_frames); 214 if (!stacktrace.record_safe(thread, skip)) { 215 return 0; 216 } 217 traceid tid = add(stacktrace); 218 if (tid == 0) { 219 stacktrace.resolve_linenos(); 220 tid = add(stacktrace); 221 } 222 return tid; 223 } 224 225 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames, unsigned int* hash) { 226 assert(hash != NULL && *hash == 0, "invariant"); 227 JfrStackTrace stacktrace(frames, max_frames); 228 if (!stacktrace.record_safe(thread, skip, true)) { 229 return 0; 230 } 231 traceid tid = add(stacktrace); 232 if (tid == 0) { 233 stacktrace.resolve_linenos(); 234 tid = add(stacktrace); 235 } 236 *hash = stacktrace._hash; 237 return tid; 238 } 239 240 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) { 241 MutexLockerEx lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 242 assert(_entries > 0, "invariant"); 243 int count = 0; 244 for (u4 i = 0; i < TABLE_SIZE; ++i) { 245 JfrStackTraceRepository::StackTrace* stacktrace = _table[i]; 246 while (stacktrace != NULL) { 247 JfrStackTraceRepository::StackTrace* next = stacktrace->next(); 248 if (stacktrace->should_write()) { 249 stacktrace->write(sw); 250 ++count; 251 } 252 if (clear) { 253 delete stacktrace; 254 } 255 stacktrace = next; 256 } 257 } 258 if (clear) { 259 memset(_table, 0, sizeof(_table)); 260 _entries = 0; 261 } 262 return count; 263 } 264 265 size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) { 266 return _entries > 0 ? write_impl(sw, clear) : 0; 267 } 268 269 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) { 270 assert(JfrStacktrace_lock->owned_by_self(), "invariant"); 271 const StackTrace* const trace = resolve_entry(hash, id); 272 assert(trace != NULL, "invariant"); 273 assert(trace->hash() == hash, "invariant"); 274 assert(trace->id() == id, "invariant"); 275 trace->write(writer); 276 return id; 277 } 278 279 JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) : 280 _next(next), 281 _frames(NULL), 282 _id(id), 283 _nr_of_frames(trace._nr_of_frames), 284 _hash(trace._hash), 285 _reached_root(trace._reached_root), 286 _written(false) { 287 if (_nr_of_frames > 0) { 288 _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing); 289 memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame)); 290 } 291 } 292 293 JfrStackTraceRepository::StackTrace::~StackTrace() { 294 if (_frames != NULL) { 295 FREE_C_HEAP_ARRAY(JfrStackFrame, _frames); 296 } 297 } 298 299 bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const { 300 if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) { 301 return false; 302 } 303 for (u4 i = 0; i < _nr_of_frames; ++i) { 304 if (!_frames[i].equals(rhs._frames[i])) { 305 return false; 306 } 307 } 308 return true; 309 } 310 311 template <typename Writer> 312 static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) { 313 w.write((u8)id); 314 w.write((u1)!reached_root); 315 w.write(nr_of_frames); 316 for (u4 i = 0; i < nr_of_frames; ++i) { 317 frames[i].write(w); 318 } 319 } 320 321 void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const { 322 assert(!_written, "invariant"); 323 write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames); 324 _written = true; 325 } 326 327 void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const { 328 write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames); 329 } 330 331 // JfrStackFrame 332 333 bool JfrStackFrame::equals(const JfrStackFrame& rhs) const { 334 return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type; 335 } 336 337 template <typename Writer> 338 static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) { 339 w.write((u8)methodid); 340 w.write((u4)line); 341 w.write((u4)bci); 342 w.write((u8)type); 343 } 344 345 void JfrStackFrame::write(JfrChunkWriter& cw) const { 346 write_frame(cw, _methodid, _line, _bci, _type); 347 } 348 349 void JfrStackFrame::write(JfrCheckpointWriter& cpw) const { 350 write_frame(cpw, _methodid, _line, _bci, _type); 351 } 352 353 // invariant is that the entry to be resolved actually exists in the table 354 const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const { 355 const size_t index = (hash % TABLE_SIZE); 356 const StackTrace* trace = _table[index]; 357 while (trace != NULL && trace->id() != id) { 358 trace = trace->next(); 359 } 360 assert(trace != NULL, "invariant"); 361 assert(trace->hash() == hash, "invariant"); 362 assert(trace->id() == id, "invariant"); 363 return trace; 364 } 365 366 void JfrStackFrame::resolve_lineno() { 367 assert(_method, "no method pointer"); 368 assert(_line == 0, "already have linenumber"); 369 _line = _method->line_number_from_bci(_bci); 370 _method = NULL; 371 } 372 373 void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) { 374 assert(frame_pos < _max_frames, "illegal frame_pos"); 375 _frames[frame_pos] = frame; 376 } 377 378 void JfrStackTrace::resolve_linenos() { 379 for(unsigned int i = 0; i < _nr_of_frames; i++) { 380 _frames[i].resolve_lineno(); 381 } 382 _lineno = true; 383 } 384 385 bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) { 386 assert(thread == Thread::current(), "Thread stack needs to be walkable"); 387 vframeStream vfs(thread); 388 u4 count = 0; 389 _reached_root = true; 390 for(int i = 0; i < skip; i++) { 391 if (vfs.at_end()) { 392 break; 393 } 394 vfs.next(); 395 } 396 397 while (!vfs.at_end()) { 398 if (count >= _max_frames) { 399 _reached_root = false; 400 break; 401 } 402 const Method* method = vfs.method(); 403 const traceid mid = JfrTraceId::use(method, leakp); 404 int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT; 405 int bci = 0; 406 if (method->is_native()) { 407 type = JfrStackFrame::FRAME_NATIVE; 408 } else { 409 bci = vfs.bci(); 410 } 411 // Can we determine if it's inlined? 412 _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type); 413 _frames[count] = JfrStackFrame(mid, bci, type, method); 414 vfs.next(); 415 count++; 416 } 417 418 _nr_of_frames = count; 419 return true; 420 } 421 422 bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) { 423 vframeStreamSamples st(&thread, frame, false); 424 u4 count = 0; 425 _reached_root = true; 426 427 while (!st.at_end()) { 428 if (count >= _max_frames) { 429 _reached_root = false; 430 break; 431 } 432 const Method* method = st.method(); 433 if (!Method::is_valid_method(method)) { 434 // we throw away everything we've gathered in this sample since 435 // none of it is safe 436 return false; 437 } 438 const traceid mid = JfrTraceId::use(method); 439 int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT; 440 int bci = 0; 441 if (method->is_native()) { 442 type = JfrStackFrame::FRAME_NATIVE; 443 } else { 444 bci = st.bci(); 445 } 446 const int lineno = method->line_number_from_bci(bci); 447 // Can we determine if it's inlined? 448 _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type); 449 _frames[count] = JfrStackFrame(mid, bci, type, lineno); 450 st.samples_next(); 451 count++; 452 } 453 454 _lineno = true; 455 _nr_of_frames = count; 456 return true; 457 } 458 459 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) { 460 JfrFrameType fct; 461 writer.write_type(TYPE_FRAMETYPE); 462 fct.serialize(writer); 463 }