Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
41153 views
1
/*
2
* Copyright (c) 2014, 2020, 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/leakprofiler/chains/bitset.inline.hpp"
26
#include "jfr/leakprofiler/chains/bfsClosure.hpp"
27
#include "jfr/leakprofiler/chains/dfsClosure.hpp"
28
#include "jfr/leakprofiler/chains/edge.hpp"
29
#include "jfr/leakprofiler/chains/edgeStore.hpp"
30
#include "jfr/leakprofiler/chains/edgeQueue.hpp"
31
#include "jfr/leakprofiler/utilities/granularTimer.hpp"
32
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
33
#include "logging/log.hpp"
34
#include "memory/iterator.inline.hpp"
35
#include "memory/resourceArea.hpp"
36
#include "oops/access.inline.hpp"
37
#include "oops/oop.inline.hpp"
38
#include "utilities/align.hpp"
39
40
BFSClosure::BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits) :
41
_edge_queue(edge_queue),
42
_edge_store(edge_store),
43
_mark_bits(mark_bits),
44
_current_parent(NULL),
45
_current_frontier_level(0),
46
_next_frontier_idx(0),
47
_prev_frontier_idx(0),
48
_dfs_fallback_idx(0),
49
_use_dfs(false) {
50
}
51
52
static void log_frontier_level_summary(size_t level,
53
size_t high_idx,
54
size_t low_idx,
55
size_t edge_size) {
56
const size_t nof_edges_in_frontier = high_idx - low_idx;
57
log_trace(jfr, system)(
58
"BFS front: " SIZE_FORMAT " edges: " SIZE_FORMAT " size: " SIZE_FORMAT " [KB]",
59
level,
60
nof_edges_in_frontier,
61
(nof_edges_in_frontier * edge_size) / K
62
);
63
}
64
65
void BFSClosure::log_completed_frontier() const {
66
log_frontier_level_summary(_current_frontier_level,
67
_next_frontier_idx,
68
_prev_frontier_idx,
69
_edge_queue->sizeof_edge());
70
}
71
72
void BFSClosure::log_dfs_fallback() const {
73
const size_t edge_size = _edge_queue->sizeof_edge();
74
// first complete summary for frontier in progress
75
log_frontier_level_summary(_current_frontier_level,
76
_next_frontier_idx,
77
_prev_frontier_idx,
78
edge_size);
79
80
// and then also complete the last frontier
81
log_frontier_level_summary(_current_frontier_level + 1,
82
_edge_queue->bottom(),
83
_next_frontier_idx,
84
edge_size);
85
86
// additional information about DFS fallover
87
log_trace(jfr, system)(
88
"BFS front: " SIZE_FORMAT " filled edge queue at edge: " SIZE_FORMAT,
89
_current_frontier_level,
90
_dfs_fallback_idx
91
);
92
93
const size_t nof_dfs_completed_edges = _edge_queue->bottom() - _dfs_fallback_idx;
94
log_trace(jfr, system)(
95
"DFS to complete " SIZE_FORMAT " edges size: " SIZE_FORMAT " [KB]",
96
nof_dfs_completed_edges,
97
(nof_dfs_completed_edges * edge_size) / K
98
);
99
}
100
101
void BFSClosure::process() {
102
process_root_set();
103
process_queue();
104
}
105
106
void BFSClosure::process_root_set() {
107
for (size_t idx = _edge_queue->bottom(); idx < _edge_queue->top(); ++idx) {
108
const Edge* edge = _edge_queue->element_at(idx);
109
assert(edge->parent() == NULL, "invariant");
110
process(edge->reference(), edge->pointee());
111
}
112
}
113
114
void BFSClosure::process(UnifiedOopRef reference, const oop pointee) {
115
closure_impl(reference, pointee);
116
}
117
void BFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) {
118
assert(!reference.is_null(), "invariant");
119
assert(reference.dereference() == pointee, "invariant");
120
121
if (GranularTimer::is_finished()) {
122
return;
123
}
124
125
if (_use_dfs) {
126
assert(_current_parent != NULL, "invariant");
127
DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent);
128
return;
129
}
130
131
if (!_mark_bits->is_marked(pointee)) {
132
_mark_bits->mark_obj(pointee);
133
// is the pointee a sample object?
134
if (pointee->mark().is_marked()) {
135
add_chain(reference, pointee);
136
}
137
138
// if we are processinig initial root set, don't add to queue
139
if (_current_parent != NULL) {
140
_edge_queue->add(_current_parent, reference);
141
}
142
143
if (_edge_queue->is_full()) {
144
dfs_fallback();
145
}
146
}
147
}
148
149
void BFSClosure::add_chain(UnifiedOopRef reference, const oop pointee) {
150
assert(pointee != NULL, "invariant");
151
assert(pointee->mark().is_marked(), "invariant");
152
Edge leak_edge(_current_parent, reference);
153
_edge_store->put_chain(&leak_edge, _current_parent == NULL ? 1 : _current_frontier_level + 2);
154
}
155
156
void BFSClosure::dfs_fallback() {
157
assert(_edge_queue->is_full(), "invariant");
158
_use_dfs = true;
159
_dfs_fallback_idx = _edge_queue->bottom();
160
while (!_edge_queue->is_empty()) {
161
const Edge* edge = _edge_queue->remove();
162
if (edge->pointee() != NULL) {
163
DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, edge);
164
}
165
}
166
}
167
168
void BFSClosure::process_queue() {
169
assert(_current_frontier_level == 0, "invariant");
170
assert(_next_frontier_idx == 0, "invariant");
171
assert(_prev_frontier_idx == 0, "invariant");
172
173
_next_frontier_idx = _edge_queue->top();
174
while (!is_complete()) {
175
iterate(_edge_queue->remove()); // edge_queue.remove() increments bottom
176
}
177
}
178
179
void BFSClosure::step_frontier() const {
180
log_completed_frontier();
181
++_current_frontier_level;
182
_prev_frontier_idx = _next_frontier_idx;
183
_next_frontier_idx = _edge_queue->top();
184
}
185
186
bool BFSClosure::is_complete() const {
187
if (_edge_queue->bottom() < _next_frontier_idx) {
188
return false;
189
}
190
if (_edge_queue->bottom() > _next_frontier_idx) {
191
// fallback onto DFS as part of processing the frontier
192
assert(_dfs_fallback_idx >= _prev_frontier_idx, "invariant");
193
assert(_dfs_fallback_idx < _next_frontier_idx, "invariant");
194
log_dfs_fallback();
195
return true;
196
}
197
assert(_edge_queue->bottom() == _next_frontier_idx, "invariant");
198
if (_edge_queue->is_empty()) {
199
return true;
200
}
201
step_frontier();
202
return false;
203
}
204
205
void BFSClosure::iterate(const Edge* parent) {
206
assert(parent != NULL, "invariant");
207
const oop pointee = parent->pointee();
208
assert(pointee != NULL, "invariant");
209
_current_parent = parent;
210
pointee->oop_iterate(this);
211
}
212
213
void BFSClosure::do_oop(oop* ref) {
214
assert(ref != NULL, "invariant");
215
assert(is_aligned(ref, HeapWordSize), "invariant");
216
const oop pointee = HeapAccess<AS_NO_KEEPALIVE>::oop_load(ref);
217
if (pointee != NULL) {
218
closure_impl(UnifiedOopRef::encode_in_heap(ref), pointee);
219
}
220
}
221
222
void BFSClosure::do_oop(narrowOop* ref) {
223
assert(ref != NULL, "invariant");
224
assert(is_aligned(ref, sizeof(narrowOop)), "invariant");
225
const oop pointee = HeapAccess<AS_NO_KEEPALIVE>::oop_load(ref);
226
if (pointee != NULL) {
227
closure_impl(UnifiedOopRef::encode_in_heap(ref), pointee);
228
}
229
}
230
231
void BFSClosure::do_root(UnifiedOopRef ref) {
232
assert(ref.dereference() != NULL, "pointee must not be null");
233
if (!_edge_queue->is_full()) {
234
_edge_queue->add(NULL, ref);
235
}
236
}
237
238