mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
7141200: log some interesting information in ring buffers for crashes
Reviewed-by: kvn, jrose, kevinw, brutisso, twisti, jmasa
This commit is contained in:
parent
a59952f4c9
commit
5a41427b37
30 changed files with 539 additions and 369 deletions
|
@ -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();
|
||||
|
||||
// Prints all events in the buffer
|
||||
static void print_all(outputStream* st) PRODUCT_RETURN;
|
||||
|
||||
// Prints last number events from the event buffer
|
||||
static void print_last(outputStream *st, int number) PRODUCT_RETURN;
|
||||
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];
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue