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/leakprofiler/chains/edgeStore.hpp"
27 #include "jfr/leakprofiler/chains/edgeUtils.hpp"
28 #include "oops/oop.inline.hpp"
29
30 RoutableEdge::RoutableEdge() : Edge() {}
31 RoutableEdge::RoutableEdge(const Edge* parent, const oop* reference) : Edge(parent, reference),
32 _skip_edge(NULL),
33 _skip_length(0),
34 _processed(false) {}
35
36 RoutableEdge::RoutableEdge(const Edge& edge) : Edge(edge),
37 _skip_edge(NULL),
38 _skip_length(0),
39 _processed(false) {}
40
41 RoutableEdge::RoutableEdge(const RoutableEdge& edge) : Edge(edge),
42 _skip_edge(edge._skip_edge),
43 _skip_length(edge._skip_length),
44 _processed(edge._processed) {}
45
46 void RoutableEdge::operator=(const RoutableEdge& edge) {
47 Edge::operator=(edge);
48 _skip_edge = edge._skip_edge;
49 _skip_length = edge._skip_length;
50 _processed = edge._processed;
51 }
52
53 size_t RoutableEdge::logical_distance_to_root() const {
54 size_t depth = 0;
55 const RoutableEdge* current = logical_parent();
56 while (current != NULL) {
57 depth++;
58 current = current->logical_parent();
59 }
60 return depth;
61 }
62
63 traceid EdgeStore::_edge_id_counter = 0;
64
65 EdgeStore::EdgeStore() : _edges(NULL) {
66 _edges = new EdgeHashTable(this);
67 }
68
69 EdgeStore::~EdgeStore() {
70 assert(_edges != NULL, "invariant");
71 delete _edges;
72 _edges = NULL;
73 }
74
75 const Edge* EdgeStore::get_edge(const Edge* edge) const {
76 assert(edge != NULL, "invariant");
77 EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
78 return entry != NULL ? entry->literal_addr() : NULL;
79 }
80
81 const Edge* EdgeStore::put(const Edge* edge) {
82 assert(edge != NULL, "invariant");
83 const RoutableEdge e = *edge;
84 assert(NULL == _edges->lookup_only(e, (uintptr_t)e.reference()), "invariant");
85 EdgeEntry& entry = _edges->put(e, (uintptr_t)e.reference());
86 return entry.literal_addr();
87 }
88
89 traceid EdgeStore::get_id(const Edge* edge) const {
90 assert(edge != NULL, "invariant");
91 EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
92 assert(entry != NULL, "invariant");
93 return entry->id();
94 }
95
96 traceid EdgeStore::get_root_id(const Edge* edge) const {
97 assert(edge != NULL, "invariant");
98 const Edge* root = EdgeUtils::root(*edge);
99 assert(root != NULL, "invariant");
100 return get_id(root);
101 }
102
103 void EdgeStore::add_chain(const Edge* chain, size_t length) {
104 assert(chain != NULL, "invariant");
105 assert(length > 0, "invariant");
106
107 size_t bottom_index = length - 1;
108 const size_t top_index = 0;
109
110 const Edge* stored_parent_edge = NULL;
111
112 // determine level of shared ancestry
113 for (; bottom_index > top_index; --bottom_index) {
114 const Edge* stored_edge = get_edge(&chain[bottom_index]);
115 if (stored_edge != NULL) {
116 stored_parent_edge = stored_edge;
117 continue;
118 }
119 break;
120 }
121
122 // insertion of new Edges
123 for (int i = (int)bottom_index; i >= (int)top_index; --i) {
124 Edge edge(stored_parent_edge, chain[i].reference());
125 stored_parent_edge = put(&edge);
126 }
127
128 const oop sample_object = stored_parent_edge->pointee();
129 assert(sample_object != NULL, "invariant");
130 assert(NULL == sample_object->mark(), "invariant");
131
132 // Install the "top" edge of the chain into the sample object mark oop.
133 // This associates the sample object with its navigable reference chain.
134 sample_object->set_mark(markOop(stored_parent_edge));
135 }
136
137 bool EdgeStore::is_empty() const {
138 return !_edges->has_entries();
139 }
140
141 size_t EdgeStore::number_of_entries() const {
142 return _edges->cardinality();
143 }
144
145 void EdgeStore::assign_id(EdgeEntry* entry) {
146 assert(entry != NULL, "invariant");
147 assert(entry->id() == 0, "invariant");
148 entry->set_id(++_edge_id_counter);
149 }
150
151 bool EdgeStore::equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry) {
152 assert(entry != NULL, "invariant");
153 assert(entry->hash() == hash, "invariant");
154 return true;
155 }
|
1 /*
2 * Copyright (c) 2014, 2019, 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/leakprofiler/chains/edgeStore.hpp"
27 #include "jfr/leakprofiler/chains/edgeUtils.hpp"
28 #include "oops/oop.inline.hpp"
29
30 StoredEdge::StoredEdge() : Edge() {}
31 StoredEdge::StoredEdge(const Edge* parent, const oop* reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
32
33 StoredEdge::StoredEdge(const Edge& edge) : Edge(edge), _gc_root_id(0), _skip_length(0) {}
34
35 StoredEdge::StoredEdge(const StoredEdge& edge) : Edge(edge), _gc_root_id(edge._gc_root_id), _skip_length(edge._skip_length) {}
36
37 void StoredEdge::operator=(const StoredEdge& edge) {
38 Edge::operator=(edge);
39 _gc_root_id = edge._gc_root_id;
40 _skip_length = edge._skip_length;
41 }
42
43 traceid EdgeStore::_edge_id_counter = 0;
44
45 EdgeStore::EdgeStore() : _edges(NULL) {
46 _edges = new EdgeHashTable(this);
47 }
48
49 EdgeStore::~EdgeStore() {
50 assert(_edges != NULL, "invariant");
51 delete _edges;
52 }
53
54 bool EdgeStore::is_empty() const {
55 return !_edges->has_entries();
56 }
57
58 void EdgeStore::assign_id(EdgeEntry* entry) {
59 assert(entry != NULL, "invariant");
60 assert(entry->id() == 0, "invariant");
61 entry->set_id(++_edge_id_counter);
62 }
63
64 bool EdgeStore::equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry) {
65 assert(entry != NULL, "invariant");
66 assert(entry->hash() == hash, "invariant");
67 return true;
68 }
69
70 #ifdef ASSERT
71 bool EdgeStore::contains(const oop* reference) const {
72 return get(reference) != NULL;
73 }
74 #endif
75
76 StoredEdge* EdgeStore::get(const oop* reference) const {
77 assert(reference != NULL, "invariant");
78 const StoredEdge e(NULL, reference);
79 EdgeEntry* const entry = _edges->lookup_only(e, (uintptr_t)reference);
80 return entry != NULL ? entry->literal_addr() : NULL;
81 }
82
83 StoredEdge* EdgeStore::put(const oop* reference) {
84 assert(reference != NULL, "invariant");
85 const StoredEdge e(NULL, reference);
86 assert(NULL == _edges->lookup_only(e, (uintptr_t)reference), "invariant");
87 EdgeEntry& entry = _edges->put(e, (uintptr_t)reference);
88 return entry.literal_addr();
89 }
90
91 traceid EdgeStore::get_id(const Edge* edge) const {
92 assert(edge != NULL, "invariant");
93 EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
94 assert(entry != NULL, "invariant");
95 return entry->id();
96 }
97
98 traceid EdgeStore::gc_root_id(const Edge* edge) const {
99 assert(edge != NULL, "invariant");
100 const traceid gc_root_id = static_cast<const StoredEdge*>(edge)->gc_root_id();
101 if (gc_root_id != 0) {
102 return gc_root_id;
103 }
104 // not cached
105 assert(edge != NULL, "invariant");
106 const Edge* const root = EdgeUtils::root(*edge);
107 assert(root != NULL, "invariant");
108 assert(root->parent() == NULL, "invariant");
109 return get_id(root);
110 }
111
112 static const Edge* get_skip_ancestor(const Edge** current, size_t distance_to_root, size_t* skip_length) {
113 assert(distance_to_root >= EdgeUtils::root_context, "invariant");
114 assert(*skip_length == 0, "invariant");
115 *skip_length = distance_to_root - (EdgeUtils::root_context - 1);
116 const Edge* const target = EdgeUtils::ancestor(**current, *skip_length);
117 assert(target != NULL, "invariant");
118 assert(target->distance_to_root() + 1 == EdgeUtils::root_context, "invariant");
119 return target;
120 }
121
122 bool EdgeStore::put_skip_edge(StoredEdge** previous, const Edge** current, size_t distance_to_root) {
123 assert(*previous != NULL, "invariant");
124 assert((*previous)->parent() == NULL, "invariant");
125 assert(*current != NULL, "invariant");
126 assert((*current)->distance_to_root() == distance_to_root, "invariant");
127
128 if (distance_to_root < EdgeUtils::root_context) {
129 // nothing to skip
130 return false;
131 }
132
133 size_t skip_length = 0;
134 const Edge* const skip_ancestor = get_skip_ancestor(current, distance_to_root, &skip_length);
135 assert(skip_ancestor != NULL, "invariant");
136 (*previous)->set_skip_length(skip_length);
137
138 // lookup target
139 StoredEdge* stored_target = get(skip_ancestor->reference());
140 if (stored_target != NULL) {
141 (*previous)->set_parent(stored_target);
142 // linked to existing, complete
143 return true;
144 }
145
146 assert(stored_target == NULL, "invariant");
147 stored_target = put(skip_ancestor->reference());
148 assert(stored_target != NULL, "invariant");
149 (*previous)->set_parent(stored_target);
150 *previous = stored_target;
151 *current = skip_ancestor->parent();
152 return false;
153 }
154
155 static void link_edge(const StoredEdge* current_stored, StoredEdge** previous) {
156 assert(current_stored != NULL, "invariant");
157 assert(*previous != NULL, "invariant");
158 assert((*previous)->parent() == NULL, "invariant");
159 (*previous)->set_parent(current_stored);
160 }
161
162 static const StoredEdge* find_closest_skip_edge(const StoredEdge* edge, size_t* distance) {
163 assert(edge != NULL, "invariant");
164 assert(distance != NULL, "invariant");
165 const StoredEdge* current = edge;
166 *distance = 1;
167 while (current != NULL && !current->is_skip_edge()) {
168 ++(*distance);
169 current = current->parent();
170 }
171 return current;
172 }
173
174 void EdgeStore::link_with_existing_chain(const StoredEdge* current_stored, StoredEdge** previous, size_t previous_length) {
175 assert(current_stored != NULL, "invariant");
176 assert((*previous)->parent() == NULL, "invariant");
177 size_t distance_to_skip_edge; // including the skip edge itself
178 const StoredEdge* const closest_skip_edge = find_closest_skip_edge(current_stored, &distance_to_skip_edge);
179 if (closest_skip_edge == NULL) {
180 // no found skip edge implies root
181 if (distance_to_skip_edge + previous_length <= EdgeUtils::max_ref_chain_depth) {
182 link_edge(current_stored, previous);
183 return;
184 }
185 assert(current_stored->distance_to_root() == distance_to_skip_edge - 2, "invariant");
186 put_skip_edge(previous, reinterpret_cast<const Edge**>(¤t_stored), distance_to_skip_edge - 2);
187 return;
188 }
189 assert(closest_skip_edge->is_skip_edge(), "invariant");
190 if (distance_to_skip_edge + previous_length <= EdgeUtils::leak_context) {
191 link_edge(current_stored, previous);
192 return;
193 }
194 // create a new skip edge with derived information from closest skip edge
195 (*previous)->set_skip_length(distance_to_skip_edge + closest_skip_edge->skip_length());
196 (*previous)->set_parent(closest_skip_edge->parent());
197 }
198
199 StoredEdge* EdgeStore::link_new_edge(StoredEdge** previous, const Edge** current) {
200 assert(*previous != NULL, "invariant");
201 assert((*previous)->parent() == NULL, "invariant");
202 assert(*current != NULL, "invariant");
203 assert(!contains((*current)->reference()), "invariant");
204 StoredEdge* const stored_edge = put((*current)->reference());
205 assert(stored_edge != NULL, "invariant");
206 link_edge(stored_edge, previous);
207 return stored_edge;
208 }
209
210 bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t limit) {
211 assert(*previous != NULL, "invariant");
212 assert(*current != NULL, "invariant");
213 size_t depth = 1;
214 while (*current != NULL && depth < limit) {
215 StoredEdge* stored_edge = get((*current)->reference());
216 if (stored_edge != NULL) {
217 link_with_existing_chain(stored_edge, previous, depth);
218 return true;
219 }
220 stored_edge = link_new_edge(previous, current);
221 assert((*previous)->parent() != NULL, "invariant");
222 *previous = stored_edge;
223 *current = (*current)->parent();
224 ++depth;
225 }
226 return NULL == *current;
227 }
228
229 // Install the immediate edge into the mark word of the leak candidate object
230 StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
231 assert(edge != NULL, "invariant");
232 assert(!contains(edge->reference()), "invariant");
233 StoredEdge* const leak_context_edge = put(edge->reference());
234 oop sample_object = edge->pointee();
235 assert(sample_object != NULL, "invariant");
236 assert(NULL == sample_object->mark(), "invariant");
237 sample_object->set_mark(markOop(leak_context_edge));
238 return leak_context_edge;
239 }
240
241 /*
242 * The purpose of put_chain() is to reify the edge sequence
243 * discovered during heap traversal with a normalized logical copy.
244 * This copy consist of two sub-sequences and a connecting link (skip edge).
245 *
246 * "current" can be thought of as the cursor (search) edge, it is not in the edge store.
247 * "previous" is always an edge in the edge store.
248 * The leak context edge is the edge adjacent to the leak candidate object, always an edge in the edge store.
249 */
250 void EdgeStore::put_chain(const Edge* chain, size_t length) {
251 assert(chain != NULL, "invariant");
252 assert(chain->distance_to_root() + 1 == length, "invariant");
253 StoredEdge* const leak_context_edge = associate_leak_context_with_candidate(chain);
254 assert(leak_context_edge != NULL, "invariant");
255 assert(leak_context_edge->parent() == NULL, "invariant");
256
257 if (1 == length) {
258 return;
259 }
260
261 const Edge* current = chain->parent();
262 assert(current != NULL, "invariant");
263 StoredEdge* previous = leak_context_edge;
264
265 // a leak context is the sequence of (limited) edges reachable from the leak candidate
266 if (put_edges(&previous, ¤t, EdgeUtils::leak_context)) {
267 // complete
268 assert(previous != NULL, "invariant");
269 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous));
270 return;
271 }
272
273 const size_t distance_to_root = length > EdgeUtils::leak_context ? length - 1 - EdgeUtils::leak_context : length - 1;
274 assert(current->distance_to_root() == distance_to_root, "invariant");
275
276 // a skip edge is the logical link
277 // connecting the leak context sequence with the root context sequence
278 if (put_skip_edge(&previous, ¤t, distance_to_root)) {
279 // complete
280 assert(previous != NULL, "invariant");
281 assert(previous->is_skip_edge(), "invariant");
282 assert(previous->parent() != NULL, "invariant");
283 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous->parent()));
284 return;
285 }
286
287 assert(current->distance_to_root() < EdgeUtils::root_context, "invariant");
288
289 // a root context is the sequence of (limited) edges reachable from the root
290 put_edges(&previous, ¤t, EdgeUtils::root_context);
291 assert(previous != NULL, "invariant");
292 put_chain_epilogue(leak_context_edge, EdgeUtils::root(*previous));
293 }
294
295 void EdgeStore::put_chain_epilogue(StoredEdge* leak_context_edge, const Edge* root) const {
296 assert(leak_context_edge != NULL, "invariant");
297 assert(root != NULL, "invariant");
298 store_gc_root_id_in_leak_context_edge(leak_context_edge, root);
299 assert(leak_context_edge->distance_to_root() + 1 <= EdgeUtils::max_ref_chain_depth, "invariant");
300 }
301
302 // To avoid another traversal to resolve the root edge id later,
303 // cache it in the immediate leak context edge for fast retrieval.
304 void EdgeStore::store_gc_root_id_in_leak_context_edge(StoredEdge* leak_context_edge, const Edge* root) const {
305 assert(leak_context_edge != NULL, "invariant");
306 assert(leak_context_edge->gc_root_id() == 0, "invariant");
307 assert(root != NULL, "invariant");
308 assert(root->parent() == NULL, "invariant");
309 assert(root->distance_to_root() == 0, "invariant");
310 const StoredEdge* const stored_root = static_cast<const StoredEdge*>(root);
311 traceid root_id = stored_root->gc_root_id();
312 if (root_id == 0) {
313 root_id = get_id(root);
314 stored_root->set_gc_root_id(root_id);
315 }
316 assert(root_id != 0, "invariant");
317 leak_context_edge->set_gc_root_id(root_id);
318 assert(leak_context_edge->gc_root_id() == stored_root->gc_root_id(), "invariant");
319 }
|