Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/jfr/leakprofiler/checkpoint/eventEmitter.cpp
38922 views
/*1* Copyright (c) 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*/2324#include "precompiled.hpp"25#include "jfr/jfrEvents.hpp"26#include "jfr/leakprofiler/chains/edgeStore.hpp"27#include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp"28#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"29#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"30#include "jfr/leakprofiler/sampling/objectSample.hpp"31#include "jfr/leakprofiler/sampling/objectSampler.hpp"32#include "memory/resourceArea.hpp"33#include "oops/markOop.hpp"34#include "oops/oop.inline.hpp"35#include "runtime/thread.inline.hpp"36#include "runtime/vmThread.hpp"3738EventEmitter::EventEmitter(const JfrTicks& start_time, const JfrTicks& end_time) :39_start_time(start_time),40_end_time(end_time),41_thread(Thread::current()),42_jfr_thread_local(_thread->jfr_thread_local()),43_thread_id(_thread->jfr_thread_local()->thread_id()) {}4445EventEmitter::~EventEmitter() {46// restore / reset thread local stack trace and thread id47_jfr_thread_local->set_thread_id(_thread_id);48_jfr_thread_local->clear_cached_stack_trace();49}5051void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all) {52assert(sampler != NULL, "invariant");5354ResourceMark rm;55EdgeStore edge_store;56if (cutoff_ticks <= 0) {57// no reference chains58JfrTicks time_stamp = JfrTicks::now();59EventEmitter emitter(time_stamp, time_stamp);60emitter.write_events(sampler, &edge_store, emit_all);61return;62}63// events emitted with reference chains require a safepoint operation64PathToGcRootsOperation op(sampler, &edge_store, cutoff_ticks, emit_all);65VMThread::execute(&op);66}6768size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) {69assert(_thread == Thread::current(), "invariant");70assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant");71assert(object_sampler != NULL, "invariant");72assert(edge_store != NULL, "invariant");7374const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();75size_t count = 0;7677const ObjectSample* current = object_sampler->first();78while (current != NULL) {79ObjectSample* prev = current->prev();80if (current->is_alive_and_older_than(last_sweep)) {81write_event(current, edge_store);82++count;83}84current = prev;85}8687if (count > 0) {88// serialize associated checkpoints and potential chains89ObjectSampleCheckpoint::write(object_sampler, edge_store, emit_all, _thread);90}91return count;92}9394static int array_size(const oop object) {95assert(object != NULL, "invariant");96if (object->is_array()) {97return arrayOop(object)->length();98}99return min_jint;100}101102void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store) {103assert(sample != NULL, "invariant");104assert(!sample->is_dead(), "invariant");105assert(edge_store != NULL, "invariant");106assert(_jfr_thread_local != NULL, "invariant");107108const oop* object_addr = sample->object_addr();109traceid gc_root_id = 0;110const Edge* edge = NULL;111if (SafepointSynchronize::is_at_safepoint()) {112edge = (const Edge*)(*object_addr)->mark();113}114if (edge == NULL) {115// In order to dump out a representation of the event116// even though it was not reachable / too long to reach,117// we need to register a top level edge for this object.118edge = edge_store->put(object_addr);119} else {120gc_root_id = edge_store->gc_root_id(edge);121}122123assert(edge != NULL, "invariant");124const traceid object_id = edge_store->get_id(edge);125assert(object_id != 0, "invariant");126127EventOldObjectSample e(UNTIMED);128e.set_starttime(_start_time);129e.set_endtime(_end_time);130e.set_allocationTime(sample->allocation_time());131e.set_lastKnownHeapUsage(sample->heap_used_at_last_gc());132e.set_object(object_id);133e.set_arrayElements(array_size(edge->pointee()));134e.set_root(gc_root_id);135136// Temporarily assigning both the stack trace id and thread id137// onto the thread local data structure of the emitter thread (for the duration138// of the commit() call). This trick provides a means to override139// the event generation mechanism by injecting externally provided id's.140// At this particular location, it allows us to emit an old object event141// supplying information from where the actual sampling occurred.142_jfr_thread_local->set_cached_stack_trace_id(sample->stack_trace_id());143assert(sample->has_thread(), "invariant");144_jfr_thread_local->set_thread_id(sample->thread_id());145e.commit();146}147148149