1 /* |
1 /* |
2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
21 * questions. |
21 * questions. |
22 * |
22 * |
23 */ |
23 */ |
24 |
24 |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
|
26 #include "jfr/leakprofiler/chains/bitset.inline.hpp" |
26 #include "jfr/leakprofiler/chains/dfsClosure.hpp" |
27 #include "jfr/leakprofiler/chains/dfsClosure.hpp" |
27 #include "jfr/leakprofiler/chains/edge.hpp" |
28 #include "jfr/leakprofiler/chains/edge.hpp" |
28 #include "jfr/leakprofiler/chains/edgeStore.hpp" |
29 #include "jfr/leakprofiler/chains/edgeStore.hpp" |
|
30 #include "jfr/leakprofiler/chains/rootSetClosure.hpp" |
29 #include "jfr/leakprofiler/utilities/granularTimer.hpp" |
31 #include "jfr/leakprofiler/utilities/granularTimer.hpp" |
30 #include "jfr/leakprofiler/chains/bitset.hpp" |
32 #include "jfr/leakprofiler/utilities/rootType.hpp" |
31 #include "jfr/leakprofiler/utilities/unifiedOop.hpp" |
33 #include "jfr/leakprofiler/utilities/unifiedOop.hpp" |
32 #include "jfr/leakprofiler/utilities/rootType.hpp" |
|
33 #include "jfr/leakprofiler/chains/rootSetClosure.hpp" |
|
34 #include "memory/iterator.inline.hpp" |
34 #include "memory/iterator.inline.hpp" |
35 #include "memory/resourceArea.hpp" |
35 #include "memory/resourceArea.hpp" |
36 #include "oops/access.inline.hpp" |
36 #include "oops/access.inline.hpp" |
37 #include "oops/oop.inline.hpp" |
37 #include "oops/oop.inline.hpp" |
38 #include "utilities/align.hpp" |
38 #include "utilities/align.hpp" |
86 _start_edge = NULL; |
86 _start_edge = NULL; |
87 |
87 |
88 // Mark root set, to avoid going sideways |
88 // Mark root set, to avoid going sideways |
89 _max_depth = 1; |
89 _max_depth = 1; |
90 _ignore_root_set = false; |
90 _ignore_root_set = false; |
91 DFSClosure dfs1; |
91 DFSClosure dfs; |
92 RootSetClosure::process_roots(&dfs1); |
92 RootSetClosure<DFSClosure> rs(&dfs); |
|
93 rs.process(); |
93 |
94 |
94 // Depth-first search |
95 // Depth-first search |
95 _max_depth = max_dfs_depth; |
96 _max_depth = max_dfs_depth; |
96 _ignore_root_set = true; |
97 _ignore_root_set = true; |
97 assert(_start_edge == NULL, "invariant"); |
98 assert(_start_edge == NULL, "invariant"); |
98 DFSClosure dfs2; |
99 rs.process(); |
99 RootSetClosure::process_roots(&dfs2); |
|
100 } |
100 } |
101 |
101 |
102 void DFSClosure::closure_impl(const oop* reference, const oop pointee) { |
102 void DFSClosure::closure_impl(const oop* reference, const oop pointee) { |
103 assert(pointee != NULL, "invariant"); |
103 assert(pointee != NULL, "invariant"); |
104 assert(reference != NULL, "invariant"); |
104 assert(reference != NULL, "invariant"); |
119 _reference = reference; |
119 _reference = reference; |
120 _mark_bits->mark_obj(pointee); |
120 _mark_bits->mark_obj(pointee); |
121 assert(_mark_bits->is_marked(pointee), "invariant"); |
121 assert(_mark_bits->is_marked(pointee), "invariant"); |
122 |
122 |
123 // is the pointee a sample object? |
123 // is the pointee a sample object? |
124 if (NULL == pointee->mark()) { |
124 if (NULL == pointee->mark().to_pointer()) { |
125 add_chain(); |
125 add_chain(); |
126 } |
126 } |
127 |
127 |
128 assert(_max_depth >= 1, "invariant"); |
128 assert(_max_depth >= 1, "invariant"); |
129 if (_depth < _max_depth - 1) { |
129 if (_depth < _max_depth - 1) { |
131 pointee->oop_iterate(&next_level); |
131 pointee->oop_iterate(&next_level); |
132 } |
132 } |
133 } |
133 } |
134 |
134 |
135 void DFSClosure::add_chain() { |
135 void DFSClosure::add_chain() { |
136 const size_t length = _start_edge == NULL ? _depth + 1 : |
136 const size_t array_length = _depth + 2; |
137 _start_edge->distance_to_root() + 1 + _depth + 1; |
|
138 |
137 |
139 ResourceMark rm; |
138 ResourceMark rm; |
140 Edge* const chain = NEW_RESOURCE_ARRAY(Edge, length); |
139 Edge* const chain = NEW_RESOURCE_ARRAY(Edge, array_length); |
141 size_t idx = 0; |
140 size_t idx = 0; |
142 |
141 |
143 // aggregate from depth-first search |
142 // aggregate from depth-first search |
144 const DFSClosure* c = this; |
143 const DFSClosure* c = this; |
145 while (c != NULL) { |
144 while (c != NULL) { |
146 chain[idx++] = Edge(NULL, c->reference()); |
145 const size_t next = idx + 1; |
|
146 chain[idx++] = Edge(&chain[next], c->reference()); |
147 c = c->parent(); |
147 c = c->parent(); |
148 } |
148 } |
149 |
149 assert(_depth + 1 == idx, "invariant"); |
150 assert(idx == _depth + 1, "invariant"); |
150 assert(array_length == idx + 1, "invariant"); |
151 |
151 |
152 // aggregate from breadth-first search |
152 // aggregate from breadth-first search |
153 const Edge* current = _start_edge; |
153 if (_start_edge != NULL) { |
154 while (current != NULL) { |
154 chain[idx++] = *_start_edge; |
155 chain[idx++] = Edge(NULL, current->reference()); |
155 } else { |
156 current = current->parent(); |
156 chain[idx - 1] = Edge(NULL, chain[idx - 1].reference()); |
157 } |
157 } |
158 assert(idx == length, "invariant"); |
158 _edge_store->put_chain(chain, idx + (_start_edge != NULL ? _start_edge->distance_to_root() : 0)); |
159 _edge_store->add_chain(chain, length); |
|
160 } |
159 } |
161 |
160 |
162 void DFSClosure::do_oop(oop* ref) { |
161 void DFSClosure::do_oop(oop* ref) { |
163 assert(ref != NULL, "invariant"); |
162 assert(ref != NULL, "invariant"); |
164 assert(is_aligned(ref, HeapWordSize), "invariant"); |
163 assert(is_aligned(ref, HeapWordSize), "invariant"); |
174 const oop pointee = RawAccess<>::oop_load(ref); |
173 const oop pointee = RawAccess<>::oop_load(ref); |
175 if (pointee != NULL) { |
174 if (pointee != NULL) { |
176 closure_impl(UnifiedOop::encode(ref), pointee); |
175 closure_impl(UnifiedOop::encode(ref), pointee); |
177 } |
176 } |
178 } |
177 } |
|
178 |
|
179 void DFSClosure::do_root(const oop* ref) { |
|
180 assert(ref != NULL, "invariant"); |
|
181 const oop pointee = UnifiedOop::dereference(ref); |
|
182 assert(pointee != NULL, "invariant"); |
|
183 closure_impl(ref, pointee); |
|
184 } |