--- /dev/null 2016-10-25 08:46:44.038854975 +0200 +++ new/src/share/vm/evtrace/traceStack.hpp 2016-10-25 10:40:15.851781943 +0200 @@ -0,0 +1,218 @@ +/* + * 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 */