--- a/hotspot/src/share/vm/utilities/events.hpp Wed Feb 01 10:36:58 2012 +0100
+++ b/hotspot/src/share/vm/utilities/events.hpp Wed Feb 01 07:59:01 2012 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,10 @@
#define SHARE_VM_UTILITIES_EVENTS_HPP
#include "memory/allocation.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/thread.hpp"
#include "utilities/top.hpp"
+#include "utilities/vmError.hpp"
// Events and EventMark provide interfaces to log events taking place in the vm.
// This facility is extremly useful for post-mortem debugging. The eventlog
@@ -47,26 +50,246 @@
// Max 3 arguments are saved for each logged event.
//
-class Events : AllStatic {
+// The base event log dumping class that is registered for dumping at
+// crash time. This is a very generic interface that is mainly here
+// for completeness. Normally the templated EventLogBase would be
+// subclassed to provide different log types.
+class EventLog : public CHeapObj {
+ friend class Events;
+
+ private:
+ EventLog* _next;
+
+ EventLog* next() const { return _next; }
+
public:
- // Logs an event, format as printf
- static void log(const char* format, ...) PRODUCT_RETURN;
+ // Automatically registers the log so that it will be printed during
+ // crashes.
+ EventLog();
+
+ virtual void print_log_on(outputStream* out) = 0;
+};
+
+
+// A templated subclass of EventLog that provides basic ring buffer
+// functionality. Most event loggers should subclass this, possibly
+// providing a more featureful log function if the existing copy
+// semantics aren't appropriate. The name is used as the label of the
+// log when it is dumped during a crash.
+template <class T> class EventLogBase : public EventLog {
+ template <class X> class EventRecord {
+ public:
+ jlong timestamp;
+ Thread* thread;
+ X data;
+ };
+
+ protected:
+ Mutex _mutex;
+ const char* _name;
+ int _length;
+ int _index;
+ int _count;
+ EventRecord<T>* _records;
+
+ public:
+ EventLogBase<T>(const char* name, int length = LogEventsBufferEntries):
+ _name(name),
+ _length(length),
+ _count(0),
+ _index(0),
+ _mutex(Mutex::event, name) {
+ _records = new EventRecord<T>[length];
+ }
- // Prints all events in the buffer
- static void print_all(outputStream* st) PRODUCT_RETURN;
+ // move the ring buffer to next open slot and return the index of
+ // the slot to use for the current message. Should only be called
+ // while mutex is held.
+ int compute_log_index() {
+ int index = _index;
+ if (_count < _length) _count++;
+ _index++;
+ if (_index >= _length) _index = 0;
+ return index;
+ }
+
+ bool should_log() {
+ // Don't bother adding new entries when we're crashing. This also
+ // avoids mutating the ring buffer when printing the log.
+ return !VMError::fatal_error_in_progress();
+ }
+
+ // Print the contents of the log
+ void print_log_on(outputStream* out);
+
+ private:
+ void print_log_impl(outputStream* out);
+
+ // Print a single element. A templated implementation might need to
+ // be declared by subclasses.
+ void print(outputStream* out, T& e);
- // Prints last number events from the event buffer
- static void print_last(outputStream *st, int number) PRODUCT_RETURN;
+ void print(outputStream* out, EventRecord<T>& e) {
+ out->print("Event: " INT64_FORMAT " ", e.timestamp);
+ if (e.thread != NULL) {
+ out->print("Thread " INTPTR_FORMAT " ", e.thread);
+ }
+ print(out, e.data);
+ }
+};
+
+// A simple wrapper class for fixed size text messages.
+class StringLogMessage : public FormatBuffer<132> {
+ public:
+ // Wrap this buffer in a stringStream.
+ stringStream stream() {
+ return stringStream(_buf, sizeof(_buf));
+ }
+};
+
+// A simple ring buffer of fixed size text messages.
+class StringEventLog : public EventLogBase<StringLogMessage> {
+ public:
+ StringEventLog(const char* name, int count = LogEventsBufferEntries) : EventLogBase<StringLogMessage>(name, count) {}
+
+ void logv(Thread* thread, const char* format, va_list ap) {
+ if (!should_log()) return;
+
+ jlong timestamp = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
+ MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag);
+ int index = compute_log_index();
+ _records[index].thread = thread;
+ _records[index].timestamp = timestamp;
+ _records[index].data.printv(format, ap);
+ }
+
+ void log(Thread* thread, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ logv(thread, format, ap);
+ va_end(ap);
+ }
+
};
+
+
+class Events : AllStatic {
+ friend class EventLog;
+
+ private:
+ static EventLog* _logs;
+
+ // A log for generic messages that aren't well categorized.
+ static StringEventLog* _messages;
+
+ // A log for internal exception related messages, like internal
+ // throws and implicit exceptions.
+ static StringEventLog* _exceptions;
+
+ // Deoptization related messages
+ static StringEventLog* _deopt_messages;
+
+ public:
+ static void print_all(outputStream* out);
+
+ static void print() {
+ print_all(tty);
+ }
+
+ // Logs a generic message with timestamp and format as printf.
+ static void log(Thread* thread, const char* format, ...);
+
+ // Log exception related message
+ static void log_exception(Thread* thread, const char* format, ...);
+
+ static void log_deopt_message(Thread* thread, const char* format, ...);
+
+ // Register default loggers
+ static void init();
+};
+
+
+inline void Events::log(Thread* thread, const char* format, ...) {
+ if (LogEvents) {
+ va_list ap;
+ va_start(ap, format);
+ _messages->logv(thread, format, ap);
+ va_end(ap);
+ }
+}
+
+inline void Events::log_exception(Thread* thread, const char* format, ...) {
+ if (LogEvents) {
+ va_list ap;
+ va_start(ap, format);
+ _exceptions->logv(thread, format, ap);
+ va_end(ap);
+ }
+}
+
+inline void Events::log_deopt_message(Thread* thread, const char* format, ...) {
+ if (LogEvents) {
+ va_list ap;
+ va_start(ap, format);
+ _deopt_messages->logv(thread, format, ap);
+ va_end(ap);
+ }
+}
+
+
+template <class T>
+inline void EventLogBase<T>::print_log_on(outputStream* out) {
+ if (ThreadLocalStorage::get_thread_slow() == NULL) {
+ // Not a regular Java thread so don't bother locking
+ print_log_impl(out);
+ } else {
+ MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag);
+ print_log_impl(out);
+ }
+}
+
+// Dump the ring buffer entries that current have entries.
+template <class T>
+inline void EventLogBase<T>::print_log_impl(outputStream* out) {
+ out->print_cr("%s (%d events):", _name, _count);
+ if (_count == 0) {
+ out->print_cr("No events");
+ return;
+ }
+
+ if (_count < _length) {
+ for (int i = 0; i < _count; i++) {
+ print(out, _records[i]);
+ }
+ } else {
+ for (int i = _index; i < _length; i++) {
+ print(out, _records[i]);
+ }
+ for (int i = 0; i < _index; i++) {
+ print(out, _records[i]);
+ }
+ }
+ out->cr();
+}
+
+// Implement a printing routine for the StringLogMessage
+template <>
+inline void EventLogBase<StringLogMessage>::print(outputStream* out, StringLogMessage& lm) {
+ out->print_raw(lm);
+ out->cr();
+}
+
+// Place markers for the beginning and end up of a set of events.
+// These end up in the default log.
class EventMark : public StackObj {
+ StringLogMessage _buffer;
+
public:
// log a begin event, format as printf
- EventMark(const char* format, ...) PRODUCT_RETURN;
+ EventMark(const char* format, ...);
// log an end event
- ~EventMark() PRODUCT_RETURN;
+ ~EventMark();
};
-int print_all_events(outputStream *st);
-
#endif // SHARE_VM_UTILITIES_EVENTS_HPP