/* * 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_TRACEEVENTS_HPP #define SHARE_VM_EVTRACE_TRACEEVENTS_HPP #include "evtrace/traceManager.hpp" #include "evtrace/traceMetadata.hpp" #include "memory/allocation.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/thread.hpp" class TraceWriter; class Klass; class ClassLoaderData; class TraceEvents: private TraceTypes // for mere convenience { public: static void initialize(); static void write_thread_start(); static void write_thread_name_change(Thread *t); static void write_thread_state_change(Thread *t); static void write_thread_interrupt(Thread *t); static void write_thread_exit(); static void write_thread_park_begin(JavaThread *t, bool is_absolute, timestamp park_time); static void write_thread_park_end(Thread *t, seq_num seq, seq_num unpark_seq, park_return_code return_code); static void write_thread_unpark(thread_id thread, seq_num seq, seq_num chained_seq); static void write_monitor_inflate(ObjectMonitor *m, seq_num seq); static void write_monitor_deflate(ObjectMonitor *m); static void write_monitor_contended_enter(ObjectMonitor *m, monitor_enter_wait wait); static void write_monitor_contended_entered(ObjectMonitor *m, monitor_entered_flags flags); static void write_monitor_contended_exited(ObjectMonitor *m, seq_num seq, stack_id preallocated_stack_id, bool resolve_stack); static void write_monitor_dummy(ObjectMonitor *m, seq_num seq); static void write_class_loader_unload(ClassLoaderData *cld); static void write_safepoint_begin(safepoint_reason reason); static void write_safepoint_end(u4 vmops_processed); static void write_vm_end(); static void write_metadata_reset(); static void write_group(JavaThread* t, seq_num park_seq_begin_ref, oop source); static void write_marker(const char *label); private: TraceEvents() { } static bool can_write(); static class_id retrieve_class_id_or_write_metadata(Klass *k); static method_id retrieve_method_id_or_write_metadata(Method *m); static stack_id retrieve_stack_id_or_write_metadata(JavaThread *t, stack_id preallocated_id = 0); static void write_stack_metadata(stack_id id, const CompositeTraceStack &ts); static void write_identical_stacks_metadata(stack_id id, stack_id known); static timestamp time_now(); static thread_id thread_id_for(Thread *t); static object_id object_id_for(oop obj); static objmonitor_id objmonitor_id_for(ObjectMonitor *om); static object_id objmonitor_object_id_for(ObjectMonitor *om); static classloader_id classloader_id_for(ClassLoaderData *cld); static method_id method_id_for(Method *m); }; class TraceEventThreadParkEnd: public StackObj { private: No_Safepoint_Verifier _nsv; bool _enabled; bool _filled; Thread *_thread; TraceTypes::seq_num _seq; TraceTypes::seq_num _unpark_seq; TraceTypes::park_return_code _return_code; void do_write(); public: TraceEventThreadParkEnd(Thread *t) : _nsv(false, false), _thread(t), _filled(false) { assert(t != NULL, "null thread"); _enabled = EnableEventTracing && EnableEventTracingParkEvents && t->park_priority() >= 0; } void fill(TraceTypes::seq_num unpark_seq, TraceTypes::park_return_code return_code) { assert(!_filled, "already filled"); _nsv.enable(); _enabled = _enabled && TraceManager::is_initialized(); if (_enabled) { _seq = TraceManager::metadata()->next_global_seq(); _thread->set_park_last_global_seq(_seq); _unpark_seq = unpark_seq; _return_code = return_code; } _filled = true; } ~TraceEventThreadParkEnd() { assert(_filled, "must have been filled"); if (_enabled) { do_write(); } } }; class TraceEventThreadUnpark: public StackObj { private: No_Safepoint_Verifier _nsv; bool _enabled; TraceTypes::thread_id _thread_id; TraceTypes::seq_num _seq; TraceTypes::seq_num _chained_seq; void do_write(); public: TraceEventThreadUnpark(Thread *t) : _nsv(true, false), _chained_seq(-1) { assert(t != NULL, "null thread"); _enabled = EnableEventTracing && EnableEventTracingParkEvents && TraceManager::is_initialized(); if (_enabled) { _thread_id = TraceManager::metadata()->thread_id(t); _seq = TraceManager::metadata()->next_global_seq(); } else { _thread_id = 0; _seq = 1; } } ~TraceEventThreadUnpark() { if (_enabled) { do_write(); } } TraceTypes::seq_num seq() { return _seq; } void set_chained_seq(TraceTypes::seq_num chained_seq) { _chained_seq = chained_seq; } }; class TraceEventMonitorContendedExited: public StackObj { private: No_Safepoint_Verifier _nsv; bool _enabled; ObjectMonitor *_monitor; TraceTypes::seq_num _seq; TraceTypes::stack_id *_stack_id_at; TraceTypes::stack_id _preallocated_stack_id; bool _resolve_stack; public: TraceEventMonitorContendedExited(ObjectMonitor *m) : _nsv(true, false), _enabled(false), _monitor(m), _seq(0), _stack_id_at(NULL), _resolve_stack(true) { if (EnableEventTracing && EventTracingStrictMonitorEventOrder) { _seq = _monitor->next_trace_seq(); } } ~TraceEventMonitorContendedExited() { if (_enabled) { TraceTypes::stack_id id = 0; if (_stack_id_at != NULL) { if (*_stack_id_at == 0 && EnableEventTracingStackTraces) { *_stack_id_at = TraceManager::metadata()->next_stack_id(); } id = *_stack_id_at; } TraceEvents::write_monitor_contended_exited(_monitor, _seq, id, _resolve_stack); } else if (EnableEventTracing && EventTracingStrictMonitorEventOrder && TraceManager::is_initialized()) { assert(!_resolve_stack || _stack_id_at == NULL || *_stack_id_at == 0, "event must be enabled if there is a stack id to resolve"); // must consume eagerly acquired sequence number TraceEvents::write_monitor_dummy(_monitor, _seq); } } void set_use_or_preallocate_stack_id_at(TraceTypes::stack_id *p) { assert (_stack_id_at == NULL, "set only once"); _stack_id_at = p; } void set_use_stack_id(TraceTypes::stack_id id) { _preallocated_stack_id = id; set_use_or_preallocate_stack_id_at(&_preallocated_stack_id); } void set_resolve_stack(bool resolve) { _resolve_stack = resolve; } void enable() { if (EnableEventTracing && TraceManager::is_initialized()) { if (!_enabled && !EventTracingStrictMonitorEventOrder) { // lazily acquire sequence number, racing with other threads which try // to spin-acquire the monitor and then write contended-entered events _seq = _monitor->next_trace_seq(); } _enabled = true; } } }; // for convenience, so this is the only file to include for writing events #include "evtrace/traceWriter.hpp" #include "evtrace/traceMacros.hpp" #endif /* SHARE_VM_EVTRACE_TRACEEVENTS_HPP */