Path: blob/master/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
41153 views
/*1* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/23#include "precompiled.hpp"24#include "jfr/leakprofiler/chains/bitset.inline.hpp"25#include "jfr/leakprofiler/chains/bfsClosure.hpp"26#include "jfr/leakprofiler/chains/dfsClosure.hpp"27#include "jfr/leakprofiler/chains/edge.hpp"28#include "jfr/leakprofiler/chains/edgeStore.hpp"29#include "jfr/leakprofiler/chains/edgeQueue.hpp"30#include "jfr/leakprofiler/utilities/granularTimer.hpp"31#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"32#include "logging/log.hpp"33#include "memory/iterator.inline.hpp"34#include "memory/resourceArea.hpp"35#include "oops/access.inline.hpp"36#include "oops/oop.inline.hpp"37#include "utilities/align.hpp"3839BFSClosure::BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits) :40_edge_queue(edge_queue),41_edge_store(edge_store),42_mark_bits(mark_bits),43_current_parent(NULL),44_current_frontier_level(0),45_next_frontier_idx(0),46_prev_frontier_idx(0),47_dfs_fallback_idx(0),48_use_dfs(false) {49}5051static void log_frontier_level_summary(size_t level,52size_t high_idx,53size_t low_idx,54size_t edge_size) {55const size_t nof_edges_in_frontier = high_idx - low_idx;56log_trace(jfr, system)(57"BFS front: " SIZE_FORMAT " edges: " SIZE_FORMAT " size: " SIZE_FORMAT " [KB]",58level,59nof_edges_in_frontier,60(nof_edges_in_frontier * edge_size) / K61);62}6364void BFSClosure::log_completed_frontier() const {65log_frontier_level_summary(_current_frontier_level,66_next_frontier_idx,67_prev_frontier_idx,68_edge_queue->sizeof_edge());69}7071void BFSClosure::log_dfs_fallback() const {72const size_t edge_size = _edge_queue->sizeof_edge();73// first complete summary for frontier in progress74log_frontier_level_summary(_current_frontier_level,75_next_frontier_idx,76_prev_frontier_idx,77edge_size);7879// and then also complete the last frontier80log_frontier_level_summary(_current_frontier_level + 1,81_edge_queue->bottom(),82_next_frontier_idx,83edge_size);8485// additional information about DFS fallover86log_trace(jfr, system)(87"BFS front: " SIZE_FORMAT " filled edge queue at edge: " SIZE_FORMAT,88_current_frontier_level,89_dfs_fallback_idx90);9192const size_t nof_dfs_completed_edges = _edge_queue->bottom() - _dfs_fallback_idx;93log_trace(jfr, system)(94"DFS to complete " SIZE_FORMAT " edges size: " SIZE_FORMAT " [KB]",95nof_dfs_completed_edges,96(nof_dfs_completed_edges * edge_size) / K97);98}99100void BFSClosure::process() {101process_root_set();102process_queue();103}104105void BFSClosure::process_root_set() {106for (size_t idx = _edge_queue->bottom(); idx < _edge_queue->top(); ++idx) {107const Edge* edge = _edge_queue->element_at(idx);108assert(edge->parent() == NULL, "invariant");109process(edge->reference(), edge->pointee());110}111}112113void BFSClosure::process(UnifiedOopRef reference, const oop pointee) {114closure_impl(reference, pointee);115}116void BFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) {117assert(!reference.is_null(), "invariant");118assert(reference.dereference() == pointee, "invariant");119120if (GranularTimer::is_finished()) {121return;122}123124if (_use_dfs) {125assert(_current_parent != NULL, "invariant");126DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent);127return;128}129130if (!_mark_bits->is_marked(pointee)) {131_mark_bits->mark_obj(pointee);132// is the pointee a sample object?133if (pointee->mark().is_marked()) {134add_chain(reference, pointee);135}136137// if we are processinig initial root set, don't add to queue138if (_current_parent != NULL) {139_edge_queue->add(_current_parent, reference);140}141142if (_edge_queue->is_full()) {143dfs_fallback();144}145}146}147148void BFSClosure::add_chain(UnifiedOopRef reference, const oop pointee) {149assert(pointee != NULL, "invariant");150assert(pointee->mark().is_marked(), "invariant");151Edge leak_edge(_current_parent, reference);152_edge_store->put_chain(&leak_edge, _current_parent == NULL ? 1 : _current_frontier_level + 2);153}154155void BFSClosure::dfs_fallback() {156assert(_edge_queue->is_full(), "invariant");157_use_dfs = true;158_dfs_fallback_idx = _edge_queue->bottom();159while (!_edge_queue->is_empty()) {160const Edge* edge = _edge_queue->remove();161if (edge->pointee() != NULL) {162DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, edge);163}164}165}166167void BFSClosure::process_queue() {168assert(_current_frontier_level == 0, "invariant");169assert(_next_frontier_idx == 0, "invariant");170assert(_prev_frontier_idx == 0, "invariant");171172_next_frontier_idx = _edge_queue->top();173while (!is_complete()) {174iterate(_edge_queue->remove()); // edge_queue.remove() increments bottom175}176}177178void BFSClosure::step_frontier() const {179log_completed_frontier();180++_current_frontier_level;181_prev_frontier_idx = _next_frontier_idx;182_next_frontier_idx = _edge_queue->top();183}184185bool BFSClosure::is_complete() const {186if (_edge_queue->bottom() < _next_frontier_idx) {187return false;188}189if (_edge_queue->bottom() > _next_frontier_idx) {190// fallback onto DFS as part of processing the frontier191assert(_dfs_fallback_idx >= _prev_frontier_idx, "invariant");192assert(_dfs_fallback_idx < _next_frontier_idx, "invariant");193log_dfs_fallback();194return true;195}196assert(_edge_queue->bottom() == _next_frontier_idx, "invariant");197if (_edge_queue->is_empty()) {198return true;199}200step_frontier();201return false;202}203204void BFSClosure::iterate(const Edge* parent) {205assert(parent != NULL, "invariant");206const oop pointee = parent->pointee();207assert(pointee != NULL, "invariant");208_current_parent = parent;209pointee->oop_iterate(this);210}211212void BFSClosure::do_oop(oop* ref) {213assert(ref != NULL, "invariant");214assert(is_aligned(ref, HeapWordSize), "invariant");215const oop pointee = HeapAccess<AS_NO_KEEPALIVE>::oop_load(ref);216if (pointee != NULL) {217closure_impl(UnifiedOopRef::encode_in_heap(ref), pointee);218}219}220221void BFSClosure::do_oop(narrowOop* ref) {222assert(ref != NULL, "invariant");223assert(is_aligned(ref, sizeof(narrowOop)), "invariant");224const oop pointee = HeapAccess<AS_NO_KEEPALIVE>::oop_load(ref);225if (pointee != NULL) {226closure_impl(UnifiedOopRef::encode_in_heap(ref), pointee);227}228}229230void BFSClosure::do_root(UnifiedOopRef ref) {231assert(ref.dereference() != NULL, "pointee must not be null");232if (!_edge_queue->is_full()) {233_edge_queue->add(NULL, ref);234}235}236237238