src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp
changeset 55571 49102ba8cf14
child 57777 90ead0febf56
equal deleted inserted replaced
55570:1e95931e7d8f 55571:49102ba8cf14
       
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     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
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "jfr/jfrEvents.hpp"
       
    27 #include "jfr/leakprofiler/chains/edgeStore.hpp"
       
    28 #include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp"
       
    29 #include "jfr/leakprofiler/checkpoint/eventEmitter.hpp"
       
    30 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
       
    31 #include "jfr/leakprofiler/sampling/objectSample.hpp"
       
    32 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
       
    33 #include "logging/log.hpp"
       
    34 #include "memory/resourceArea.hpp"
       
    35 #include "oops/markOop.hpp"
       
    36 #include "oops/oop.inline.hpp"
       
    37 #include "runtime/thread.inline.hpp"
       
    38 #include "runtime/vmThread.hpp"
       
    39 
       
    40 EventEmitter::EventEmitter(const JfrTicks& start_time, const JfrTicks& end_time) :
       
    41   _start_time(start_time),
       
    42   _end_time(end_time),
       
    43   _thread(Thread::current()),
       
    44   _jfr_thread_local(_thread->jfr_thread_local()),
       
    45   _thread_id(_thread->jfr_thread_local()->thread_id()) {}
       
    46 
       
    47 EventEmitter::~EventEmitter() {
       
    48   // restore / reset thread local stack trace and thread id
       
    49   _jfr_thread_local->set_thread_id(_thread_id);
       
    50   _jfr_thread_local->clear_cached_stack_trace();
       
    51 }
       
    52 
       
    53 void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all) {
       
    54   assert(sampler != NULL, "invariant");
       
    55 
       
    56   ResourceMark rm;
       
    57   EdgeStore edge_store;
       
    58   if (cutoff_ticks <= 0) {
       
    59     // no reference chains
       
    60     JfrTicks time_stamp = JfrTicks::now();
       
    61     EventEmitter emitter(time_stamp, time_stamp);
       
    62     emitter.write_events(sampler, &edge_store, emit_all);
       
    63     return;
       
    64   }
       
    65   // events emitted with reference chains require a safepoint operation
       
    66   PathToGcRootsOperation op(sampler, &edge_store, cutoff_ticks, emit_all);
       
    67   VMThread::execute(&op);
       
    68 }
       
    69 
       
    70 size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) {
       
    71   assert(_thread == Thread::current(), "invariant");
       
    72   assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant");
       
    73   assert(object_sampler != NULL, "invariant");
       
    74   assert(edge_store != NULL, "invariant");
       
    75 
       
    76   const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
       
    77   size_t count = 0;
       
    78 
       
    79   const ObjectSample* current = object_sampler->first();
       
    80   while (current != NULL) {
       
    81     ObjectSample* prev = current->prev();
       
    82     if (current->is_alive_and_older_than(last_sweep)) {
       
    83       write_event(current, edge_store);
       
    84       ++count;
       
    85     }
       
    86     current = prev;
       
    87   }
       
    88 
       
    89   if (count > 0) {
       
    90     // serialize associated checkpoints and potential chains
       
    91     ObjectSampleCheckpoint::write(object_sampler, edge_store, emit_all, _thread);
       
    92   }
       
    93   return count;
       
    94 }
       
    95 
       
    96 static int array_size(const oop object) {
       
    97   assert(object != NULL, "invariant");
       
    98   if (object->is_array()) {
       
    99     return arrayOop(object)->length();
       
   100   }
       
   101   return min_jint;
       
   102 }
       
   103 
       
   104 void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store) {
       
   105   assert(sample != NULL, "invariant");
       
   106   assert(!sample->is_dead(), "invariant");
       
   107   assert(edge_store != NULL, "invariant");
       
   108   assert(_jfr_thread_local != NULL, "invariant");
       
   109 
       
   110   const oop* object_addr = sample->object_addr();
       
   111   traceid gc_root_id = 0;
       
   112   const Edge* edge = NULL;
       
   113   if (SafepointSynchronize::is_at_safepoint()) {
       
   114     edge = (const Edge*)(*object_addr)->mark();
       
   115   }
       
   116   if (edge == NULL) {
       
   117     // In order to dump out a representation of the event
       
   118     // even though it was not reachable / too long to reach,
       
   119     // we need to register a top level edge for this object.
       
   120     edge = edge_store->put(object_addr);
       
   121   } else {
       
   122     gc_root_id = edge_store->gc_root_id(edge);
       
   123   }
       
   124 
       
   125   assert(edge != NULL, "invariant");
       
   126   const traceid object_id = edge_store->get_id(edge);
       
   127   assert(object_id != 0, "invariant");
       
   128 
       
   129   EventOldObjectSample e(UNTIMED);
       
   130   e.set_starttime(_start_time);
       
   131   e.set_endtime(_end_time);
       
   132   e.set_allocationTime(sample->allocation_time());
       
   133   e.set_lastKnownHeapUsage(sample->heap_used_at_last_gc());
       
   134   e.set_object(object_id);
       
   135   e.set_arrayElements(array_size(edge->pointee()));
       
   136   e.set_root(gc_root_id);
       
   137 
       
   138   // Temporarily assigning both the stack trace id and thread id
       
   139   // onto the thread local data structure of the emitter thread (for the duration
       
   140   // of the commit() call). This trick provides a means to override
       
   141   // the event generation mechanism by injecting externally provided id's.
       
   142   // At this particular location, it allows us to emit an old object event
       
   143   // supplying information from where the actual sampling occurred.
       
   144   _jfr_thread_local->set_cached_stack_trace_id(sample->stack_trace_id());
       
   145   assert(sample->has_thread(), "invariant");
       
   146   _jfr_thread_local->set_thread_id(sample->thread_id());
       
   147   e.commit();
       
   148 }