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