1 /*
   2  * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
   3  *
   4  * This file is part of the Lock Contention Tracing Subsystem for the HotSpot
   5  * Virtual Machine, which is developed at Christian Doppler Laboratory on
   6  * Monitoring and Evolution of Very-Large-Scale Software Systems. Please
   7  * contact us at <http://mevss.jku.at/> if you need additional information
   8  * or have any questions.
   9  *
  10  * This code is free software; you can redistribute it and/or modify it
  11  * under the terms of the GNU General Public License version 2 only, as
  12  * published by the Free Software Foundation.
  13  *
  14  * This code is distributed in the hope that it will be useful, but WITHOUT
  15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17  * version 2 for more details (a copy is included in the LICENSE file that
  18  * accompanied this code).
  19  *
  20  * You should have received a copy of the GNU General Public License version
  21  * 2 along with this work. If not, see <http://www.gnu.org/licenses/>.
  22  *
  23  */
  24 
  25 #include "evtrace/traceStack.hpp"
  26 
  27 #include "evtrace/traceEvents.hpp"
  28 #include "evtrace/traceMetadata.hpp"
  29 
  30 #include "runtime/vframe.hpp"
  31 #include "runtime/init.hpp"
  32 
  33 //
  34 // TraceStackBuilder
  35 //
  36 
  37 void TraceStackBuilder::add(const TraceStackFrame &f) {
  38   assert(!is_full(), "already full");
  39   _frames[_count] = f;
  40   _hash ^= f.hash();
  41   _count++;
  42 }
  43 
  44 void TraceStackBuilder::add_frame(const frame *fr) {
  45   TraceStackFrame f;
  46   f.is_compiled = fr->cb()->is_nmethod();
  47   if (f.is_compiled) {
  48     assert(fr->is_compiled_frame() || fr->is_native_frame(), "unsupported frame type");
  49     f.compiled.pc = fr->pc();
  50     f.compiled.nm = (nmethod *) fr->cb();
  51   } else {
  52     assert(fr->is_interpreted_frame(), "unsupported frame type");
  53     f.interpreted.method = fr->interpreter_frame_method();
  54     f.interpreted.bci = fr->interpreter_frame_bci();
  55   }
  56   add(f);
  57 }
  58 
  59 bool TraceStackBuilder::range_equals(size_t offset, const CachedTraceStack *cts, size_t cts_offset, size_t count) const {
  60   for (size_t i = 0; i < count; i++) {
  61     if (!frame_at(offset + i)->equals(*cts->frame_at(cts_offset + i))) {
  62       return false;
  63     }
  64   }
  65   return true;
  66 }
  67 
  68 //
  69 // CachedTraceStack
  70 //
  71 
  72 CachedTraceStack *CachedTraceStack::create(TraceTypes::stack_id id, const CompositeTraceStack &ts) {
  73   assert (in_bytes(byte_offset_of(CachedTraceStack, _frames)) == sizeof(CachedTraceStack),
  74       "variable-sized frame array must be last field");
  75   return new (ts.count()) CachedTraceStack(id, ts);
  76 }
  77 
  78 void* CachedTraceStack::operator new(size_t size, size_t nframes) throw () {
  79   return CHeapObj<mtEventTracing>::operator new(size + sizeof(_frames[0]) * nframes, CALLER_PC);
  80 }
  81 
  82 void CachedTraceStack::operator delete(void* p) {
  83   CHeapObj<mtEventTracing>::operator delete(p);
  84 }
  85 
  86 CachedTraceStack::CachedTraceStack(TraceTypes::stack_id id, const CompositeTraceStack& ts)
  87   : _id(id),
  88     _count(ts.count()),
  89     _hash(ts.hash()),
  90     _truncated(ts.is_truncated()),
  91     _valid(true)
  92 {
  93   for (size_t i = 0; i < ts.count(); i++) {
  94     _frames[i] = *ts.frame_at(i);
  95   }
  96 }
  97 
  98 bool CachedTraceStack::has_interpreted_method_from_classloader(const ClassLoaderData* loader) const {
  99   assert(is_valid(), "sanity");
 100   for (size_t i = 0; i < _count; i++) {
 101     if (!_frames[i].is_compiled && _frames[i].interpreted.method->method_holder()->class_loader_data() == loader) {
 102       return true;
 103     }
 104   }
 105   return false;
 106 }
 107 
 108 bool CachedTraceStack::has_nmethod(const nmethod *nm) const {
 109   assert(is_valid(), "sanity");
 110   for (size_t i = 0; i < _count; i++) {
 111     if (_frames[i].is_compiled && _frames[i].compiled.nm == nm) {
 112       return true;
 113     }
 114   }
 115   return false;
 116 }
 117 
 118 bool CachedTraceStack::range_equals(size_t offset, const CachedTraceStack *other, size_t other_offset, size_t count) const {
 119   for (size_t i = 0; i < count; i++) {
 120     if (!frame_at(offset + i)->equals(*other->frame_at(other_offset + i))) {
 121       return false;
 122     }
 123   }
 124   return true;
 125 }
 126 
 127 //
 128 // CompositeTraceStack
 129 //
 130 
 131 void CompositeTraceStack::set_bottom(const CachedTraceStack *bottom, size_t offset) {
 132   _hash = _top.hash();
 133   _count = _top.count();
 134   _truncated = _top.is_truncated();
 135 
 136   _bottom = bottom;
 137   _bottom_offset = offset;
 138   if (bottom != NULL) {
 139     if (_top.count() < EventTracingStackDepthLimit) {
 140       assert(!_top.is_truncated(), "missing frames between top and bottom");
 141       _count += bottom->count() - offset;
 142       _truncated = _truncated || bottom->is_truncated();
 143       if (_count > EventTracingStackDepthLimit) {
 144         _truncated = true;
 145         _count = EventTracingStackDepthLimit;
 146       }
 147       _hash ^= bottom->hash();
 148       // drop frames before offset from hash
 149       for (size_t i = 0; i < offset; i++) {
 150         _hash ^= bottom->frame_at(i)->hash();
 151       }
 152       // drop truncated frames from hash
 153       for (size_t i = EventTracingStackDepthLimit - _top.count() + offset; i < _bottom->count(); i++) {
 154         _hash ^= bottom->frame_at(i)->hash();
 155       }
 156     } else {
 157       _truncated = _truncated || (bottom->count() > offset);
 158     }
 159   }
 160 
 161 #ifdef ASSERT
 162   intptr_t h = 0;
 163   for (size_t i = 0; i < count(); i++) {
 164     h ^= frame_at(i)->hash();
 165   }
 166   assert(h == hash(), "hash mismatch");
 167 #endif
 168 }
 169 
 170 bool CompositeTraceStack::equals(const CachedTraceStack* cts) const {
 171   if (hash() != cts->hash() || count() != cts->count() || is_truncated() != cts->is_truncated()) {
 172     return false;
 173   }
 174   return _top.range_equals(0, cts, 0, _top.count())
 175       && (_bottom == NULL || _bottom->range_equals(_bottom_offset, cts, _top.count(), count() - _top.count()));
 176 }
 177 
 178 bool CompositeTraceStack::equals(const CompositeTraceStack &other) const {
 179   if (hash() != other.hash() || count() != other.count() || is_truncated() != other.is_truncated()) {
 180     return false;
 181   }
 182   for (size_t i = 0; i < count(); i++) {
 183     if (!frame_at(i)->equals(*other.frame_at(i))) {
 184       return false;
 185     }
 186   }
 187   return true;
 188 }
 189 
 190 //
 191 // TraceStackCache
 192 //
 193 
 194 TraceStackCache::TraceStackCache(TraceMetadata *tm)
 195 {
 196   _metadata = tm;
 197 
 198   _table = NULL;
 199   _count = 0;
 200   _has_invalid_stacks = false;
 201 
 202   _lookup_counter = _lookup_miss_counter = _lookup_collision_counter = _probe_counter = _probe_collision_counter = 0;
 203 
 204   _size = (1 << 12);
 205   assert(is_power_of_2(_size), "sanity");
 206   _table = (CachedTraceStack **) os::malloc(_size * sizeof(_table[0]), mtEventTracing, CURRENT_PC);
 207   memset(_table, 0, _size * sizeof(_table[0]));
 208 }
 209 
 210 TraceStackCache::~TraceStackCache() {
 211   for (size_t i = 0; i < _size; i++) {
 212     CachedTraceStack *p = _table[i];
 213     while (p != NULL) {
 214       CachedTraceStack *next = p->cache_next();
 215       delete p;
 216       p = next;
 217     }
 218   }
 219   os::free(_table, mtEventTracing);
 220 }
 221 
 222 void TraceStackCache::add_for_rehash(CachedTraceStack *cts) {
 223   const size_t mask = (_size - 1);
 224   intptr_t index = cts->hash() & mask;
 225   cts->set_cache_next(_table[index]);
 226   _table[index] = cts;
 227   _count++;
 228 }
 229 
 230 inline void TraceStackCache::update_counters_after_lookup(bool present, jlong probes, jlong collisions) {
 231   if (EnableEventTracingDiagnostics) {
 232     Atomic::inc_ptr(&_lookup_counter);
 233     Atomic::add_ptr(probes, &_probe_counter);
 234     if (!present) {
 235       Atomic::inc_ptr(&_lookup_miss_counter);
 236     }
 237     if (collisions > 0) {
 238       Atomic::inc_ptr(&_lookup_collision_counter);
 239       Atomic::add_ptr(collisions, &_probe_collision_counter);
 240     }
 241   }
 242 }
 243 
 244 const CachedTraceStack * TraceStackCache::get_or_try_add(const CompositeTraceStack &ts, bool &known, TraceTypes::stack_id preallocated_id) {
 245   jlong probes = 0, collisions = 0;
 246 
 247   CachedTraceStack *created = NULL;
 248 
 249   const size_t mask = (_size - 1);
 250   const size_t index = ts.hash() & mask;
 251   // XXX: probably need barriers here on non-x86
 252   for(;;) {
 253     CachedTraceStack *head = _table[index];
 254     if (head == NULL) {
 255       probes++;
 256     }
 257     CachedTraceStack *p = head;
 258     while (p != NULL) {
 259       probes++;
 260       if (ts.hash() == p->hash()) {
 261         if (ts.equals(p)) {
 262           delete created;
 263           known = true;
 264           update_counters_after_lookup(true, probes, collisions);
 265           return p;
 266         } else {
 267           collisions++;
 268         }
 269       }
 270       p = p->cache_next();
 271     }
 272     // not found
 273     if (created == NULL) {
 274       TraceTypes::stack_id id = preallocated_id;
 275       if (id == 0) {
 276         id = _metadata->next_stack_id();
 277       }
 278       created = CachedTraceStack::create(id, ts);
 279     }
 280     created->set_cache_next(head);
 281     if (Atomic::cmpxchg_ptr(created, &_table[index], head) == head) {
 282       Atomic::inc_ptr(&_count);
 283       known = false;
 284       update_counters_after_lookup(false, probes, collisions);
 285       return created;
 286     }
 287     // head of collision chain changed: walk the entire chain again in the next
 288     // next iteration to check whether the stack trace has been inserted by
 289     // another thread (head is not enough, multiple threads may have inserted)
 290   }
 291 }
 292 
 293 class TraceStackCache::CachedTraceStackPredicate {
 294 public:
 295   virtual bool test(CachedTraceStack *cts) = 0;
 296 };
 297 
 298 inline void TraceStackCache::purge_matches(TraceStackCache::CachedTraceStackPredicate *pr) {
 299   if (EnableEventTracingDiagnostics) {
 300     _purge_timer.start();
 301   }
 302 
 303   for (size_t i = 0; i < _size; i++) {
 304     CachedTraceStack *p = _table[i];
 305     while (p != NULL) {
 306       if (p->is_valid() && pr->test(p)) {
 307         p->invalidate();
 308         _has_invalid_stacks = true;
 309       }
 310       p = p->cache_next();
 311     }
 312   }
 313 
 314   if (EnableEventTracingDiagnostics) {
 315     _purge_timer.stop();
 316   }
 317 }
 318 
 319 class TraceStackCache::UnloadingClassPredicate : public TraceStackCache::CachedTraceStackPredicate {
 320   const ClassLoaderData *_loader;
 321 public:
 322   UnloadingClassPredicate(const ClassLoaderData *loader) : _loader(loader) { }
 323   virtual bool test(CachedTraceStack *stack) {
 324     return stack->has_interpreted_method_from_classloader(_loader);
 325   }
 326 };
 327 
 328 void TraceStackCache::purge_unloading_classes(const ClassLoaderData* loader) {
 329   assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "must be done in VM thread at safepoint");
 330 
 331   // NOTE: only purges stack traces with *interpreted* frames that refer to
 332   // unloading classes. nmethods with code from unloaded classes are unloaded
 333   // in a later step, at which point we also unload the stack traces that
 334   // contain those nmethods.
 335   UnloadingClassPredicate pr(loader);
 336   purge_matches(&pr);
 337 }
 338 
 339 class TraceStackCache::UnloadingNmethodPredicate : public TraceStackCache::CachedTraceStackPredicate {
 340   const nmethod *_nmethod;
 341 public:
 342   UnloadingNmethodPredicate(const nmethod *nm) : _nmethod(nm) { }
 343   virtual bool test(CachedTraceStack *stack) {
 344     return stack->has_nmethod(_nmethod);
 345   }
 346 };
 347 
 348 void TraceStackCache::purge_unloading_nmethod(const nmethod *nm) {
 349   UnloadingNmethodPredicate pr(nm);
 350   purge_matches(&pr);
 351 }
 352 
 353 class TraceStackCache::AnyPredicate : public TraceStackCache::CachedTraceStackPredicate {
 354 public:
 355   virtual bool test(CachedTraceStack *stack) {
 356     return true;
 357   }
 358 };
 359 
 360 void TraceStackCache::purge_all() {
 361   AnyPredicate pr;
 362   purge_matches(&pr);
 363 }
 364 
 365 void TraceStackCache::do_maintenance() {
 366   assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "must be done in VM thread at safepoint");
 367 
 368   bool should_grow = (_count / (float) _size > 0.7f);
 369   if (should_grow || has_invalid_stacks()) {
 370     if (EnableEventTracingDiagnostics) {
 371       _maintenance_timer.start();
 372     }
 373 
 374     CachedTraceStack **old_table = _table;
 375     size_t old_capacity = _size;
 376 
 377     if (should_grow) {
 378       _size <<= 1;
 379       assert(is_power_of_2(_size), "sanity");
 380     }
 381     _count = 0;
 382     _table = (CachedTraceStack **) os::malloc(_size * sizeof(_table[0]), mtEventTracing, CURRENT_PC);
 383     memset(_table, 0, _size * sizeof(_table[0]));
 384     for (size_t i = 0; i < old_capacity; i++) {
 385       CachedTraceStack *p = old_table[i];
 386       while (p != NULL) {
 387         CachedTraceStack *next = p->cache_next();
 388         if (p->is_valid()) {
 389           add_for_rehash(p);
 390         } else {
 391           delete p;
 392         }
 393         p = next;
 394       }
 395     }
 396     os::free(old_table, mtEventTracing);
 397 
 398     if (EnableEventTracingDiagnostics) {
 399       _maintenance_timer.stop();
 400     }
 401 
 402     _has_invalid_stacks = false;
 403   }
 404 }
 405 
 406 void TraceStackCache::reset_stats() {
 407   _lookup_counter = _lookup_miss_counter = _lookup_collision_counter = _probe_counter = _probe_collision_counter = 0;
 408 
 409   // these are only used in a safepoint: we should be fine either way
 410   _purge_timer.reset();
 411   _maintenance_timer.reset();
 412 }