Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/leakprofiler/chains/bfsClosure.cpp
48358 views
/*1* Copyright (c) 2014, 2019, 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.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/unifiedOop.hpp"32#include "memory/iterator.inline.hpp"33#include "memory/resourceArea.hpp"34#include "oops/oop.inline.hpp"35#include "utilities/align.hpp"3637BFSClosure::BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits) :38_edge_queue(edge_queue),39_edge_store(edge_store),40_mark_bits(mark_bits),41_current_parent(NULL),42_current_frontier_level(0),43_next_frontier_idx(0),44_prev_frontier_idx(0),45_dfs_fallback_idx(0),46_use_dfs(false) {47}4849static void log_frontier_level_summary(size_t level,50size_t high_idx,51size_t low_idx,52size_t edge_size) {53const size_t nof_edges_in_frontier = high_idx - low_idx;54if (LogJFR && Verbose) tty->print_cr(55"BFS front: " SIZE_FORMAT " edges: " SIZE_FORMAT " size: " SIZE_FORMAT " [KB]",56level,57nof_edges_in_frontier,58(nof_edges_in_frontier * edge_size) / K59);60}6162void BFSClosure::log_completed_frontier() const {63log_frontier_level_summary(_current_frontier_level,64_next_frontier_idx,65_prev_frontier_idx,66_edge_queue->sizeof_edge());67}6869void BFSClosure::log_dfs_fallback() const {70const size_t edge_size = _edge_queue->sizeof_edge();71// first complete summary for frontier in progress72log_frontier_level_summary(_current_frontier_level,73_next_frontier_idx,74_prev_frontier_idx,75edge_size);7677// and then also complete the last frontier78log_frontier_level_summary(_current_frontier_level + 1,79_edge_queue->bottom(),80_next_frontier_idx,81edge_size);8283// additional information about DFS fallover84if (LogJFR && Verbose) tty->print_cr(85"BFS front: " SIZE_FORMAT " filled edge queue at edge: " SIZE_FORMAT,86_current_frontier_level,87_dfs_fallback_idx88);8990const size_t nof_dfs_completed_edges = _edge_queue->bottom() - _dfs_fallback_idx;91if (LogJFR && Verbose) tty->print_cr(92"DFS to complete " SIZE_FORMAT " edges size: " SIZE_FORMAT " [KB]",93nof_dfs_completed_edges,94(nof_dfs_completed_edges * edge_size) / K95);96}9798void BFSClosure::process() {99process_root_set();100process_queue();101}102103void BFSClosure::process_root_set() {104for (size_t idx = _edge_queue->bottom(); idx < _edge_queue->top(); ++idx) {105const Edge* edge = _edge_queue->element_at(idx);106assert(edge->parent() == NULL, "invariant");107process(edge->reference(), edge->pointee());108}109}110111void BFSClosure::process(const oop* reference, const oop pointee) {112closure_impl(reference, pointee);113}114void BFSClosure::closure_impl(const oop* reference, const oop pointee) {115assert(reference != NULL, "invariant");116assert(UnifiedOop::dereference(reference) == pointee, "invariant");117118if (GranularTimer::is_finished()) {119return;120}121122if (_use_dfs) {123assert(_current_parent != NULL, "invariant");124DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent);125return;126}127128if (!_mark_bits->is_marked(pointee)) {129_mark_bits->mark_obj(pointee);130// is the pointee a sample object?131if (NULL == pointee->mark()) {132add_chain(reference, pointee);133}134135// if we are processinig initial root set, don't add to queue136if (_current_parent != NULL) {137_edge_queue->add(_current_parent, reference);138}139140if (_edge_queue->is_full()) {141dfs_fallback();142}143}144}145146void BFSClosure::add_chain(const oop* reference, const oop pointee) {147assert(pointee != NULL, "invariant");148assert(NULL == pointee->mark(), "invariant");149Edge leak_edge(_current_parent, reference);150_edge_store->put_chain(&leak_edge, _current_parent == NULL ? 1 : _current_frontier_level + 2);151}152153void BFSClosure::dfs_fallback() {154assert(_edge_queue->is_full(), "invariant");155_use_dfs = true;156_dfs_fallback_idx = _edge_queue->bottom();157while (!_edge_queue->is_empty()) {158const Edge* edge = _edge_queue->remove();159if (edge->pointee() != NULL) {160DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, edge);161}162}163}164165void BFSClosure::process_queue() {166assert(_current_frontier_level == 0, "invariant");167assert(_next_frontier_idx == 0, "invariant");168assert(_prev_frontier_idx == 0, "invariant");169170_next_frontier_idx = _edge_queue->top();171while (!is_complete()) {172iterate(_edge_queue->remove()); // edge_queue.remove() increments bottom173}174}175176void BFSClosure::step_frontier() const {177log_completed_frontier();178++_current_frontier_level;179_prev_frontier_idx = _next_frontier_idx;180_next_frontier_idx = _edge_queue->top();181}182183bool BFSClosure::is_complete() const {184if (_edge_queue->bottom() < _next_frontier_idx) {185return false;186}187if (_edge_queue->bottom() > _next_frontier_idx) {188// fallback onto DFS as part of processing the frontier189assert(_dfs_fallback_idx >= _prev_frontier_idx, "invariant");190assert(_dfs_fallback_idx < _next_frontier_idx, "invariant");191log_dfs_fallback();192return true;193}194assert(_edge_queue->bottom() == _next_frontier_idx, "invariant");195if (_edge_queue->is_empty()) {196return true;197}198step_frontier();199return false;200}201202void BFSClosure::iterate(const Edge* parent) {203assert(parent != NULL, "invariant");204const oop pointee = parent->pointee();205assert(pointee != NULL, "invariant");206_current_parent = parent;207pointee->oop_iterate(this);208}209210void BFSClosure::do_oop(oop* ref) {211assert(ref != NULL, "invariant");212assert(is_aligned(ref, HeapWordSize), "invariant");213const oop pointee = *ref;214if (pointee != NULL) {215closure_impl(ref, pointee);216}217}218219void BFSClosure::do_oop(narrowOop* ref) {220assert(ref != NULL, "invariant");221assert(is_aligned(ref, sizeof(narrowOop)), "invariant");222const oop pointee = oopDesc::load_decode_heap_oop(ref);223if (pointee != NULL) {224closure_impl(UnifiedOop::encode(ref), pointee);225}226}227228void BFSClosure::do_root(const oop* ref) {229assert(ref != NULL, "invariant");230if (!_edge_queue->is_full()) {231_edge_queue->add(NULL, ref);232}233}234235236