src/share/vm/utilities/events.hpp

Wed, 01 Feb 2012 07:59:01 -0800

author
never
date
Wed, 01 Feb 2012 07:59:01 -0800
changeset 3499
aa3d708d67c4
parent 2314
f95d63e2154a
child 3571
09d00c18e323
permissions
-rw-r--r--

7141200: log some interesting information in ring buffers for crashes
Reviewed-by: kvn, jrose, kevinw, brutisso, twisti, jmasa

     1 /*
     2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #ifndef SHARE_VM_UTILITIES_EVENTS_HPP
    26 #define SHARE_VM_UTILITIES_EVENTS_HPP
    28 #include "memory/allocation.hpp"
    29 #include "runtime/mutexLocker.hpp"
    30 #include "runtime/thread.hpp"
    31 #include "utilities/top.hpp"
    32 #include "utilities/vmError.hpp"
    34 // Events and EventMark provide interfaces to log events taking place in the vm.
    35 // This facility is extremly useful for post-mortem debugging. The eventlog
    36 // often provides crucial information about events leading up to the crash.
    37 //
    38 // All arguments past the format string must be passed as an intptr_t.
    39 //
    40 // To log a single event use:
    41 //    Events::log("New nmethod has been created " INTPTR_FORMAT, nm);
    42 //
    43 // To log a block of events use:
    44 //    EventMark m("GarbageCollecting %d", (intptr_t)gc_number);
    45 //
    46 // The constructor to eventlog indents the eventlog until the
    47 // destructor has been executed.
    48 //
    49 // IMPLEMENTATION RESTRICTION:
    50 //   Max 3 arguments are saved for each logged event.
    51 //
    53 // The base event log dumping class that is registered for dumping at
    54 // crash time.  This is a very generic interface that is mainly here
    55 // for completeness.  Normally the templated EventLogBase would be
    56 // subclassed to provide different log types.
    57 class EventLog : public CHeapObj {
    58   friend class Events;
    60  private:
    61   EventLog* _next;
    63   EventLog* next() const { return _next; }
    65  public:
    66   // Automatically registers the log so that it will be printed during
    67   // crashes.
    68   EventLog();
    70   virtual void print_log_on(outputStream* out) = 0;
    71 };
    74 // A templated subclass of EventLog that provides basic ring buffer
    75 // functionality.  Most event loggers should subclass this, possibly
    76 // providing a more featureful log function if the existing copy
    77 // semantics aren't appropriate.  The name is used as the label of the
    78 // log when it is dumped during a crash.
    79 template <class T> class EventLogBase : public EventLog {
    80   template <class X> class EventRecord {
    81    public:
    82     jlong   timestamp;
    83     Thread* thread;
    84     X       data;
    85   };
    87  protected:
    88   Mutex           _mutex;
    89   const char*     _name;
    90   int             _length;
    91   int             _index;
    92   int             _count;
    93   EventRecord<T>* _records;
    95  public:
    96   EventLogBase<T>(const char* name, int length = LogEventsBufferEntries):
    97     _name(name),
    98     _length(length),
    99     _count(0),
   100     _index(0),
   101     _mutex(Mutex::event, name) {
   102     _records = new EventRecord<T>[length];
   103   }
   105   // move the ring buffer to next open slot and return the index of
   106   // the slot to use for the current message.  Should only be called
   107   // while mutex is held.
   108   int compute_log_index() {
   109     int index = _index;
   110     if (_count < _length) _count++;
   111     _index++;
   112     if (_index >= _length) _index = 0;
   113     return index;
   114   }
   116   bool should_log() {
   117     // Don't bother adding new entries when we're crashing.  This also
   118     // avoids mutating the ring buffer when printing the log.
   119     return !VMError::fatal_error_in_progress();
   120   }
   122   // Print the contents of the log
   123   void print_log_on(outputStream* out);
   125  private:
   126   void print_log_impl(outputStream* out);
   128   // Print a single element.  A templated implementation might need to
   129   // be declared by subclasses.
   130   void print(outputStream* out, T& e);
   132   void print(outputStream* out, EventRecord<T>& e) {
   133     out->print("Event: " INT64_FORMAT " ", e.timestamp);
   134     if (e.thread != NULL) {
   135       out->print("Thread " INTPTR_FORMAT " ", e.thread);
   136     }
   137     print(out, e.data);
   138   }
   139 };
   141 // A simple wrapper class for fixed size text messages.
   142 class StringLogMessage : public FormatBuffer<132> {
   143  public:
   144   // Wrap this buffer in a stringStream.
   145   stringStream stream() {
   146     return stringStream(_buf, sizeof(_buf));
   147   }
   148 };
   150 // A simple ring buffer of fixed size text messages.
   151 class StringEventLog : public EventLogBase<StringLogMessage> {
   152  public:
   153   StringEventLog(const char* name, int count = LogEventsBufferEntries) : EventLogBase<StringLogMessage>(name, count) {}
   155   void logv(Thread* thread, const char* format, va_list ap) {
   156     if (!should_log()) return;
   158     jlong timestamp = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
   159     MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag);
   160     int index = compute_log_index();
   161     _records[index].thread = thread;
   162     _records[index].timestamp = timestamp;
   163     _records[index].data.printv(format, ap);
   164   }
   166   void log(Thread* thread, const char* format, ...) {
   167     va_list ap;
   168     va_start(ap, format);
   169     logv(thread, format, ap);
   170     va_end(ap);
   171   }
   173 };
   177 class Events : AllStatic {
   178   friend class EventLog;
   180  private:
   181   static EventLog* _logs;
   183   // A log for generic messages that aren't well categorized.
   184   static StringEventLog* _messages;
   186   // A log for internal exception related messages, like internal
   187   // throws and implicit exceptions.
   188   static StringEventLog* _exceptions;
   190   // Deoptization related messages
   191   static StringEventLog* _deopt_messages;
   193  public:
   194   static void print_all(outputStream* out);
   196   static void print() {
   197     print_all(tty);
   198   }
   200   // Logs a generic message with timestamp and format as printf.
   201   static void log(Thread* thread, const char* format, ...);
   203   // Log exception related message
   204   static void log_exception(Thread* thread, const char* format, ...);
   206   static void log_deopt_message(Thread* thread, const char* format, ...);
   208   // Register default loggers
   209   static void init();
   210 };
   213 inline void Events::log(Thread* thread, const char* format, ...) {
   214   if (LogEvents) {
   215     va_list ap;
   216     va_start(ap, format);
   217     _messages->logv(thread, format, ap);
   218     va_end(ap);
   219   }
   220 }
   222 inline void Events::log_exception(Thread* thread, const char* format, ...) {
   223   if (LogEvents) {
   224     va_list ap;
   225     va_start(ap, format);
   226     _exceptions->logv(thread, format, ap);
   227     va_end(ap);
   228   }
   229 }
   231 inline void Events::log_deopt_message(Thread* thread, const char* format, ...) {
   232   if (LogEvents) {
   233     va_list ap;
   234     va_start(ap, format);
   235     _deopt_messages->logv(thread, format, ap);
   236     va_end(ap);
   237   }
   238 }
   241 template <class T>
   242 inline void EventLogBase<T>::print_log_on(outputStream* out) {
   243   if (ThreadLocalStorage::get_thread_slow() == NULL) {
   244     // Not a regular Java thread so don't bother locking
   245     print_log_impl(out);
   246   } else {
   247     MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag);
   248     print_log_impl(out);
   249   }
   250 }
   252 // Dump the ring buffer entries that current have entries.
   253 template <class T>
   254 inline void EventLogBase<T>::print_log_impl(outputStream* out) {
   255   out->print_cr("%s (%d events):", _name, _count);
   256   if (_count == 0) {
   257     out->print_cr("No events");
   258     return;
   259   }
   261   if (_count < _length) {
   262     for (int i = 0; i < _count; i++) {
   263       print(out, _records[i]);
   264     }
   265   } else {
   266     for (int i = _index; i < _length; i++) {
   267       print(out, _records[i]);
   268     }
   269     for (int i = 0; i < _index; i++) {
   270       print(out, _records[i]);
   271     }
   272   }
   273   out->cr();
   274 }
   276 // Implement a printing routine for the StringLogMessage
   277 template <>
   278 inline void EventLogBase<StringLogMessage>::print(outputStream* out, StringLogMessage& lm) {
   279   out->print_raw(lm);
   280   out->cr();
   281 }
   283 // Place markers for the beginning and end up of a set of events.
   284 // These end up in the default log.
   285 class EventMark : public StackObj {
   286   StringLogMessage _buffer;
   288  public:
   289   // log a begin event, format as printf
   290   EventMark(const char* format, ...);
   291   // log an end event
   292   ~EventMark();
   293 };
   295 #endif // SHARE_VM_UTILITIES_EVENTS_HPP

mercurial