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 "memory/resourceArea.hpp" 34 #include "oops/markOop.hpp" 35 #include "oops/oop.inline.hpp" 36 #include "runtime/thread.inline.hpp" 37 #include "runtime/vmThread.hpp" 38 39 EventEmitter::EventEmitter(const JfrTicks& start_time, const JfrTicks& end_time) : 40 _start_time(start_time), 41 _end_time(end_time), 42 _thread(Thread::current()), 43 _jfr_thread_local(_thread->jfr_thread_local()), 44 _thread_id(_thread->jfr_thread_local()->thread_id()) {} 45 46 EventEmitter::~EventEmitter() { 47 // restore / reset thread local stack trace and thread id 48 _jfr_thread_local->set_thread_id(_thread_id); 49 _jfr_thread_local->clear_cached_stack_trace(); 50 } 51 52 void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all) { 53 assert(sampler != NULL, "invariant"); 54 55 ResourceMark rm; 56 EdgeStore edge_store; 57 if (cutoff_ticks <= 0) { 58 // no reference chains 59 JfrTicks time_stamp = JfrTicks::now(); 60 EventEmitter emitter(time_stamp, time_stamp); 61 emitter.write_events(sampler, &edge_store, emit_all); 62 return; 63 } 64 // events emitted with reference chains require a safepoint operation 65 PathToGcRootsOperation op(sampler, &edge_store, cutoff_ticks, emit_all); 66 VMThread::execute(&op); 67 } 68 69 size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) { 70 assert(_thread == Thread::current(), "invariant"); 71 assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant"); 72 assert(object_sampler != NULL, "invariant"); 73 assert(edge_store != NULL, "invariant"); 74 75 const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value(); 76 size_t count = 0; 77 78 const ObjectSample* current = object_sampler->first(); 79 while (current != NULL) { 80 ObjectSample* prev = current->prev(); 81 if (current->is_alive_and_older_than(last_sweep)) { 82 write_event(current, edge_store); 83 ++count; 84 } 85 current = prev; 86 } 87 88 if (count > 0) { 89 // serialize associated checkpoints and potential chains 90 ObjectSampleCheckpoint::write(object_sampler, edge_store, emit_all, _thread); 91 } 92 return count; 93 } 94 95 static int array_size(const oop object) { 96 assert(object != NULL, "invariant"); 97 if (object->is_array()) { 98 return arrayOop(object)->length(); 99 } 100 return min_jint; 101 } 102 103 void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store) { 104 assert(sample != NULL, "invariant"); 105 assert(!sample->is_dead(), "invariant"); 106 assert(edge_store != NULL, "invariant"); 107 assert(_jfr_thread_local != NULL, "invariant"); 108 109 const oop* object_addr = sample->object_addr(); 110 traceid gc_root_id = 0; 111 const Edge* edge = NULL; 112 if (SafepointSynchronize::is_at_safepoint()) { 113 edge = (const Edge*)(*object_addr)->mark(); 114 } 115 if (edge == NULL) { 116 // In order to dump out a representation of the event 117 // even though it was not reachable / too long to reach, 118 // we need to register a top level edge for this object. 119 edge = edge_store->put(object_addr); 120 } else { 121 gc_root_id = edge_store->gc_root_id(edge); 122 } 123 124 assert(edge != NULL, "invariant"); 125 const traceid object_id = edge_store->get_id(edge); 126 assert(object_id != 0, "invariant"); 127 128 EventOldObjectSample e(UNTIMED); 129 e.set_starttime(_start_time); 130 e.set_endtime(_end_time); 131 e.set_allocationTime(sample->allocation_time()); 132 e.set_lastKnownHeapUsage(sample->heap_used_at_last_gc()); 133 e.set_object(object_id); 134 e.set_arrayElements(array_size(edge->pointee())); 135 e.set_root(gc_root_id); 136 137 // Temporarily assigning both the stack trace id and thread id 138 // onto the thread local data structure of the emitter thread (for the duration 139 // of the commit() call). This trick provides a means to override 140 // the event generation mechanism by injecting externally provided id's. 141 // At this particular location, it allows us to emit an old object event 142 // supplying information from where the actual sampling occurred. 143 _jfr_thread_local->set_cached_stack_trace_id(sample->stack_trace_id()); 144 assert(sample->has_thread(), "invariant"); 145 _jfr_thread_local->set_thread_id(sample->thread_id()); 146 e.commit(); 147 }