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/jfrCheckpointWriter.hpp" 28 #include "jfr/recorder/repository/jfrChunkWriter.hpp" 29 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 30 #include "jfr/support/jfrThreadLocal.hpp" 31 #include "runtime/mutexLocker.hpp" 32 33 static JfrStackTraceRepository* _instance = NULL; 34 35 JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) { 36 memset(_table, 0, sizeof(_table)); 37 } 38 39 JfrStackTraceRepository& JfrStackTraceRepository::instance() { 40 return *_instance; 41 } 42 43 JfrStackTraceRepository* JfrStackTraceRepository::create() { 44 assert(_instance == NULL, "invariant"); 45 _instance = new JfrStackTraceRepository(); 46 return _instance; 47 } 48 49 class JfrFrameType : public JfrSerializer { 50 public: 51 void serialize(JfrCheckpointWriter& writer) { 52 writer.write_count(JfrStackFrame::NUM_FRAME_TYPES); 53 writer.write_key(JfrStackFrame::FRAME_INTERPRETER); 54 writer.write("Interpreted"); 55 writer.write_key(JfrStackFrame::FRAME_JIT); 56 writer.write("JIT compiled"); 57 writer.write_key(JfrStackFrame::FRAME_INLINE); 58 writer.write("Inlined"); 59 writer.write_key(JfrStackFrame::FRAME_NATIVE); 60 writer.write("Native"); 61 } 62 }; 63 64 bool JfrStackTraceRepository::initialize() { 65 return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType()); 66 } 67 68 void JfrStackTraceRepository::destroy() { 69 assert(_instance != NULL, "invarinat"); 70 delete _instance; 71 _instance = NULL; 72 } 73 74 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) { 75 MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 76 assert(_entries > 0, "invariant"); 77 int count = 0; 78 for (u4 i = 0; i < TABLE_SIZE; ++i) { 79 JfrStackTrace* stacktrace = _table[i]; 80 while (stacktrace != NULL) { 81 JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next()); 82 if (stacktrace->should_write()) { 83 stacktrace->write(sw); 84 ++count; 85 } 86 if (clear) { 87 delete stacktrace; 88 } 89 stacktrace = next; 90 } 91 } 92 if (clear) { 93 memset(_table, 0, sizeof(_table)); 94 _entries = 0; 95 } 96 return count; 97 } 98 99 size_t JfrStackTraceRepository::write(JfrChunkWriter& sw, bool clear) { 100 return _entries > 0 ? write_impl(sw, clear) : 0; 101 } 102 103 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) { 104 assert(JfrStacktrace_lock->owned_by_self(), "invariant"); 105 const JfrStackTrace* const trace = lookup(hash, id); 106 assert(trace != NULL, "invariant"); 107 assert(trace->hash() == hash, "invariant"); 108 assert(trace->id() == id, "invariant"); 109 trace->write(writer); 110 return id; 111 } 112 113 void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) { 114 JfrFrameType fct; 115 writer.write_type(TYPE_FRAMETYPE); 116 fct.serialize(writer); 117 } 118 119 size_t JfrStackTraceRepository::clear() { 120 MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 121 if (_entries == 0) { 122 return 0; 123 } 124 for (u4 i = 0; i < TABLE_SIZE; ++i) { 125 JfrStackTrace* stacktrace = _table[i]; 126 while (stacktrace != NULL) { 127 JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next()); 128 delete stacktrace; 129 stacktrace = next; 130 } 131 } 132 memset(_table, 0, sizeof(_table)); 133 const size_t processed = _entries; 134 _entries = 0; 135 return processed; 136 } 137 138 traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) { 139 assert(thread == Thread::current(), "invariant"); 140 JfrThreadLocal* const tl = thread->jfr_thread_local(); 141 assert(tl != NULL, "invariant"); 142 if (tl->has_cached_stack_trace()) { 143 return tl->cached_stack_trace_id(); 144 } 145 if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) { 146 return 0; 147 } 148 JfrStackFrame* frames = tl->stackframes(); 149 if (frames == NULL) { 150 // pending oom 151 return 0; 152 } 153 assert(frames != NULL, "invariant"); 154 assert(tl->stackframes() == frames, "invariant"); 155 return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth()); 156 } 157 158 traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) { 159 JfrStackTrace stacktrace(frames, max_frames); 160 return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0; 161 } 162 163 traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) { 164 traceid tid = instance().add_trace(stacktrace); 165 if (tid == 0) { 166 stacktrace.resolve_linenos(); 167 tid = instance().add_trace(stacktrace); 168 } 169 assert(tid != 0, "invariant"); 170 return tid; 171 } 172 173 void JfrStackTraceRepository::record_and_cache(JavaThread* thread, int skip /* 0 */) { 174 assert(thread != NULL, "invariant"); 175 JfrThreadLocal* const tl = thread->jfr_thread_local(); 176 assert(tl != NULL, "invariant"); 177 assert(!tl->has_cached_stack_trace(), "invariant"); 178 JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth()); 179 stacktrace.record_safe(thread, skip); 180 const unsigned int hash = stacktrace.hash(); 181 if (hash != 0) { 182 tl->set_cached_stack_trace_id(instance().add(stacktrace), hash); 183 } 184 } 185 186 traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) { 187 MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag); 188 const size_t index = stacktrace._hash % TABLE_SIZE; 189 const JfrStackTrace* table_entry = _table[index]; 190 191 while (table_entry != NULL) { 192 if (table_entry->equals(stacktrace)) { 193 return table_entry->id(); 194 } 195 table_entry = table_entry->next(); 196 } 197 198 if (!stacktrace.have_lineno()) { 199 return 0; 200 } 201 202 traceid id = ++_next_id; 203 _table[index] = new JfrStackTrace(id, stacktrace, _table[index]); 204 ++_entries; 205 return id; 206 } 207 208 // invariant is that the entry to be resolved actually exists in the table 209 const JfrStackTrace* JfrStackTraceRepository::lookup(unsigned int hash, traceid id) const { 210 const size_t index = (hash % TABLE_SIZE); 211 const JfrStackTrace* trace = _table[index]; 212 while (trace != NULL && trace->id() != id) { 213 trace = trace->next(); 214 } 215 assert(trace != NULL, "invariant"); 216 assert(trace->hash() == hash, "invariant"); 217 assert(trace->id() == id, "invariant"); 218 return trace; 219 }