1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/jfr/leakprofiler/chains/dfsClosure.cpp Mon Aug 12 18:30:40 2019 +0300 1.3 @@ -0,0 +1,177 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "jfr/leakprofiler/chains/dfsClosure.hpp" 1.30 +#include "jfr/leakprofiler/chains/edge.hpp" 1.31 +#include "jfr/leakprofiler/chains/edgeStore.hpp" 1.32 +#include "jfr/leakprofiler/utilities/granularTimer.hpp" 1.33 +#include "jfr/leakprofiler/chains/bitset.hpp" 1.34 +#include "jfr/leakprofiler/utilities/unifiedOop.hpp" 1.35 +#include "jfr/leakprofiler/utilities/rootType.hpp" 1.36 +#include "jfr/leakprofiler/chains/rootSetClosure.hpp" 1.37 +#include "memory/iterator.inline.hpp" 1.38 +#include "memory/resourceArea.hpp" 1.39 +#include "oops/oop.inline.hpp" 1.40 +#include "utilities/align.hpp" 1.41 + 1.42 +// max dfs depth should not exceed size of stack 1.43 +static const size_t max_dfs_depth = 5000; 1.44 + 1.45 +EdgeStore* DFSClosure::_edge_store = NULL; 1.46 +BitSet* DFSClosure::_mark_bits = NULL; 1.47 +const Edge* DFSClosure::_start_edge = NULL; 1.48 +size_t DFSClosure::_max_depth = max_dfs_depth; 1.49 +bool DFSClosure::_ignore_root_set = false; 1.50 + 1.51 +DFSClosure::DFSClosure() : 1.52 + _parent(NULL), 1.53 + _reference(NULL), 1.54 + _depth(0) { 1.55 +} 1.56 + 1.57 +DFSClosure::DFSClosure(DFSClosure* parent, size_t depth) : 1.58 + _parent(parent), 1.59 + _reference(NULL), 1.60 + _depth(depth) { 1.61 +} 1.62 + 1.63 +void DFSClosure::find_leaks_from_edge(EdgeStore* edge_store, 1.64 + BitSet* mark_bits, 1.65 + const Edge* start_edge) { 1.66 + assert(edge_store != NULL, "invariant"); 1.67 + assert(mark_bits != NULL," invariant"); 1.68 + assert(start_edge != NULL, "invariant"); 1.69 + 1.70 + _edge_store = edge_store; 1.71 + _mark_bits = mark_bits; 1.72 + _start_edge = start_edge; 1.73 + _ignore_root_set = false; 1.74 + assert(_max_depth == max_dfs_depth, "invariant"); 1.75 + 1.76 + // Depth-first search, starting from a BFS egde 1.77 + DFSClosure dfs; 1.78 + start_edge->pointee()->oop_iterate(&dfs); 1.79 +} 1.80 + 1.81 +void DFSClosure::find_leaks_from_root_set(EdgeStore* edge_store, 1.82 + BitSet* mark_bits) { 1.83 + assert(edge_store != NULL, "invariant"); 1.84 + assert(mark_bits != NULL, "invariant"); 1.85 + 1.86 + _edge_store = edge_store; 1.87 + _mark_bits = mark_bits; 1.88 + _start_edge = NULL; 1.89 + 1.90 + // Mark root set, to avoid going sideways 1.91 + _max_depth = 1; 1.92 + _ignore_root_set = false; 1.93 + DFSClosure dfs1; 1.94 + RootSetClosure::process_roots(&dfs1); 1.95 + 1.96 + // Depth-first search 1.97 + _max_depth = max_dfs_depth; 1.98 + _ignore_root_set = true; 1.99 + assert(_start_edge == NULL, "invariant"); 1.100 + DFSClosure dfs2; 1.101 + RootSetClosure::process_roots(&dfs2); 1.102 +} 1.103 + 1.104 +void DFSClosure::closure_impl(const oop* reference, const oop pointee) { 1.105 + assert(pointee != NULL, "invariant"); 1.106 + assert(reference != NULL, "invariant"); 1.107 + 1.108 + if (GranularTimer::is_finished()) { 1.109 + return; 1.110 + } 1.111 + if (_depth == 0 && _ignore_root_set) { 1.112 + // Root set is already marked, but we want 1.113 + // to continue, so skip is_marked check. 1.114 + assert(_mark_bits->is_marked(pointee), "invariant"); 1.115 + } else { 1.116 + if (_mark_bits->is_marked(pointee)) { 1.117 + return; 1.118 + } 1.119 + } 1.120 + 1.121 + _reference = reference; 1.122 + _mark_bits->mark_obj(pointee); 1.123 + assert(_mark_bits->is_marked(pointee), "invariant"); 1.124 + 1.125 + // is the pointee a sample object? 1.126 + if (NULL == pointee->mark()) { 1.127 + add_chain(); 1.128 + } 1.129 + 1.130 + assert(_max_depth >= 1, "invariant"); 1.131 + if (_depth < _max_depth - 1) { 1.132 + DFSClosure next_level(this, _depth + 1); 1.133 + pointee->oop_iterate(&next_level); 1.134 + } 1.135 +} 1.136 + 1.137 +void DFSClosure::add_chain() { 1.138 + const size_t length = _start_edge == NULL ? _depth + 1 : 1.139 + _start_edge->distance_to_root() + 1 + _depth + 1; 1.140 + 1.141 + ResourceMark rm; 1.142 + Edge* const chain = NEW_RESOURCE_ARRAY(Edge, length); 1.143 + size_t idx = 0; 1.144 + 1.145 + // aggregate from depth-first search 1.146 + const DFSClosure* c = this; 1.147 + while (c != NULL) { 1.148 + chain[idx++] = Edge(NULL, c->reference()); 1.149 + c = c->parent(); 1.150 + } 1.151 + 1.152 + assert(idx == _depth + 1, "invariant"); 1.153 + 1.154 + // aggregate from breadth-first search 1.155 + const Edge* current = _start_edge; 1.156 + while (current != NULL) { 1.157 + chain[idx++] = Edge(NULL, current->reference()); 1.158 + current = current->parent(); 1.159 + } 1.160 + assert(idx == length, "invariant"); 1.161 + _edge_store->add_chain(chain, length); 1.162 +} 1.163 + 1.164 +void DFSClosure::do_oop(oop* ref) { 1.165 + assert(ref != NULL, "invariant"); 1.166 + assert(is_aligned(ref, HeapWordSize), "invariant"); 1.167 + const oop pointee = *ref; 1.168 + if (pointee != NULL) { 1.169 + closure_impl(ref, pointee); 1.170 + } 1.171 +} 1.172 + 1.173 +void DFSClosure::do_oop(narrowOop* ref) { 1.174 + assert(ref != NULL, "invariant"); 1.175 + assert(is_aligned(ref, sizeof(narrowOop)), "invariant"); 1.176 + const oop pointee = oopDesc::load_decode_heap_oop(ref); 1.177 + if (pointee != NULL) { 1.178 + closure_impl(UnifiedOop::encode(ref), pointee); 1.179 + } 1.180 +}