src/share/vm/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp

changeset 9858
b985cbb00e68
child 9885
8e875c964f41
equal deleted inserted replaced
9727:c7a3e57fdf4a 9858:b985cbb00e68
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/jfrEvents.hpp"
27 #include "jfr/recorder/jfrRecorder.hpp"
28 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
29 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
31 #include "jfr/leakprofiler/chains/edgeStore.hpp"
32 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
33 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
34 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
35 #include "jfr/leakprofiler/leakProfiler.hpp"
36 #include "jfr/leakprofiler/sampling/objectSample.hpp"
37 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
38 #include "jfr/leakprofiler/utilities/rootType.hpp"
39 #include "jfr/metadata/jfrSerializer.hpp"
40 #include "runtime/interfaceSupport.hpp"
41 #include "runtime/mutexLocker.hpp"
42 #include "runtime/thread.inline.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 RootSystemType : public JfrSerializer {
54 public:
55 void serialize(JfrCheckpointWriter& writer) {
56 const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
57 writer.write_count(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 RootType : public JfrSerializer {
66 public:
67 void serialize(JfrCheckpointWriter& writer) {
68 const u4 nof_root_types = OldObjectRoot::_number_of_types;
69 writer.write_count(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 types_registered = false;
232 if (!types_registered) {
233 JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
234 JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
235 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_type(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_count((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 }

mercurial