duke@435: /* dcubed@4967: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_UTILITIES_EVENTS_HPP stefank@2314: #define SHARE_VM_UTILITIES_EVENTS_HPP stefank@2314: stefank@2314: #include "memory/allocation.hpp" never@3499: #include "runtime/mutexLocker.hpp" never@3499: #include "runtime/thread.hpp" stefank@2314: #include "utilities/top.hpp" never@3499: #include "utilities/vmError.hpp" stefank@2314: duke@435: // Events and EventMark provide interfaces to log events taking place in the vm. duke@435: // This facility is extremly useful for post-mortem debugging. The eventlog duke@435: // often provides crucial information about events leading up to the crash. duke@435: // never@3571: // Abstractly the logs can record whatever they way but normally they never@3571: // would record at least a timestamp and the current Thread, along never@3571: // with whatever data they need in a ring buffer. Commonly fixed never@3571: // length text messages are recorded for simplicity but other never@3571: // strategies could be used. Several logs are provided by default but never@3571: // new instances can be created as needed. duke@435: never@3499: // The base event log dumping class that is registered for dumping at never@3499: // crash time. This is a very generic interface that is mainly here never@3499: // for completeness. Normally the templated EventLogBase would be never@3499: // subclassed to provide different log types. zgu@3900: class EventLog : public CHeapObj { never@3499: friend class Events; never@3499: never@3499: private: never@3499: EventLog* _next; never@3499: never@3499: EventLog* next() const { return _next; } never@3499: duke@435: public: never@3499: // Automatically registers the log so that it will be printed during never@3499: // crashes. never@3499: EventLog(); duke@435: never@3499: virtual void print_log_on(outputStream* out) = 0; duke@435: }; duke@435: never@3499: never@3499: // A templated subclass of EventLog that provides basic ring buffer never@3499: // functionality. Most event loggers should subclass this, possibly never@3499: // providing a more featureful log function if the existing copy never@3499: // semantics aren't appropriate. The name is used as the label of the never@3499: // log when it is dumped during a crash. never@3499: template class EventLogBase : public EventLog { dcubed@4967: template class EventRecord { never@3499: public: never@3571: double timestamp; never@3499: Thread* thread; never@3499: X data; never@3499: }; never@3499: never@3499: protected: never@3499: Mutex _mutex; never@3499: const char* _name; never@3499: int _length; never@3499: int _index; never@3499: int _count; never@3499: EventRecord* _records; never@3499: never@3499: public: never@3499: EventLogBase(const char* name, int length = LogEventsBufferEntries): never@3499: _name(name), never@3499: _length(length), never@3499: _count(0), never@3499: _index(0), never@3499: _mutex(Mutex::event, name) { never@3499: _records = new EventRecord[length]; never@3499: } never@3499: never@3571: double fetch_timestamp() { never@3578: return os::elapsedTime(); never@3571: } never@3571: never@3499: // move the ring buffer to next open slot and return the index of never@3499: // the slot to use for the current message. Should only be called never@3499: // while mutex is held. never@3499: int compute_log_index() { never@3499: int index = _index; never@3499: if (_count < _length) _count++; never@3499: _index++; never@3499: if (_index >= _length) _index = 0; never@3499: return index; never@3499: } never@3499: never@3499: bool should_log() { never@3499: // Don't bother adding new entries when we're crashing. This also never@3499: // avoids mutating the ring buffer when printing the log. never@3499: return !VMError::fatal_error_in_progress(); never@3499: } never@3499: never@3499: // Print the contents of the log never@3499: void print_log_on(outputStream* out); never@3499: never@3499: private: never@3499: void print_log_impl(outputStream* out); never@3499: never@3499: // Print a single element. A templated implementation might need to never@3499: // be declared by subclasses. never@3499: void print(outputStream* out, T& e); never@3499: never@3499: void print(outputStream* out, EventRecord& e) { never@3571: out->print("Event: %.3f ", e.timestamp); never@3499: if (e.thread != NULL) { never@3499: out->print("Thread " INTPTR_FORMAT " ", e.thread); never@3499: } never@3499: print(out, e.data); never@3499: } never@3499: }; never@3499: never@3499: // A simple wrapper class for fixed size text messages. vlivanov@4312: class StringLogMessage : public FormatBuffer<256> { never@3499: public: never@3499: // Wrap this buffer in a stringStream. never@3499: stringStream stream() { vlivanov@4312: return stringStream(_buf, size()); never@3499: } never@3499: }; never@3499: never@3499: // A simple ring buffer of fixed size text messages. never@3499: class StringEventLog : public EventLogBase { never@3499: public: never@3499: StringEventLog(const char* name, int count = LogEventsBufferEntries) : EventLogBase(name, count) {} never@3499: never@3499: void logv(Thread* thread, const char* format, va_list ap) { never@3499: if (!should_log()) return; never@3499: never@3571: double timestamp = fetch_timestamp(); never@3499: MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag); never@3499: int index = compute_log_index(); never@3499: _records[index].thread = thread; never@3499: _records[index].timestamp = timestamp; never@3499: _records[index].data.printv(format, ap); never@3499: } never@3499: never@3499: void log(Thread* thread, const char* format, ...) { never@3499: va_list ap; never@3499: va_start(ap, format); never@3499: logv(thread, format, ap); never@3499: va_end(ap); never@3499: } never@3499: never@3499: }; never@3499: never@3499: never@3499: never@3499: class Events : AllStatic { never@3499: friend class EventLog; never@3499: never@3499: private: never@3499: static EventLog* _logs; never@3499: never@3499: // A log for generic messages that aren't well categorized. never@3499: static StringEventLog* _messages; never@3499: never@3499: // A log for internal exception related messages, like internal never@3499: // throws and implicit exceptions. never@3499: static StringEventLog* _exceptions; never@3499: never@3499: // Deoptization related messages never@3499: static StringEventLog* _deopt_messages; never@3499: never@3499: public: never@3499: static void print_all(outputStream* out); never@3499: never@3571: // Dump all events to the tty never@3571: static void print(); never@3499: never@3499: // Logs a generic message with timestamp and format as printf. never@3499: static void log(Thread* thread, const char* format, ...); never@3499: never@3499: // Log exception related message never@3499: static void log_exception(Thread* thread, const char* format, ...); never@3499: never@3499: static void log_deopt_message(Thread* thread, const char* format, ...); never@3499: never@3499: // Register default loggers never@3499: static void init(); never@3499: }; never@3499: never@3499: never@3499: inline void Events::log(Thread* thread, const char* format, ...) { never@3499: if (LogEvents) { never@3499: va_list ap; never@3499: va_start(ap, format); never@3499: _messages->logv(thread, format, ap); never@3499: va_end(ap); never@3499: } never@3499: } never@3499: never@3499: inline void Events::log_exception(Thread* thread, const char* format, ...) { never@3499: if (LogEvents) { never@3499: va_list ap; never@3499: va_start(ap, format); never@3499: _exceptions->logv(thread, format, ap); never@3499: va_end(ap); never@3499: } never@3499: } never@3499: never@3499: inline void Events::log_deopt_message(Thread* thread, const char* format, ...) { never@3499: if (LogEvents) { never@3499: va_list ap; never@3499: va_start(ap, format); never@3499: _deopt_messages->logv(thread, format, ap); never@3499: va_end(ap); never@3499: } never@3499: } never@3499: never@3499: never@3499: template never@3499: inline void EventLogBase::print_log_on(outputStream* out) { never@3499: if (ThreadLocalStorage::get_thread_slow() == NULL) { never@3499: // Not a regular Java thread so don't bother locking never@3499: print_log_impl(out); never@3499: } else { never@3499: MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag); never@3499: print_log_impl(out); never@3499: } never@3499: } never@3499: never@3499: // Dump the ring buffer entries that current have entries. never@3499: template never@3499: inline void EventLogBase::print_log_impl(outputStream* out) { never@3499: out->print_cr("%s (%d events):", _name, _count); never@3499: if (_count == 0) { never@3499: out->print_cr("No events"); never@3571: out->cr(); never@3499: return; never@3499: } never@3499: never@3499: if (_count < _length) { never@3499: for (int i = 0; i < _count; i++) { never@3499: print(out, _records[i]); never@3499: } never@3499: } else { never@3499: for (int i = _index; i < _length; i++) { never@3499: print(out, _records[i]); never@3499: } never@3499: for (int i = 0; i < _index; i++) { never@3499: print(out, _records[i]); never@3499: } never@3499: } never@3499: out->cr(); never@3499: } never@3499: never@3499: // Implement a printing routine for the StringLogMessage never@3499: template <> never@3499: inline void EventLogBase::print(outputStream* out, StringLogMessage& lm) { never@3499: out->print_raw(lm); never@3499: out->cr(); never@3499: } never@3499: never@3499: // Place markers for the beginning and end up of a set of events. never@3499: // These end up in the default log. duke@435: class EventMark : public StackObj { never@3499: StringLogMessage _buffer; never@3499: duke@435: public: duke@435: // log a begin event, format as printf never@3499: EventMark(const char* format, ...); duke@435: // log an end event never@3499: ~EventMark(); duke@435: }; duke@435: stefank@2314: #endif // SHARE_VM_UTILITIES_EVENTS_HPP