1 /* 2 * Copyright (c) 2014, 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/recorder/jfrRecorder.hpp" 27 #include "jfr/recorder/checkpoint/constant/traceid/jfrTraceId.inline.hpp" 28 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" 29 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 30 #include "jfr/leakprofiler/chains/edgeStore.hpp" 31 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp" 32 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" 33 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp" 34 #include "jfr/leakprofiler/leakProfiler.hpp" 35 #include "jfr/leakprofiler/sampling/objectSample.hpp" 36 #include "jfr/leakprofiler/sampling/objectSampler.hpp" 37 #include "jfr/leakprofiler/utilities/rootType.hpp" 38 #include "jfr/metadata/jfrConstantSerializer.hpp" 39 #include "runtime/mutexLocker.hpp" 40 #include "runtime/thread.inline.hpp" 41 // to get CONTENT_TYPE defines 42 #include "tracefiles/traceTypes.hpp" 43 44 template <typename SampleProcessor> 45 static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) { 46 assert(sample != NULL, "invariant"); 47 while (sample != end) { 48 processor.sample_do(sample); 49 sample = sample->next(); 50 } 51 } 52 53 class ConstantTypeRootSystem : public JfrConstantSerializer { 54 public: 55 void write_constants(JfrCheckpointWriter& writer) { 56 const u4 nof_root_systems = OldObjectRoot::_number_of_systems; 57 writer.write_number_of_constants(nof_root_systems); 58 for (u4 i = 0; i < nof_root_systems; ++i) { 59 writer.write_key(i); 60 writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i)); 61 } 62 } 63 }; 64 65 class ConstantRootType : public JfrConstantSerializer { 66 public: 67 void write_constants(JfrCheckpointWriter& writer) { 68 const u4 nof_root_types = OldObjectRoot::_number_of_types; 69 writer.write_number_of_constants(nof_root_types); 70 for (u4 i = 0; i < nof_root_types; ++i) { 71 writer.write_key(i); 72 writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i)); 73 } 74 } 75 }; 76 77 class CheckpointInstall { 78 private: 79 const JfrCheckpointBlobHandle& _cp; 80 public: 81 CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {} 82 void sample_do(ObjectSample* sample) { 83 assert(sample != NULL, "invariant"); 84 if (!sample->is_dead()) { 85 sample->set_klass_checkpoint(_cp); 86 } 87 } 88 }; 89 90 class CheckpointWrite { 91 private: 92 JfrCheckpointWriter& _writer; 93 const jlong _last_sweep; 94 public: 95 CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {} 96 void sample_do(ObjectSample* sample) { 97 assert(sample != NULL, "invariant"); 98 if (sample->is_alive_and_older_than(_last_sweep)) { 99 if (sample->has_thread_checkpoint()) { 100 const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint(); 101 thread_cp->exclusive_write(_writer); 102 } 103 if (sample->has_klass_checkpoint()) { 104 const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint(); 105 klass_cp->exclusive_write(_writer); 106 } 107 } 108 } 109 }; 110 111 class CheckpointStateReset { 112 private: 113 const jlong _last_sweep; 114 public: 115 CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {} 116 void sample_do(ObjectSample* sample) { 117 assert(sample != NULL, "invariant"); 118 if (sample->is_alive_and_older_than(_last_sweep)) { 119 if (sample->has_thread_checkpoint()) { 120 const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint(); 121 thread_cp->reset_write_state(); 122 } 123 if (sample->has_klass_checkpoint()) { 124 const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint(); 125 klass_cp->reset_write_state(); 126 } 127 } 128 } 129 }; 130 131 class StackTraceWrite { 132 private: 133 JfrStackTraceRepository& _stack_trace_repo; 134 JfrCheckpointWriter& _writer; 135 int _count; 136 public: 137 StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) : 138 _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) { 139 JfrStacktrace_lock->lock(); 140 } 141 ~StackTraceWrite() { 142 assert(JfrStacktrace_lock->owned_by_self(), "invariant"); 143 JfrStacktrace_lock->unlock(); 144 } 145 146 void sample_do(ObjectSample* sample) { 147 assert(sample != NULL, "invariant"); 148 if (!sample->is_dead()) { 149 if (sample->has_stack_trace()) { 150 JfrTraceId::use(sample->klass(), true); 151 _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash()); 152 ++_count; 153 } 154 } 155 } 156 157 int count() const { 158 return _count; 159 } 160 }; 161 162 class SampleMark { 163 private: 164 ObjectSampleMarker& _marker; 165 jlong _last_sweep; 166 int _count; 167 public: 168 SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker), 169 _last_sweep(last_sweep), 170 _count(0) {} 171 void sample_do(ObjectSample* sample) { 172 assert(sample != NULL, "invariant"); 173 if (sample->is_alive_and_older_than(_last_sweep)) { 174 _marker.mark(sample->object()); 175 ++_count; 176 } 177 } 178 179 int count() const { 180 return _count; 181 } 182 }; 183 184 void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool resume) { 185 assert(class_unload ? SafepointSynchronize::is_at_safepoint() : LeakProfiler::is_suspended(), "invariant"); 186 187 if (!writer.has_data()) { 188 if (!class_unload) { 189 LeakProfiler::resume(); 190 } 191 assert(LeakProfiler::is_running(), "invariant"); 192 return; 193 } 194 195 assert(writer.has_data(), "invariant"); 196 const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob(); 197 198 const ObjectSampler* const object_sampler = LeakProfiler::object_sampler(); 199 assert(object_sampler != NULL, "invariant"); 200 201 ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 202 const ObjectSample* const last_resolved = object_sampler->last_resolved(); 203 CheckpointInstall install(h_cp); 204 205 if (class_unload) { 206 if (last != NULL) { 207 // all samples need the class unload information 208 do_samples(last, NULL, install); 209 } 210 assert(LeakProfiler::is_running(), "invariant"); 211 return; 212 } 213 214 // only new samples since last resolved checkpoint 215 if (last != last_resolved) { 216 do_samples(last, last_resolved, install); 217 if (resume) { 218 const_cast<ObjectSampler*>(object_sampler)->set_last_resolved(last); 219 } 220 } 221 assert(LeakProfiler::is_suspended(), "invariant"); 222 if (resume) { 223 LeakProfiler::resume(); 224 assert(LeakProfiler::is_running(), "invariant"); 225 } 226 } 227 228 void ObjectSampleCheckpoint::write(const EdgeStore* edge_store, bool emit_all, Thread* thread) { 229 assert(edge_store != NULL, "invariant"); 230 assert(thread != NULL, "invariant"); 231 static bool constant_types_registered = false; 232 if (!constant_types_registered) { 233 JfrConstantSerializer::register_serializer(CONSTANT_TYPE_OLDOBJECTROOTSYSTEM, false, true, new ConstantTypeRootSystem()); 234 JfrConstantSerializer::register_serializer(CONSTANT_TYPE_OLDOBJECTROOTTYPE, false, true, new ConstantRootType()); 235 constant_types_registered = true; 236 } 237 const ObjectSampler* const object_sampler = LeakProfiler::object_sampler(); 238 assert(object_sampler != NULL, "invariant"); 239 const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value(); 240 ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 241 { 242 JfrCheckpointWriter writer(false, false, thread); 243 CheckpointWrite checkpoint_write(writer, last_sweep); 244 do_samples(last, NULL, checkpoint_write); 245 } 246 CheckpointStateReset state_reset(last_sweep); 247 do_samples(last, NULL, state_reset); 248 if (!edge_store->is_empty()) { 249 // java object and chain representations 250 JfrCheckpointWriter writer(false, true, thread); 251 ObjectSampleWriter osw(writer, edge_store); 252 edge_store->iterate_edges(osw); 253 } 254 } 255 256 WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(JfrStackTraceRepository& repo) : 257 _stack_trace_repo(repo) { 258 } 259 260 bool WriteObjectSampleStacktrace::process() { 261 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); 262 if (!LeakProfiler::is_running()) { 263 return true; 264 } 265 // Suspend the LeakProfiler subsystem 266 // to ensure stable samples even 267 // after we return from the safepoint. 268 LeakProfiler::suspend(); 269 assert(!LeakProfiler::is_running(), "invariant"); 270 assert(LeakProfiler::is_suspended(), "invariant"); 271 272 const ObjectSampler* object_sampler = LeakProfiler::object_sampler(); 273 assert(object_sampler != NULL, "invariant"); 274 assert(LeakProfiler::is_suspended(), "invariant"); 275 276 ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 277 const ObjectSample* const last_resolved = object_sampler->last_resolved(); 278 if (last == last_resolved) { 279 assert(LeakProfiler::is_suspended(), "invariant"); 280 return true; 281 } 282 283 JfrCheckpointWriter writer(false, true, Thread::current()); 284 const JfrCheckpointContext ctx = writer.context(); 285 286 writer.write_constant_type(CONSTANT_TYPE_STACKTRACE); 287 const jlong count_offset = writer.reserve(sizeof(u4)); 288 289 int count = 0; 290 { 291 StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock 292 do_samples(last, last_resolved, stack_trace_write); 293 count = stack_trace_write.count(); 294 } 295 if (count == 0) { 296 writer.set_context(ctx); 297 assert(LeakProfiler::is_suspended(), "invariant"); 298 return true; 299 } 300 assert(count > 0, "invariant"); 301 writer.write_number_of_constants((u4)count, count_offset); 302 JfrStackTraceRepository::write_metadata(writer); 303 304 ObjectSampleCheckpoint::install(writer, false, false); 305 assert(LeakProfiler::is_suspended(), "invariant"); 306 return true; 307 } 308 309 int ObjectSampleCheckpoint::mark(ObjectSampleMarker& marker, bool emit_all) { 310 const ObjectSampler* object_sampler = LeakProfiler::object_sampler(); 311 assert(object_sampler != NULL, "invariant"); 312 ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 313 if (last == NULL) { 314 return 0; 315 } 316 const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value(); 317 SampleMark mark(marker, last_sweep); 318 do_samples(last, NULL, mark); 319 return mark.count(); 320 }