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