1 /*
   2  * Copyright (c) 2017, 2018, 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 #include "precompiled.hpp"
  25 #include "jfr/jfrEvents.hpp"
  26 #include "jfr/leakprofiler/sampling/objectSample.hpp"
  27 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
  28 #include "jfr/leakprofiler/sampling/sampleList.hpp"
  29 #include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp"
  30 #include "jfr/recorder/jfrEventSetting.inline.hpp"
  31 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
  32 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
  33 #include "jfr/support/jfrThreadLocal.hpp"
  34 #include "jfr/utilities/jfrTryLock.hpp"
  35 #include "memory/universe.hpp"
  36 #include "oops/oop.inline.hpp"
  37 #include "runtime/atomic.hpp"
  38 #include "runtime/orderAccess.hpp"
  39 #include "runtime/safepoint.hpp"
  40 #include "runtime/thread.hpp"
  41 
  42 static ObjectSampler* _instance = NULL;
  43 
  44 static ObjectSampler& instance() {
  45   assert(_instance != NULL, "invariant");
  46   return *_instance;
  47 }
  48 
  49 ObjectSampler::ObjectSampler(size_t size) :
  50   _priority_queue(new SamplePriorityQueue(size)),
  51   _list(new SampleList(size)),
  52   _last_sweep(JfrTicks::now()),
  53   _total_allocated(0),
  54   _threshold(0),
  55   _size(size),
  56   _dead_samples(false) {}
  57 
  58 ObjectSampler::~ObjectSampler() {
  59   delete _priority_queue;
  60   _priority_queue = NULL;
  61   delete _list;
  62   _list = NULL;
  63 }
  64 
  65 bool ObjectSampler::create(size_t size) {
  66   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
  67   assert(_instance == NULL, "invariant");
  68   _instance = new ObjectSampler(size);
  69   return _instance != NULL;
  70 }
  71 
  72 bool ObjectSampler::is_created() {
  73   return _instance != NULL;
  74 }
  75 
  76 ObjectSampler* ObjectSampler::sampler() {
  77   assert(is_created(), "invariant");
  78   return _instance;
  79 }
  80 
  81 void ObjectSampler::destroy() {
  82   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
  83   if (_instance != NULL) {
  84     ObjectSampler* const sampler = _instance;
  85     _instance = NULL;
  86     delete sampler;
  87   }
  88 }
  89 
  90 static volatile int _lock = 0;
  91 
  92 ObjectSampler* ObjectSampler::acquire() {
  93   assert(is_created(), "invariant");
  94   while (Atomic::cmpxchg(1, &_lock, 0) == 1) {}
  95   return _instance;
  96 }
  97 
  98 void ObjectSampler::release() {
  99   assert(is_created(), "invariant");
 100   OrderAccess::fence();
 101   _lock = 0;
 102 }
 103 
 104 static traceid get_thread_id(JavaThread* thread) {
 105   assert(thread != NULL, "invariant");
 106   if (thread->threadObj() == NULL) {
 107     return 0;
 108   }
 109   const JfrThreadLocal* const tl = thread->jfr_thread_local();
 110   assert(tl != NULL, "invariant");
 111   if (!tl->has_thread_checkpoint()) {
 112     JfrCheckpointManager::create_thread_checkpoint(thread);
 113   }
 114   assert(tl->has_thread_checkpoint(), "invariant");
 115   return tl->thread_id();
 116 }
 117 
 118 // Populates the thread local stack frames, but does not add them
 119 // to the stacktrace repository (...yet, see stacktrace_id() below)
 120 //
 121 void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread) {
 122   assert(stacktrace != NULL, "invariant");
 123   assert(thread != NULL, "invariant");
 124   if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
 125     JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0);
 126   }
 127 }
 128 
 129 // We were successful in acquiring the try lock and have been selected for adding a sample.
 130 // Go ahead with installing our previously taken stacktrace into the stacktrace repository.
 131 //
 132 traceid ObjectSampler::stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread) {
 133   assert(stacktrace != NULL, "invariant");
 134   assert(stacktrace->hash() != 0, "invariant");
 135   const traceid stacktrace_id = JfrStackTraceRepository::add(stacktrace, thread);
 136   thread->jfr_thread_local()->set_cached_stack_trace_id(stacktrace_id, stacktrace->hash());
 137   return stacktrace_id;
 138 }
 139 
 140 void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) {
 141   assert(thread != NULL, "invariant");
 142   assert(is_created(), "invariant");
 143 
 144   const traceid thread_id = get_thread_id(thread);
 145   if (thread_id == 0) {
 146     return;
 147   }
 148   const JfrThreadLocal* const tl = thread->jfr_thread_local();
 149   JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
 150   fill_stacktrace(&stacktrace, thread);
 151 
 152   // try enter critical section
 153   JfrTryLock tryLock(&_lock);
 154   if (!tryLock.has_lock()) {
 155     if (LogJFR && Verbose) tty->print_cr("Skipping old object sample due to lock contention");
 156     return;
 157   }
 158 
 159   instance().add(obj, allocated, thread_id, &stacktrace, thread);
 160 }
 161 
 162 void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread) {
 163   assert(stacktrace != NULL, "invariant");
 164   assert(thread_id != 0, "invariant");
 165   assert(thread != NULL, "invariant");
 166   assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
 167 
 168   if (_dead_samples) {
 169     scavenge();
 170     assert(!_dead_samples, "invariant");
 171   }
 172 
 173   _total_allocated += allocated;
 174   const size_t span = _total_allocated - _priority_queue->total();
 175   ObjectSample* sample;
 176   if ((size_t)_priority_queue->count() == _size) {
 177     assert(_list->count() == _size, "invariant");
 178     const ObjectSample* peek = _priority_queue->peek();
 179     if (peek->span() > span) {
 180       // quick reject, will not fit
 181       return;
 182     }
 183     sample = _list->reuse(_priority_queue->pop());
 184   } else {
 185     sample = _list->get();
 186   }
 187 
 188   assert(sample != NULL, "invariant");
 189   sample->set_thread_id(thread_id);
 190   sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
 191 
 192   const unsigned int stacktrace_hash = stacktrace->hash();
 193   if (stacktrace_hash != 0) {
 194     sample->set_stack_trace_id(stacktrace_id(stacktrace, thread));
 195     sample->set_stack_trace_hash(stacktrace_hash);
 196   }
 197 
 198   sample->set_span(allocated);
 199   sample->set_object((oop)obj);
 200   sample->set_allocated(allocated);
 201   sample->set_allocation_time(JfrTicks::now());
 202   sample->set_heap_used_at_last_gc(Universe::get_heap_used_at_last_gc());
 203   _priority_queue->push(sample);
 204 }
 205 
 206 void ObjectSampler::scavenge() {
 207   ObjectSample* current = _list->last();
 208   while (current != NULL) {
 209     ObjectSample* next = current->next();
 210     if (current->is_dead()) {
 211       remove_dead(current);
 212     }
 213     current = next;
 214   }
 215   _dead_samples = false;
 216 }
 217 
 218 void ObjectSampler::remove_dead(ObjectSample* sample) {
 219   assert(sample != NULL, "invariant");
 220   assert(sample->is_dead(), "invariant");
 221   ObjectSample* const previous = sample->prev();
 222   // push span on to previous
 223   if (previous != NULL) {
 224     _priority_queue->remove(previous);
 225     previous->add_span(sample->span());
 226     _priority_queue->push(previous);
 227   }
 228   _priority_queue->remove(sample);
 229   _list->release(sample);
 230 }
 231 
 232 void ObjectSampler::oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
 233   assert(is_created(), "invariant");
 234   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
 235   ObjectSampler& sampler = instance();
 236   ObjectSample* current = sampler._list->last();
 237   while (current != NULL) {
 238     ObjectSample* next = current->next();
 239     if (!current->is_dead()) {
 240       if (is_alive->do_object_b(current->object())) {
 241         // The weakly referenced object is alive, update pointer
 242         f->do_oop(const_cast<oop*>(current->object_addr()));
 243       } else {
 244         current->set_dead();
 245         sampler._dead_samples = true;
 246       }
 247     }
 248     current = next;
 249   }
 250   sampler._last_sweep = JfrTicks::now();
 251 }
 252 
 253 const ObjectSample* ObjectSampler::last() const {
 254   return _list->last();
 255 }
 256 
 257 const ObjectSample* ObjectSampler::first() const {
 258   return _list->first();
 259 }
 260 
 261 const ObjectSample* ObjectSampler::last_resolved() const {
 262   return _list->last_resolved();
 263 }
 264 
 265 void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
 266   _list->set_last_resolved(sample);
 267 }
 268 
 269 int ObjectSampler::item_count() const {
 270   return _priority_queue->count();
 271 }
 272 
 273 const ObjectSample* ObjectSampler::item_at(int index) const {
 274   return _priority_queue->item_at(index);
 275 }
 276 
 277 ObjectSample* ObjectSampler::item_at(int index) {
 278   return const_cast<ObjectSample*>(
 279     const_cast<const ObjectSampler*>(this)->item_at(index)
 280                                   );
 281 }
 282 
 283 const JfrTicks& ObjectSampler::last_sweep() const {
 284   return _last_sweep;
 285 }