1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/jfr/leakprofiler/sampling/objectSampler.cpp Mon Aug 12 18:30:40 2019 +0300 1.3 @@ -0,0 +1,192 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 +#include "precompiled.hpp" 1.28 +#include "jfr/jfrEvents.hpp" 1.29 +#include "jfr/leakprofiler/sampling/objectSample.hpp" 1.30 +#include "jfr/leakprofiler/sampling/objectSampler.hpp" 1.31 +#include "jfr/leakprofiler/sampling/sampleList.hpp" 1.32 +#include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp" 1.33 +#include "jfr/recorder/jfrEventSetting.inline.hpp" 1.34 +#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" 1.35 +#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 1.36 +#include "jfr/support/jfrThreadLocal.hpp" 1.37 +#include "jfr/utilities/jfrTryLock.hpp" 1.38 +#include "memory/universe.hpp" 1.39 +#include "oops/oop.inline.hpp" 1.40 +#include "runtime/thread.hpp" 1.41 + 1.42 +ObjectSampler::ObjectSampler(size_t size) : 1.43 + _priority_queue(new SamplePriorityQueue(size)), 1.44 + _list(new SampleList(size)), 1.45 + _last_sweep(JfrTicks::now()), 1.46 + _total_allocated(0), 1.47 + _threshold(0), 1.48 + _size(size), 1.49 + _tryLock(0), 1.50 + _dead_samples(false) {} 1.51 + 1.52 +ObjectSampler::~ObjectSampler() { 1.53 + delete _priority_queue; 1.54 + _priority_queue = NULL; 1.55 + delete _list; 1.56 + _list = NULL; 1.57 +} 1.58 + 1.59 +void ObjectSampler::add(HeapWord* obj, size_t allocated, JavaThread* thread) { 1.60 + assert(thread != NULL, "invariant"); 1.61 + const traceid thread_id = thread->threadObj() != NULL ? thread->jfr_thread_local()->thread_id() : 0; 1.62 + if (thread_id == 0) { 1.63 + return; 1.64 + } 1.65 + assert(thread_id != 0, "invariant"); 1.66 + 1.67 + if (!thread->jfr_thread_local()->has_thread_checkpoint()) { 1.68 + JfrCheckpointManager::create_thread_checkpoint(thread); 1.69 + assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant"); 1.70 + } 1.71 + 1.72 + traceid stack_trace_id = 0; 1.73 + unsigned int stack_trace_hash = 0; 1.74 + if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) { 1.75 + stack_trace_id = JfrStackTraceRepository::record(thread, 0, &stack_trace_hash); 1.76 + thread->jfr_thread_local()->set_cached_stack_trace_id(stack_trace_id, stack_trace_hash); 1.77 + } 1.78 + 1.79 + JfrTryLock tryLock(&_tryLock); 1.80 + if (!tryLock.has_lock()) { 1.81 + if (LogJFR && Verbose) tty->print_cr("Skipping old object sample due to lock contention"); 1.82 + return; 1.83 + } 1.84 + 1.85 + if (_dead_samples) { 1.86 + scavenge(); 1.87 + assert(!_dead_samples, "invariant"); 1.88 + } 1.89 + 1.90 + _total_allocated += allocated; 1.91 + const size_t span = _total_allocated - _priority_queue->total(); 1.92 + ObjectSample* sample; 1.93 + if ((size_t)_priority_queue->count() == _size) { 1.94 + assert(_list->count() == _size, "invariant"); 1.95 + const ObjectSample* peek = _priority_queue->peek(); 1.96 + if (peek->span() > span) { 1.97 + // quick reject, will not fit 1.98 + return; 1.99 + } 1.100 + sample = _list->reuse(_priority_queue->pop()); 1.101 + } else { 1.102 + sample = _list->get(); 1.103 + } 1.104 + 1.105 + assert(sample != NULL, "invariant"); 1.106 + assert(thread_id != 0, "invariant"); 1.107 + sample->set_thread_id(thread_id); 1.108 + sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint()); 1.109 + 1.110 + if (stack_trace_id != 0) { 1.111 + sample->set_stack_trace_id(stack_trace_id); 1.112 + sample->set_stack_trace_hash(stack_trace_hash); 1.113 + } 1.114 + 1.115 + sample->set_span(allocated); 1.116 + sample->set_object((oop)obj); 1.117 + sample->set_allocated(allocated); 1.118 + sample->set_allocation_time(JfrTicks::now()); 1.119 + sample->set_heap_used_at_last_gc(Universe::get_heap_used_at_last_gc()); 1.120 + _priority_queue->push(sample); 1.121 +} 1.122 + 1.123 +const ObjectSample* ObjectSampler::last() const { 1.124 + return _list->last(); 1.125 +} 1.126 + 1.127 +const ObjectSample* ObjectSampler::last_resolved() const { 1.128 + return _list->last_resolved(); 1.129 +} 1.130 + 1.131 +void ObjectSampler::set_last_resolved(const ObjectSample* sample) { 1.132 + _list->set_last_resolved(sample); 1.133 +} 1.134 + 1.135 +void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) { 1.136 + ObjectSample* current = _list->last(); 1.137 + while (current != NULL) { 1.138 + ObjectSample* next = current->next(); 1.139 + if (!current->is_dead()) { 1.140 + if (is_alive->do_object_b(current->object())) { 1.141 + // The weakly referenced object is alive, update pointer 1.142 + f->do_oop(const_cast<oop*>(current->object_addr())); 1.143 + } else { 1.144 + current->set_dead(); 1.145 + _dead_samples = true; 1.146 + } 1.147 + } 1.148 + current = next; 1.149 + } 1.150 + _last_sweep = JfrTicks::now(); 1.151 +} 1.152 + 1.153 +void ObjectSampler::remove_dead(ObjectSample* sample) { 1.154 + assert(sample != NULL, "invariant"); 1.155 + assert(sample->is_dead(), "invariant"); 1.156 + ObjectSample* const previous = sample->prev(); 1.157 + // push span on to previous 1.158 + if (previous != NULL) { 1.159 + _priority_queue->remove(previous); 1.160 + previous->add_span(sample->span()); 1.161 + _priority_queue->push(previous); 1.162 + } 1.163 + _priority_queue->remove(sample); 1.164 + _list->release(sample); 1.165 +} 1.166 + 1.167 +void ObjectSampler::scavenge() { 1.168 + ObjectSample* current = _list->last(); 1.169 + while (current != NULL) { 1.170 + ObjectSample* next = current->next(); 1.171 + if (current->is_dead()) { 1.172 + remove_dead(current); 1.173 + } 1.174 + current = next; 1.175 + } 1.176 + _dead_samples = false; 1.177 +} 1.178 + 1.179 +int ObjectSampler::item_count() const { 1.180 + return _priority_queue->count(); 1.181 +} 1.182 + 1.183 +const ObjectSample* ObjectSampler::item_at(int index) const { 1.184 + return _priority_queue->item_at(index); 1.185 +} 1.186 + 1.187 +ObjectSample* ObjectSampler::item_at(int index) { 1.188 + return const_cast<ObjectSample*>( 1.189 + const_cast<const ObjectSampler*>(this)->item_at(index) 1.190 + ); 1.191 +} 1.192 + 1.193 +const JfrTicks& ObjectSampler::last_sweep() const { 1.194 + return _last_sweep; 1.195 +}