/* * Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved. * * This file is part of the Lock Contention Tracing Subsystem for the HotSpot * Virtual Machine, which is developed at Christian Doppler Laboratory on * Monitoring and Evolution of Very-Large-Scale Software Systems. Please * contact us at if you need additional information * or have any questions. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work. If not, see . * */ #ifndef SHARE_VM_EVTRACE_TRACESTACK_HPP #define SHARE_VM_EVTRACE_TRACESTACK_HPP #include "evtrace/traceTypes.hpp" #include "memory/allocation.hpp" #include "runtime/timer.hpp" class Method; class CachedTraceStack; class TraceMetadata; #define TRACE_STACK_MAX_FRAMES 128 class CompositeTraceStack; struct TraceStackFrame { bool is_compiled; union { struct { nmethod *nm; address pc; } compiled; struct { Method *method; int bci; } interpreted; }; intptr_t hash() const; bool equals(const TraceStackFrame& other) const; }; class TraceStackBuilder: StackObj { private: TraceStackFrame _frames[TRACE_STACK_MAX_FRAMES]; size_t _count; bool _truncated; intptr_t _hash; void add(const TraceStackFrame &f); public: TraceStackBuilder(); void add_frame(const frame *fr); void set_truncated() { _truncated = true; } const TraceStackFrame *frame_at(size_t index) const; size_t count() const { return _count; } bool is_full() const { return (_count == EventTracingStackDepthLimit); } bool is_truncated() const { return _truncated; } intptr_t hash() const { return _hash; } bool range_equals(size_t offset, const CachedTraceStack *cts, size_t cts_offset, size_t count) const; }; class CachedTraceStack: CHeapObj { public: static CachedTraceStack *create(TraceTypes::stack_id id, const CompositeTraceStack &ts); const TraceStackFrame *frame_at(size_t index) const; TraceTypes::stack_id id() const { return _id; } size_t count() const { return _count; } bool is_truncated() const { return _truncated; } intptr_t hash() const { return _hash; } bool has_interpreted_method_from_classloader(const ClassLoaderData *loader) const; bool has_nmethod(const nmethod *nm) const; bool range_equals(size_t offset, const CachedTraceStack *other, size_t other_offset, size_t count) const; bool is_valid() const { return _valid; } void invalidate(); CachedTraceStack *cache_next(); void set_cache_next(CachedTraceStack *next); void operator delete(void* p); private: void* operator new(size_t size, size_t nframes) throw (); CachedTraceStack(TraceTypes::stack_id id, const CompositeTraceStack &ts); CachedTraceStack * volatile _cache_next; const TraceTypes::stack_id _id; const intptr_t _hash; const size_t _count; const bool _truncated; bool _valid; TraceStackFrame _frames[0]; }; class CompositeTraceStack: StackObj { private: const TraceStackBuilder &_top; const CachedTraceStack *_bottom; size_t _bottom_offset; intptr_t _hash; size_t _count; bool _truncated; public: CompositeTraceStack(TraceStackBuilder &top); void set_bottom(const CachedTraceStack *cts, size_t offset); bool equals(const CachedTraceStack *cts) const; bool equals(const CompositeTraceStack &other) const; const TraceStackFrame *frame_at(size_t index) const; intptr_t hash() const { return _hash; } size_t count() const { return _count; } bool is_truncated() const { return _truncated; } }; class TraceStackVframeIterator: StackObj { private: const CompositeTraceStack &_ts; int _index; int _decode_offset; Method *_method; int _bci; void fill_from_compiled_frame(); public: TraceStackVframeIterator(const CompositeTraceStack &ts); bool has_next(); void next(); void reset(); Method *method() { return _method; } int bci() { return _bci; } }; class TraceStackCache: public CHeapObj { private: TraceMetadata *_metadata; CachedTraceStack **_table; volatile intptr_t _count; size_t _size; volatile bool _has_invalid_stacks; // statistics elapsedTimer _purge_timer; elapsedTimer _maintenance_timer; volatile intptr_t _lookup_counter; volatile intptr_t _lookup_miss_counter; volatile intptr_t _lookup_collision_counter; volatile intptr_t _probe_counter; volatile intptr_t _probe_collision_counter; void add_for_rehash(CachedTraceStack *cts); class CachedTraceStackPredicate; class UnloadingClassPredicate; class UnloadingNmethodPredicate; class AnyPredicate; void purge_matches(CachedTraceStackPredicate *pr); void update_counters_after_lookup(bool present, jlong probes, jlong collisions); public: TraceStackCache(TraceMetadata *tm); virtual ~TraceStackCache(); const CachedTraceStack * get_or_try_add(const CompositeTraceStack &ts, bool &known, TraceTypes::stack_id preallocated_id = 0); void purge_unloading_classes(const ClassLoaderData *loader); void purge_unloading_nmethod(const nmethod *nm); void purge_all(); bool has_invalid_stacks() const { return _has_invalid_stacks; } void do_maintenance(); intptr_t lookups() { return _lookup_counter; } intptr_t lookup_misses() { return _lookup_miss_counter; } intptr_t lookup_collisions() { return _lookup_collision_counter; } intptr_t probes() { return _probe_counter; } intptr_t probe_collisions() { return _probe_collision_counter; } jlong purge_millis() { return _purge_timer.milliseconds(); } jlong maintenance_millis() { return _maintenance_timer.milliseconds(); } void reset_stats(); }; #include "evtrace/traceStack.inline.hpp" #endif /* SHARE_VM_EVTRACE_TRACESTACK_HPP */