--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp Fri Aug 23 18:47:55 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp Sat Aug 24 14:30:27 2019 +0200
@@ -24,66 +24,17 @@
#include "precompiled.hpp"
#include "jfr/metadata/jfrSerializer.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
-#include "jfr/utilities/jfrTypes.hpp"
-#include "memory/allocation.inline.hpp"
#include "runtime/mutexLocker.hpp"
-#include "runtime/os.inline.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/task.hpp"
-#include "runtime/vframe.inline.hpp"
-
-class vframeStreamSamples : public vframeStreamCommon {
- public:
- // constructor that starts with sender of frame fr (top_frame)
- vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub);
- void samples_next();
- void stop() {}
-};
-
-vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
- _stop_at_java_call_stub = stop_at_java_call_stub;
- _frame = fr;
-
- // We must always have a valid frame to start filling
- bool filled_in = fill_from_frame();
- assert(filled_in, "invariant");
-}
-
-// Solaris SPARC Compiler1 needs an additional check on the grandparent
-// of the top_frame when the parent of the top_frame is interpreted and
-// the grandparent is compiled. However, in this method we do not know
-// the relationship of the current _frame relative to the top_frame so
-// we implement a more broad sanity check. When the previous callee is
-// interpreted and the current sender is compiled, we verify that the
-// current sender is also walkable. If it is not walkable, then we mark
-// the current vframeStream as at the end.
-void vframeStreamSamples::samples_next() {
- // handle frames with inlining
- if (_mode == compiled_mode &&
- vframeStreamCommon::fill_in_compiled_inlined_sender()) {
- return;
- }
-
- // handle general case
- u4 loop_count = 0;
- u4 loop_max = MAX_STACK_DEPTH * 2;
- do {
- loop_count++;
- // By the time we get here we should never see unsafe but better safe then segv'd
- if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
- _mode = at_end_mode;
- return;
- }
- _frame = _frame.sender(&_reg_map);
- } while (!fill_from_frame());
-}
static JfrStackTraceRepository* _instance = NULL;
+JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
+ memset(_table, 0, sizeof(_table));
+}
+
JfrStackTraceRepository& JfrStackTraceRepository::instance() {
return *_instance;
}
@@ -94,15 +45,6 @@
return _instance;
}
-void JfrStackTraceRepository::destroy() {
- assert(_instance != NULL, "invarinat");
- delete _instance;
- _instance = NULL;
-}
-
-JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
- memset(_table, 0, sizeof(_table));
-}
class JfrFrameType : public JfrSerializer {
public:
void serialize(JfrCheckpointWriter& writer) {
@@ -122,119 +64,10 @@
return JfrSerializer::register_serializer(TYPE_FRAMETYPE, true, new JfrFrameType());
}
-size_t JfrStackTraceRepository::clear() {
- MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
- if (_entries == 0) {
- return 0;
- }
- for (u4 i = 0; i < TABLE_SIZE; ++i) {
- JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
- while (stacktrace != NULL) {
- JfrStackTraceRepository::StackTrace* next = stacktrace->next();
- delete stacktrace;
- stacktrace = next;
- }
- }
- memset(_table, 0, sizeof(_table));
- const size_t processed = _entries;
- _entries = 0;
- return processed;
-}
-
-traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
- MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
- const size_t index = stacktrace._hash % TABLE_SIZE;
- const StackTrace* table_entry = _table[index];
-
- while (table_entry != NULL) {
- if (table_entry->equals(stacktrace)) {
- return table_entry->id();
- }
- table_entry = table_entry->next();
- }
-
- if (!stacktrace.have_lineno()) {
- return 0;
- }
-
- traceid id = ++_next_id;
- _table[index] = new StackTrace(id, stacktrace, _table[index]);
- ++_entries;
- return id;
-}
-
-traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
- return instance().add_trace(stacktrace);
-}
-
-traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
- assert(thread == Thread::current(), "invariant");
- JfrThreadLocal* const tl = thread->jfr_thread_local();
- assert(tl != NULL, "invariant");
- if (tl->has_cached_stack_trace()) {
- return tl->cached_stack_trace_id();
- }
- if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
- return 0;
- }
- JfrStackFrame* frames = tl->stackframes();
- if (frames == NULL) {
- // pending oom
- return 0;
- }
- assert(frames != NULL, "invariant");
- assert(tl->stackframes() == frames, "invariant");
- return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
-}
-
-traceid JfrStackTraceRepository::record(Thread* thread, int skip, unsigned int* hash) {
- assert(thread == Thread::current(), "invariant");
- JfrThreadLocal* const tl = thread->jfr_thread_local();
- assert(tl != NULL, "invariant");
-
- if (tl->has_cached_stack_trace()) {
- *hash = tl->cached_stack_trace_hash();
- return tl->cached_stack_trace_id();
- }
- if (!thread->is_Java_thread() || thread->is_hidden_from_external_view() || tl->is_excluded()) {
- return 0;
- }
- JfrStackFrame* frames = tl->stackframes();
- if (frames == NULL) {
- // pending oom
- return 0;
- }
- assert(frames != NULL, "invariant");
- assert(tl->stackframes() == frames, "invariant");
- return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth(), hash);
-}
-
-traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
- JfrStackTrace stacktrace(frames, max_frames);
- if (!stacktrace.record_safe(thread, skip)) {
- return 0;
- }
- traceid tid = add(stacktrace);
- if (tid == 0) {
- stacktrace.resolve_linenos();
- tid = add(stacktrace);
- }
- return tid;
-}
-
-traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames, unsigned int* hash) {
- assert(hash != NULL && *hash == 0, "invariant");
- JfrStackTrace stacktrace(frames, max_frames);
- if (!stacktrace.record_safe(thread, skip, true)) {
- return 0;
- }
- traceid tid = add(stacktrace);
- if (tid == 0) {
- stacktrace.resolve_linenos();
- tid = add(stacktrace);
- }
- *hash = stacktrace._hash;
- return tid;
+void JfrStackTraceRepository::destroy() {
+ assert(_instance != NULL, "invarinat");
+ delete _instance;
+ _instance = NULL;
}
size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
@@ -242,9 +75,9 @@
assert(_entries > 0, "invariant");
int count = 0;
for (u4 i = 0; i < TABLE_SIZE; ++i) {
- JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
+ JfrStackTrace* stacktrace = _table[i];
while (stacktrace != NULL) {
- JfrStackTraceRepository::StackTrace* next = stacktrace->next();
+ JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
if (stacktrace->should_write()) {
stacktrace->write(sw);
++count;
@@ -268,7 +101,7 @@
traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
assert(JfrStacktrace_lock->owned_by_self(), "invariant");
- const StackTrace* const trace = resolve_entry(hash, id);
+ const JfrStackTrace* const trace = lookup(hash, id);
assert(trace != NULL, "invariant");
assert(trace->hash() == hash, "invariant");
assert(trace->id() == id, "invariant");
@@ -276,84 +109,99 @@
return id;
}
-JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
- _next(next),
- _frames(NULL),
- _id(id),
- _nr_of_frames(trace._nr_of_frames),
- _hash(trace._hash),
- _reached_root(trace._reached_root),
- _written(false) {
- if (_nr_of_frames > 0) {
- _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
- memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
- }
+void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
+ JfrFrameType fct;
+ writer.write_type(TYPE_FRAMETYPE);
+ fct.serialize(writer);
}
-JfrStackTraceRepository::StackTrace::~StackTrace() {
- if (_frames != NULL) {
- FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
+size_t JfrStackTraceRepository::clear() {
+ MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+ if (_entries == 0) {
+ return 0;
}
-}
-
-bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
- if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
- return false;
- }
- for (u4 i = 0; i < _nr_of_frames; ++i) {
- if (!_frames[i].equals(rhs._frames[i])) {
- return false;
+ for (u4 i = 0; i < TABLE_SIZE; ++i) {
+ JfrStackTrace* stacktrace = _table[i];
+ while (stacktrace != NULL) {
+ JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
+ delete stacktrace;
+ stacktrace = next;
}
}
- return true;
+ memset(_table, 0, sizeof(_table));
+ const size_t processed = _entries;
+ _entries = 0;
+ return processed;
}
-template <typename Writer>
-static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
- w.write((u8)id);
- w.write((u1)!reached_root);
- w.write(nr_of_frames);
- for (u4 i = 0; i < nr_of_frames; ++i) {
- frames[i].write(w);
+traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
+ assert(thread == Thread::current(), "invariant");
+ JfrThreadLocal* const tl = thread->jfr_thread_local();
+ assert(tl != NULL, "invariant");
+ if (tl->has_cached_stack_trace()) {
+ return tl->cached_stack_trace_id();
}
+ if (!thread->is_Java_thread() || thread->is_hidden_from_external_view() || tl->is_excluded()) {
+ return 0;
+ }
+ JfrStackFrame* frames = tl->stackframes();
+ if (frames == NULL) {
+ // pending oom
+ return 0;
+ }
+ assert(frames != NULL, "invariant");
+ assert(tl->stackframes() == frames, "invariant");
+ return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
}
-void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
- assert(!_written, "invariant");
- write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
- _written = true;
-}
-
-void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
- write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
+traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
+ JfrStackTrace stacktrace(frames, max_frames);
+ return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
}
-// JfrStackFrame
+traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
+ assert(stacktrace != NULL, "invariant");
+ assert(thread != NULL, "invariant");
+ assert(stacktrace->hash() != 0, "invariant");
+ return add(*stacktrace);
+}
-bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
- return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
+traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
+ traceid tid = instance().add_trace(stacktrace);
+ if (tid == 0) {
+ stacktrace.resolve_linenos();
+ tid = instance().add_trace(stacktrace);
+ }
+ assert(tid != 0, "invariant");
+ return tid;
}
-template <typename Writer>
-static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
- w.write((u8)methodid);
- w.write((u4)line);
- w.write((u4)bci);
- w.write((u8)type);
-}
+traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
+ MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+ const size_t index = stacktrace._hash % TABLE_SIZE;
+ const JfrStackTrace* table_entry = _table[index];
-void JfrStackFrame::write(JfrChunkWriter& cw) const {
- write_frame(cw, _methodid, _line, _bci, _type);
-}
+ while (table_entry != NULL) {
+ if (table_entry->equals(stacktrace)) {
+ return table_entry->id();
+ }
+ table_entry = table_entry->next();
+ }
-void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
- write_frame(cpw, _methodid, _line, _bci, _type);
+ if (!stacktrace.have_lineno()) {
+ return 0;
+ }
+
+ traceid id = ++_next_id;
+ _table[index] = new JfrStackTrace(id, stacktrace, _table[index]);
+ ++_entries;
+ return id;
}
// invariant is that the entry to be resolved actually exists in the table
-const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
+const JfrStackTrace* JfrStackTraceRepository::lookup(unsigned int hash, traceid id) const {
const size_t index = (hash % TABLE_SIZE);
- const StackTrace* trace = _table[index];
+ const JfrStackTrace* trace = _table[index];
while (trace != NULL && trace->id() != id) {
trace = trace->next();
}
@@ -363,100 +211,16 @@
return trace;
}
-void JfrStackFrame::resolve_lineno() {
- assert(_method, "no method pointer");
- assert(_line == 0, "already have linenumber");
- _line = _method->line_number_from_bci(_bci);
-}
-
-void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
- assert(frame_pos < _max_frames, "illegal frame_pos");
- _frames[frame_pos] = frame;
-}
-
-void JfrStackTrace::resolve_linenos() {
- for(unsigned int i = 0; i < _nr_of_frames; i++) {
- _frames[i].resolve_lineno();
+bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
+ assert(thread == Thread::current(), "invariant");
+ assert(stacktrace != NULL, "invariant");
+ JfrThreadLocal* const tl = thread->jfr_thread_local();
+ assert(tl != NULL, "invariant");
+ const unsigned int cached_stacktrace_hash = tl->cached_stack_trace_hash();
+ if (cached_stacktrace_hash != 0) {
+ stacktrace->set_hash(cached_stacktrace_hash);
+ return true;
}
- _lineno = true;
+ return stacktrace->record_safe(thread, skip);
}
-bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
- assert(thread == Thread::current(), "Thread stack needs to be walkable");
- vframeStream vfs(thread);
- u4 count = 0;
- _reached_root = true;
- for(int i = 0; i < skip; i++) {
- if (vfs.at_end()) {
- break;
- }
- vfs.next();
- }
-
- while (!vfs.at_end()) {
- if (count >= _max_frames) {
- _reached_root = false;
- break;
- }
- const Method* method = vfs.method();
- const traceid mid = JfrTraceId::use(method, leakp);
- int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
- int bci = 0;
- if (method->is_native()) {
- type = JfrStackFrame::FRAME_NATIVE;
- } else {
- bci = vfs.bci();
- }
- // Can we determine if it's inlined?
- _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
- _frames[count] = JfrStackFrame(mid, bci, type, method);
- vfs.next();
- count++;
- }
-
- _nr_of_frames = count;
- return true;
-}
-
-bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
- vframeStreamSamples st(&thread, frame, false);
- u4 count = 0;
- _reached_root = true;
-
- while (!st.at_end()) {
- if (count >= _max_frames) {
- _reached_root = false;
- break;
- }
- const Method* method = st.method();
- if (!Method::is_valid_method(method)) {
- // we throw away everything we've gathered in this sample since
- // none of it is safe
- return false;
- }
- const traceid mid = JfrTraceId::use(method);
- int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
- int bci = 0;
- if (method->is_native()) {
- type = JfrStackFrame::FRAME_NATIVE;
- } else {
- bci = st.bci();
- }
- const int lineno = method->line_number_from_bci(bci);
- // Can we determine if it's inlined?
- _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
- _frames[count] = JfrStackFrame(method, mid, bci, type, lineno);
- st.samples_next();
- count++;
- }
-
- _lineno = true;
- _nr_of_frames = count;
- return true;
-}
-
-void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
- JfrFrameType fct;
- writer.write_type(TYPE_FRAMETYPE);
- fct.serialize(writer);
-}