1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp Mon Aug 12 18:30:40 2019 +0300 1.3 @@ -0,0 +1,320 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "jfr/jfrEvents.hpp" 1.30 +#include "jfr/recorder/jfrRecorder.hpp" 1.31 +#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" 1.32 +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" 1.33 +#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 1.34 +#include "jfr/leakprofiler/chains/edgeStore.hpp" 1.35 +#include "jfr/leakprofiler/chains/objectSampleMarker.hpp" 1.36 +#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" 1.37 +#include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp" 1.38 +#include "jfr/leakprofiler/leakProfiler.hpp" 1.39 +#include "jfr/leakprofiler/sampling/objectSample.hpp" 1.40 +#include "jfr/leakprofiler/sampling/objectSampler.hpp" 1.41 +#include "jfr/leakprofiler/utilities/rootType.hpp" 1.42 +#include "jfr/metadata/jfrSerializer.hpp" 1.43 +#include "runtime/interfaceSupport.hpp" 1.44 +#include "runtime/mutexLocker.hpp" 1.45 +#include "runtime/thread.inline.hpp" 1.46 + 1.47 +template <typename SampleProcessor> 1.48 +static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) { 1.49 + assert(sample != NULL, "invariant"); 1.50 + while (sample != end) { 1.51 + processor.sample_do(sample); 1.52 + sample = sample->next(); 1.53 + } 1.54 +} 1.55 + 1.56 +class RootSystemType : public JfrSerializer { 1.57 + public: 1.58 + void serialize(JfrCheckpointWriter& writer) { 1.59 + const u4 nof_root_systems = OldObjectRoot::_number_of_systems; 1.60 + writer.write_count(nof_root_systems); 1.61 + for (u4 i = 0; i < nof_root_systems; ++i) { 1.62 + writer.write_key(i); 1.63 + writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i)); 1.64 + } 1.65 + } 1.66 +}; 1.67 + 1.68 +class RootType : public JfrSerializer { 1.69 + public: 1.70 + void serialize(JfrCheckpointWriter& writer) { 1.71 + const u4 nof_root_types = OldObjectRoot::_number_of_types; 1.72 + writer.write_count(nof_root_types); 1.73 + for (u4 i = 0; i < nof_root_types; ++i) { 1.74 + writer.write_key(i); 1.75 + writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i)); 1.76 + } 1.77 + } 1.78 +}; 1.79 + 1.80 +class CheckpointInstall { 1.81 + private: 1.82 + const JfrCheckpointBlobHandle& _cp; 1.83 + public: 1.84 + CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {} 1.85 + void sample_do(ObjectSample* sample) { 1.86 + assert(sample != NULL, "invariant"); 1.87 + if (!sample->is_dead()) { 1.88 + sample->set_klass_checkpoint(_cp); 1.89 + } 1.90 + } 1.91 +}; 1.92 + 1.93 +class CheckpointWrite { 1.94 + private: 1.95 + JfrCheckpointWriter& _writer; 1.96 + const jlong _last_sweep; 1.97 + public: 1.98 + CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {} 1.99 + void sample_do(ObjectSample* sample) { 1.100 + assert(sample != NULL, "invariant"); 1.101 + if (sample->is_alive_and_older_than(_last_sweep)) { 1.102 + if (sample->has_thread_checkpoint()) { 1.103 + const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint(); 1.104 + thread_cp->exclusive_write(_writer); 1.105 + } 1.106 + if (sample->has_klass_checkpoint()) { 1.107 + const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint(); 1.108 + klass_cp->exclusive_write(_writer); 1.109 + } 1.110 + } 1.111 + } 1.112 +}; 1.113 + 1.114 +class CheckpointStateReset { 1.115 + private: 1.116 + const jlong _last_sweep; 1.117 + public: 1.118 + CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {} 1.119 + void sample_do(ObjectSample* sample) { 1.120 + assert(sample != NULL, "invariant"); 1.121 + if (sample->is_alive_and_older_than(_last_sweep)) { 1.122 + if (sample->has_thread_checkpoint()) { 1.123 + const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint(); 1.124 + thread_cp->reset_write_state(); 1.125 + } 1.126 + if (sample->has_klass_checkpoint()) { 1.127 + const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint(); 1.128 + klass_cp->reset_write_state(); 1.129 + } 1.130 + } 1.131 + } 1.132 +}; 1.133 + 1.134 +class StackTraceWrite { 1.135 + private: 1.136 + JfrStackTraceRepository& _stack_trace_repo; 1.137 + JfrCheckpointWriter& _writer; 1.138 + int _count; 1.139 + public: 1.140 + StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) : 1.141 + _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) { 1.142 + JfrStacktrace_lock->lock(); 1.143 + } 1.144 + ~StackTraceWrite() { 1.145 + assert(JfrStacktrace_lock->owned_by_self(), "invariant"); 1.146 + JfrStacktrace_lock->unlock(); 1.147 + } 1.148 + 1.149 + void sample_do(ObjectSample* sample) { 1.150 + assert(sample != NULL, "invariant"); 1.151 + if (!sample->is_dead()) { 1.152 + if (sample->has_stack_trace()) { 1.153 + JfrTraceId::use(sample->klass(), true); 1.154 + _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash()); 1.155 + ++_count; 1.156 + } 1.157 + } 1.158 + } 1.159 + 1.160 + int count() const { 1.161 + return _count; 1.162 + } 1.163 +}; 1.164 + 1.165 +class SampleMark { 1.166 + private: 1.167 + ObjectSampleMarker& _marker; 1.168 + jlong _last_sweep; 1.169 + int _count; 1.170 + public: 1.171 + SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker), 1.172 + _last_sweep(last_sweep), 1.173 + _count(0) {} 1.174 + void sample_do(ObjectSample* sample) { 1.175 + assert(sample != NULL, "invariant"); 1.176 + if (sample->is_alive_and_older_than(_last_sweep)) { 1.177 + _marker.mark(sample->object()); 1.178 + ++_count; 1.179 + } 1.180 + } 1.181 + 1.182 + int count() const { 1.183 + return _count; 1.184 + } 1.185 +}; 1.186 + 1.187 +void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool resume) { 1.188 + assert(class_unload ? SafepointSynchronize::is_at_safepoint() : LeakProfiler::is_suspended(), "invariant"); 1.189 + 1.190 + if (!writer.has_data()) { 1.191 + if (!class_unload) { 1.192 + LeakProfiler::resume(); 1.193 + } 1.194 + assert(LeakProfiler::is_running(), "invariant"); 1.195 + return; 1.196 + } 1.197 + 1.198 + assert(writer.has_data(), "invariant"); 1.199 + const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob(); 1.200 + 1.201 + const ObjectSampler* const object_sampler = LeakProfiler::object_sampler(); 1.202 + assert(object_sampler != NULL, "invariant"); 1.203 + 1.204 + ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 1.205 + const ObjectSample* const last_resolved = object_sampler->last_resolved(); 1.206 + CheckpointInstall install(h_cp); 1.207 + 1.208 + if (class_unload) { 1.209 + if (last != NULL) { 1.210 + // all samples need the class unload information 1.211 + do_samples(last, NULL, install); 1.212 + } 1.213 + assert(LeakProfiler::is_running(), "invariant"); 1.214 + return; 1.215 + } 1.216 + 1.217 + // only new samples since last resolved checkpoint 1.218 + if (last != last_resolved) { 1.219 + do_samples(last, last_resolved, install); 1.220 + if (resume) { 1.221 + const_cast<ObjectSampler*>(object_sampler)->set_last_resolved(last); 1.222 + } 1.223 + } 1.224 + assert(LeakProfiler::is_suspended(), "invariant"); 1.225 + if (resume) { 1.226 + LeakProfiler::resume(); 1.227 + assert(LeakProfiler::is_running(), "invariant"); 1.228 + } 1.229 +} 1.230 + 1.231 +void ObjectSampleCheckpoint::write(const EdgeStore* edge_store, bool emit_all, Thread* thread) { 1.232 + assert(edge_store != NULL, "invariant"); 1.233 + assert(thread != NULL, "invariant"); 1.234 + static bool types_registered = false; 1.235 + if (!types_registered) { 1.236 + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType()); 1.237 + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType()); 1.238 + types_registered = true; 1.239 + } 1.240 + const ObjectSampler* const object_sampler = LeakProfiler::object_sampler(); 1.241 + assert(object_sampler != NULL, "invariant"); 1.242 + const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value(); 1.243 + ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 1.244 + { 1.245 + JfrCheckpointWriter writer(false, false, thread); 1.246 + CheckpointWrite checkpoint_write(writer, last_sweep); 1.247 + do_samples(last, NULL, checkpoint_write); 1.248 + } 1.249 + CheckpointStateReset state_reset(last_sweep); 1.250 + do_samples(last, NULL, state_reset); 1.251 + if (!edge_store->is_empty()) { 1.252 + // java object and chain representations 1.253 + JfrCheckpointWriter writer(false, true, thread); 1.254 + ObjectSampleWriter osw(writer, edge_store); 1.255 + edge_store->iterate_edges(osw); 1.256 + } 1.257 +} 1.258 + 1.259 +WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(JfrStackTraceRepository& repo) : 1.260 + _stack_trace_repo(repo) { 1.261 +} 1.262 + 1.263 +bool WriteObjectSampleStacktrace::process() { 1.264 + assert(SafepointSynchronize::is_at_safepoint(), "invariant"); 1.265 + if (!LeakProfiler::is_running()) { 1.266 + return true; 1.267 + } 1.268 + // Suspend the LeakProfiler subsystem 1.269 + // to ensure stable samples even 1.270 + // after we return from the safepoint. 1.271 + LeakProfiler::suspend(); 1.272 + assert(!LeakProfiler::is_running(), "invariant"); 1.273 + assert(LeakProfiler::is_suspended(), "invariant"); 1.274 + 1.275 + const ObjectSampler* object_sampler = LeakProfiler::object_sampler(); 1.276 + assert(object_sampler != NULL, "invariant"); 1.277 + assert(LeakProfiler::is_suspended(), "invariant"); 1.278 + 1.279 + ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 1.280 + const ObjectSample* const last_resolved = object_sampler->last_resolved(); 1.281 + if (last == last_resolved) { 1.282 + assert(LeakProfiler::is_suspended(), "invariant"); 1.283 + return true; 1.284 + } 1.285 + 1.286 + JfrCheckpointWriter writer(false, true, Thread::current()); 1.287 + const JfrCheckpointContext ctx = writer.context(); 1.288 + 1.289 + writer.write_type(TYPE_STACKTRACE); 1.290 + const jlong count_offset = writer.reserve(sizeof(u4)); 1.291 + 1.292 + int count = 0; 1.293 + { 1.294 + StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock 1.295 + do_samples(last, last_resolved, stack_trace_write); 1.296 + count = stack_trace_write.count(); 1.297 + } 1.298 + if (count == 0) { 1.299 + writer.set_context(ctx); 1.300 + assert(LeakProfiler::is_suspended(), "invariant"); 1.301 + return true; 1.302 + } 1.303 + assert(count > 0, "invariant"); 1.304 + writer.write_count((u4)count, count_offset); 1.305 + JfrStackTraceRepository::write_metadata(writer); 1.306 + 1.307 + ObjectSampleCheckpoint::install(writer, false, false); 1.308 + assert(LeakProfiler::is_suspended(), "invariant"); 1.309 + return true; 1.310 +} 1.311 + 1.312 +int ObjectSampleCheckpoint::mark(ObjectSampleMarker& marker, bool emit_all) { 1.313 + const ObjectSampler* object_sampler = LeakProfiler::object_sampler(); 1.314 + assert(object_sampler != NULL, "invariant"); 1.315 + ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last()); 1.316 + if (last == NULL) { 1.317 + return 0; 1.318 + } 1.319 + const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value(); 1.320 + SampleMark mark(marker, last_sweep); 1.321 + do_samples(last, NULL, mark); 1.322 + return mark.count(); 1.323 +}