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 #ifndef SHARE_VM_EVTRACE_TRACESTACK_HPP
  26 #define SHARE_VM_EVTRACE_TRACESTACK_HPP
  27 
  28 #include "evtrace/traceTypes.hpp"
  29 
  30 #include "memory/allocation.hpp"
  31 #include "runtime/timer.hpp"
  32 
  33 class Method;
  34 class CachedTraceStack;
  35 class TraceMetadata;
  36 
  37 #define TRACE_STACK_MAX_FRAMES 128
  38 
  39 class CompositeTraceStack;
  40 
  41 struct TraceStackFrame {
  42   bool is_compiled;
  43   union {
  44     struct {
  45       nmethod *nm;
  46       address  pc;
  47     } compiled;
  48     struct {
  49       Method *method;
  50       int     bci;
  51     } interpreted;
  52   };
  53 
  54   intptr_t hash() const;
  55   bool equals(const TraceStackFrame& other) const;
  56 };
  57 
  58 class TraceStackBuilder: StackObj {
  59 private:
  60   TraceStackFrame _frames[TRACE_STACK_MAX_FRAMES];
  61   size_t   _count;
  62   bool     _truncated;
  63   intptr_t _hash;
  64 
  65   void add(const TraceStackFrame &f);
  66 
  67 public:
  68   TraceStackBuilder();
  69 
  70   void add_frame(const frame *fr);
  71   void set_truncated() { _truncated = true; }
  72 
  73   const TraceStackFrame *frame_at(size_t index) const;
  74 
  75   size_t   count() const        { return _count;     }
  76   bool     is_full() const      { return (_count == EventTracingStackDepthLimit); }
  77   bool     is_truncated() const { return _truncated; }
  78   intptr_t hash() const         { return _hash;      }
  79 
  80   bool     range_equals(size_t offset, const CachedTraceStack *cts, size_t cts_offset, size_t count) const;
  81 };
  82 
  83 class CachedTraceStack: CHeapObj<mtEventTracing> {
  84 public:
  85   static CachedTraceStack *create(TraceTypes::stack_id id, const CompositeTraceStack &ts);
  86 
  87   const TraceStackFrame *frame_at(size_t index) const;
  88 
  89   TraceTypes::stack_id  id() const { return _id;        }
  90   size_t   count() const           { return _count;     }
  91   bool     is_truncated() const    { return _truncated; }
  92   intptr_t hash() const            { return _hash;      }
  93 
  94   bool     has_interpreted_method_from_classloader(const ClassLoaderData *loader) const;
  95   bool     has_nmethod(const nmethod *nm) const;
  96   bool     range_equals(size_t offset, const CachedTraceStack *other, size_t other_offset, size_t count) const;
  97 
  98   bool     is_valid() const { return _valid; }
  99   void     invalidate();
 100 
 101   CachedTraceStack *cache_next();
 102   void     set_cache_next(CachedTraceStack *next);
 103 
 104   void operator delete(void* p);
 105 
 106 private:
 107   void* operator new(size_t size, size_t nframes) throw ();
 108   CachedTraceStack(TraceTypes::stack_id id, const CompositeTraceStack &ts);
 109 
 110   CachedTraceStack * volatile _cache_next;
 111 
 112   const TraceTypes::stack_id  _id;
 113   const intptr_t              _hash;
 114   const size_t                _count;
 115   const bool                  _truncated;
 116   bool                        _valid;
 117   TraceStackFrame             _frames[0];
 118 };
 119 
 120 class CompositeTraceStack: StackObj {
 121 private:
 122   const TraceStackBuilder &_top;
 123   const CachedTraceStack  *_bottom;
 124   size_t    _bottom_offset;
 125   intptr_t  _hash;
 126   size_t    _count;
 127   bool      _truncated;
 128 
 129 public:
 130   CompositeTraceStack(TraceStackBuilder &top);
 131 
 132   void set_bottom(const CachedTraceStack *cts, size_t offset);
 133 
 134   bool equals(const CachedTraceStack *cts) const;
 135   bool equals(const CompositeTraceStack &other) const;
 136 
 137   const TraceStackFrame *frame_at(size_t index) const;
 138 
 139   intptr_t hash() const         { return _hash;      }
 140   size_t   count() const        { return _count;     }
 141   bool     is_truncated() const { return _truncated; }
 142 };
 143 
 144 class TraceStackVframeIterator: StackObj {
 145 private:
 146   const CompositeTraceStack &_ts;
 147   int      _index;
 148   int      _decode_offset;
 149   Method  *_method;
 150   int      _bci;
 151 
 152   void fill_from_compiled_frame();
 153 
 154 public:
 155   TraceStackVframeIterator(const CompositeTraceStack &ts);
 156 
 157   bool has_next();
 158   void next();
 159   void reset();
 160 
 161   Method *method() { return _method; }
 162   int     bci()    { return _bci;    }
 163 };
 164 
 165 class TraceStackCache: public CHeapObj<mtEventTracing> {
 166 private:
 167   TraceMetadata *_metadata;
 168 
 169   CachedTraceStack **_table;
 170   volatile intptr_t  _count;
 171   size_t             _size;
 172   volatile bool      _has_invalid_stacks;
 173 
 174   // statistics
 175   elapsedTimer   _purge_timer;
 176   elapsedTimer   _maintenance_timer;
 177   volatile intptr_t _lookup_counter;
 178   volatile intptr_t _lookup_miss_counter;
 179   volatile intptr_t _lookup_collision_counter;
 180   volatile intptr_t _probe_counter;
 181   volatile intptr_t _probe_collision_counter;
 182 
 183   void add_for_rehash(CachedTraceStack *cts);
 184 
 185   class CachedTraceStackPredicate;
 186   class UnloadingClassPredicate;
 187   class UnloadingNmethodPredicate;
 188   class AnyPredicate;
 189   void purge_matches(CachedTraceStackPredicate *pr);
 190 
 191   void update_counters_after_lookup(bool present, jlong probes, jlong collisions);
 192 
 193 public:
 194   TraceStackCache(TraceMetadata *tm);
 195   virtual ~TraceStackCache();
 196 
 197   const CachedTraceStack * get_or_try_add(const CompositeTraceStack &ts, bool &known, TraceTypes::stack_id preallocated_id = 0);
 198 
 199   void purge_unloading_classes(const ClassLoaderData *loader);
 200   void purge_unloading_nmethod(const nmethod *nm);
 201   void purge_all();
 202 
 203   bool has_invalid_stacks() const { return _has_invalid_stacks; }
 204   void do_maintenance();
 205 
 206   intptr_t lookups()            { return _lookup_counter;                   }
 207   intptr_t lookup_misses()      { return _lookup_miss_counter;              }
 208   intptr_t lookup_collisions()  { return _lookup_collision_counter;         }
 209   intptr_t probes()             { return _probe_counter;                    }
 210   intptr_t probe_collisions()   { return _probe_collision_counter;          }
 211   jlong    purge_millis()       { return _purge_timer.milliseconds();       }
 212   jlong    maintenance_millis() { return _maintenance_timer.milliseconds(); }
 213   void     reset_stats();
 214 };
 215 
 216 #include "evtrace/traceStack.inline.hpp"
 217 
 218 #endif /* SHARE_VM_EVTRACE_TRACESTACK_HPP */