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