Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/leakprofiler/sampling/objectSampler.cpp
38922 views
1
/*
2
* Copyright (c) 2017, 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
#include "precompiled.hpp"
25
#include "jfr/jfrEvents.hpp"
26
#include "jfr/leakprofiler/sampling/objectSample.hpp"
27
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
28
#include "jfr/leakprofiler/sampling/sampleList.hpp"
29
#include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp"
30
#include "jfr/recorder/jfrEventSetting.inline.hpp"
31
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
32
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
33
#include "jfr/support/jfrThreadLocal.hpp"
34
#include "jfr/utilities/jfrTryLock.hpp"
35
#include "memory/universe.hpp"
36
#include "oops/oop.inline.hpp"
37
#include "runtime/atomic.hpp"
38
#include "runtime/orderAccess.hpp"
39
#include "runtime/safepoint.hpp"
40
#include "runtime/thread.hpp"
41
42
static ObjectSampler* _instance = NULL;
43
44
static ObjectSampler& instance() {
45
assert(_instance != NULL, "invariant");
46
return *_instance;
47
}
48
49
ObjectSampler::ObjectSampler(size_t size) :
50
_priority_queue(new SamplePriorityQueue(size)),
51
_list(new SampleList(size)),
52
_last_sweep(JfrTicks::now()),
53
_total_allocated(0),
54
_threshold(0),
55
_size(size),
56
_dead_samples(false) {}
57
58
ObjectSampler::~ObjectSampler() {
59
delete _priority_queue;
60
_priority_queue = NULL;
61
delete _list;
62
_list = NULL;
63
}
64
65
bool ObjectSampler::create(size_t size) {
66
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
67
assert(_instance == NULL, "invariant");
68
_instance = new ObjectSampler(size);
69
return _instance != NULL;
70
}
71
72
bool ObjectSampler::is_created() {
73
return _instance != NULL;
74
}
75
76
ObjectSampler* ObjectSampler::sampler() {
77
assert(is_created(), "invariant");
78
return _instance;
79
}
80
81
void ObjectSampler::destroy() {
82
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
83
if (_instance != NULL) {
84
ObjectSampler* const sampler = _instance;
85
_instance = NULL;
86
delete sampler;
87
}
88
}
89
90
static volatile int _lock = 0;
91
92
ObjectSampler* ObjectSampler::acquire() {
93
assert(is_created(), "invariant");
94
while (Atomic::cmpxchg(1, &_lock, 0) == 1) {}
95
return _instance;
96
}
97
98
void ObjectSampler::release() {
99
assert(is_created(), "invariant");
100
OrderAccess::fence();
101
_lock = 0;
102
}
103
104
static traceid get_thread_id(JavaThread* thread) {
105
assert(thread != NULL, "invariant");
106
if (thread->threadObj() == NULL) {
107
return 0;
108
}
109
const JfrThreadLocal* const tl = thread->jfr_thread_local();
110
assert(tl != NULL, "invariant");
111
if (!tl->has_thread_checkpoint()) {
112
JfrCheckpointManager::create_thread_checkpoint(thread);
113
}
114
assert(tl->has_thread_checkpoint(), "invariant");
115
return tl->thread_id();
116
}
117
118
// Populates the thread local stack frames, but does not add them
119
// to the stacktrace repository (...yet, see stacktrace_id() below)
120
//
121
void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread) {
122
assert(stacktrace != NULL, "invariant");
123
assert(thread != NULL, "invariant");
124
if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
125
JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0);
126
}
127
}
128
129
// We were successful in acquiring the try lock and have been selected for adding a sample.
130
// Go ahead with installing our previously taken stacktrace into the stacktrace repository.
131
//
132
traceid ObjectSampler::stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread) {
133
assert(stacktrace != NULL, "invariant");
134
assert(stacktrace->hash() != 0, "invariant");
135
const traceid stacktrace_id = JfrStackTraceRepository::add(stacktrace, thread);
136
thread->jfr_thread_local()->set_cached_stack_trace_id(stacktrace_id, stacktrace->hash());
137
return stacktrace_id;
138
}
139
140
void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) {
141
assert(thread != NULL, "invariant");
142
assert(is_created(), "invariant");
143
144
const traceid thread_id = get_thread_id(thread);
145
if (thread_id == 0) {
146
return;
147
}
148
const JfrThreadLocal* const tl = thread->jfr_thread_local();
149
JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
150
fill_stacktrace(&stacktrace, thread);
151
152
// try enter critical section
153
JfrTryLock tryLock(&_lock);
154
if (!tryLock.has_lock()) {
155
if (LogJFR && Verbose) tty->print_cr("Skipping old object sample due to lock contention");
156
return;
157
}
158
159
instance().add(obj, allocated, thread_id, &stacktrace, thread);
160
}
161
162
void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread) {
163
assert(stacktrace != NULL, "invariant");
164
assert(thread_id != 0, "invariant");
165
assert(thread != NULL, "invariant");
166
assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
167
168
if (_dead_samples) {
169
scavenge();
170
assert(!_dead_samples, "invariant");
171
}
172
173
_total_allocated += allocated;
174
const size_t span = _total_allocated - _priority_queue->total();
175
ObjectSample* sample;
176
if ((size_t)_priority_queue->count() == _size) {
177
assert(_list->count() == _size, "invariant");
178
const ObjectSample* peek = _priority_queue->peek();
179
if (peek->span() > span) {
180
// quick reject, will not fit
181
return;
182
}
183
sample = _list->reuse(_priority_queue->pop());
184
} else {
185
sample = _list->get();
186
}
187
188
assert(sample != NULL, "invariant");
189
sample->set_thread_id(thread_id);
190
sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
191
192
const unsigned int stacktrace_hash = stacktrace->hash();
193
if (stacktrace_hash != 0) {
194
sample->set_stack_trace_id(stacktrace_id(stacktrace, thread));
195
sample->set_stack_trace_hash(stacktrace_hash);
196
}
197
198
sample->set_span(allocated);
199
sample->set_object((oop)obj);
200
sample->set_allocated(allocated);
201
sample->set_allocation_time(JfrTicks::now());
202
sample->set_heap_used_at_last_gc(Universe::get_heap_used_at_last_gc());
203
_priority_queue->push(sample);
204
}
205
206
void ObjectSampler::scavenge() {
207
ObjectSample* current = _list->last();
208
while (current != NULL) {
209
ObjectSample* next = current->next();
210
if (current->is_dead()) {
211
remove_dead(current);
212
}
213
current = next;
214
}
215
_dead_samples = false;
216
}
217
218
void ObjectSampler::remove_dead(ObjectSample* sample) {
219
assert(sample != NULL, "invariant");
220
assert(sample->is_dead(), "invariant");
221
ObjectSample* const previous = sample->prev();
222
// push span on to previous
223
if (previous != NULL) {
224
_priority_queue->remove(previous);
225
previous->add_span(sample->span());
226
_priority_queue->push(previous);
227
}
228
_priority_queue->remove(sample);
229
_list->release(sample);
230
}
231
232
void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
233
assert(is_created(), "invariant");
234
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
235
ObjectSampler& sampler = instance();
236
ObjectSample* current = sampler._list->last();
237
while (current != NULL) {
238
ObjectSample* next = current->next();
239
if (!current->is_dead()) {
240
if (is_alive->do_object_b(current->object())) {
241
// The weakly referenced object is alive, update pointer
242
f->do_oop(const_cast<oop*>(current->object_addr()));
243
} else {
244
current->set_dead();
245
sampler._dead_samples = true;
246
}
247
}
248
current = next;
249
}
250
sampler._last_sweep = JfrTicks::now();
251
}
252
253
const ObjectSample* ObjectSampler::last() const {
254
return _list->last();
255
}
256
257
const ObjectSample* ObjectSampler::first() const {
258
return _list->first();
259
}
260
261
const ObjectSample* ObjectSampler::last_resolved() const {
262
return _list->last_resolved();
263
}
264
265
void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
266
_list->set_last_resolved(sample);
267
}
268
269
int ObjectSampler::item_count() const {
270
return _priority_queue->count();
271
}
272
273
const ObjectSample* ObjectSampler::item_at(int index) const {
274
return _priority_queue->item_at(index);
275
}
276
277
ObjectSample* ObjectSampler::item_at(int index) {
278
return const_cast<ObjectSample*>(
279
const_cast<const ObjectSampler*>(this)->item_at(index)
280
);
281
}
282
283
const JfrTicks& ObjectSampler::last_sweep() const {
284
return _last_sweep;
285
}
286
287