events.cpp revision 2721:f08d439fab8c
1/*
2 * Copyright (c) 1997, 2010, 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 */
24
25#include "precompiled.hpp"
26#include "memory/allocation.inline.hpp"
27#include "runtime/mutexLocker.hpp"
28#include "runtime/osThread.hpp"
29#include "runtime/threadLocalStorage.hpp"
30#include "runtime/timer.hpp"
31#include "utilities/events.hpp"
32#ifdef TARGET_OS_FAMILY_linux
33# include "thread_linux.inline.hpp"
34#endif
35#ifdef TARGET_OS_FAMILY_solaris
36# include "thread_solaris.inline.hpp"
37#endif
38#ifdef TARGET_OS_FAMILY_windows
39# include "thread_windows.inline.hpp"
40#endif
41#ifdef TARGET_OS_FAMILY_bsd
42# include "thread_bsd.inline.hpp"
43#endif
44
45
46#ifndef PRODUCT
47
48////////////////////////////////////////////////////////////////////////////
49// Event
50
51typedef u4 EventID;
52
53class Event VALUE_OBJ_CLASS_SPEC  {
54 private:
55  jlong       _time_tick;
56  intx        _thread_id;
57  const char* _format;
58  int         _indent;
59  intptr_t    _arg_1;
60  intptr_t    _arg_2;
61  intptr_t    _arg_3;
62
63  // only EventBuffer::add_event() can assign event id
64  friend class EventBuffer;
65  EventID     _id;
66
67 public:
68
69  void clear() { _format = NULL; }
70
71  EventID id() const { return _id; }
72
73  void fill(int indent, const char* format, intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) {
74    _format = format;
75    _arg_1  = arg_1;
76    _arg_2  = arg_2;
77    _arg_3  = arg_3;
78
79    _indent = indent;
80
81    _thread_id = os::current_thread_id();
82    _time_tick = os::elapsed_counter();
83  }
84
85  void print_on(outputStream *st) {
86    if (_format == NULL) return;
87    st->print("  %d", _thread_id);
88    st->print("  %3.2g   ", (double)_time_tick / os::elapsed_frequency());
89    st->fill_to(20);
90    for (int index = 0; index < _indent; index++) {
91      st->print("| ");
92    }
93    st->print_cr(_format, _arg_1, _arg_2, _arg_3);
94  }
95};
96
97////////////////////////////////////////////////////////////////////////////
98// EventBuffer
99//
100// Simple lock-free event queue. Every event has a unique 32-bit id.
101// It's fine if two threads add events at the same time, because they
102// will get different event id, and then write to different buffer location.
103// However, it is assumed that add_event() is quick enough (or buffer size
104// is big enough), so when one thread is adding event, there can't be more
105// than "size" events created by other threads; otherwise we'll end up having
106// two threads writing to the same location.
107
108class EventBuffer : AllStatic {
109 private:
110  static Event* buffer;
111  static int    size;
112  static jint   indent;
113  static volatile EventID _current_event_id;
114
115  static EventID get_next_event_id() {
116    return (EventID)Atomic::add(1, (jint*)&_current_event_id);
117  }
118
119 public:
120  static void inc_indent() { Atomic::inc(&indent); }
121  static void dec_indent() { Atomic::dec(&indent); }
122
123  static bool get_event(EventID id, Event* event) {
124    int index = (int)(id % size);
125    if (buffer[index].id() == id) {
126      memcpy(event, &buffer[index], sizeof(Event));
127      // check id again; if buffer[index] is being updated by another thread,
128      // event->id() will contain different value.
129      return (event->id() == id);
130    } else {
131      // id does not match - id is invalid, or event is overwritten
132      return false;
133    }
134  }
135
136  // add a new event to the queue; if EventBuffer is full, this call will
137  // overwrite the oldest event in the queue
138  static EventID add_event(const char* format,
139                           intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) {
140    // assign a unique id
141    EventID id = get_next_event_id();
142
143    // event will be copied to buffer[index]
144    int index = (int)(id % size);
145
146    // first, invalidate id, buffer[index] can't have event with id = index + 2
147    buffer[index]._id = index + 2;
148
149    // make sure everyone has seen that buffer[index] is invalid
150    OrderAccess::fence();
151
152    // ... before updating its value
153    buffer[index].fill(indent, format, arg_1, arg_2, arg_3);
154
155    // finally, set up real event id, now buffer[index] contains valid event
156    OrderAccess::release_store(&(buffer[index]._id), id);
157
158    return id;
159  }
160
161  static void print_last(outputStream *st, int number) {
162    st->print_cr("[Last %d events in the event buffer]", number);
163    st->print_cr("-<thd>-<elapsed sec>-<description>---------------------");
164
165    int count = 0;
166    EventID id = _current_event_id;
167    while (count < number) {
168      Event event;
169      if (get_event(id, &event)) {
170         event.print_on(st);
171      }
172      id--;
173      count++;
174    }
175  }
176
177  static void print_all(outputStream* st) {
178    print_last(st, size);
179  }
180
181  static void init() {
182    // Allocate the event buffer
183    size   = EventLogLength;
184    buffer = NEW_C_HEAP_ARRAY(Event, size);
185
186    _current_event_id = 0;
187
188    // Clear the event buffer
189    for (int index = 0; index < size; index++) {
190      buffer[index]._id = index + 1;       // index + 1 is invalid id
191      buffer[index].clear();
192    }
193  }
194};
195
196Event*           EventBuffer::buffer;
197int              EventBuffer::size;
198volatile EventID EventBuffer::_current_event_id;
199int              EventBuffer::indent;
200
201////////////////////////////////////////////////////////////////////////////
202// Events
203
204// Events::log() is safe for signal handlers
205void Events::log(const char* format, ...) {
206  if (LogEvents) {
207    va_list ap;
208    va_start(ap, format);
209    intptr_t arg_1 = va_arg(ap, intptr_t);
210    intptr_t arg_2 = va_arg(ap, intptr_t);
211    intptr_t arg_3 = va_arg(ap, intptr_t);
212    va_end(ap);
213
214    EventBuffer::add_event(format, arg_1, arg_2, arg_3);
215  }
216}
217
218void Events::print_all(outputStream *st) {
219  EventBuffer::print_all(st);
220}
221
222void Events::print_last(outputStream *st, int number) {
223  EventBuffer::print_last(st, number);
224}
225
226///////////////////////////////////////////////////////////////////////////
227// EventMark
228
229EventMark::EventMark(const char* format, ...) {
230  if (LogEvents) {
231    va_list ap;
232    va_start(ap, format);
233    intptr_t arg_1 = va_arg(ap, intptr_t);
234    intptr_t arg_2 = va_arg(ap, intptr_t);
235    intptr_t arg_3 = va_arg(ap, intptr_t);
236    va_end(ap);
237
238    EventBuffer::add_event(format, arg_1, arg_2, arg_3);
239    EventBuffer::inc_indent();
240  }
241}
242
243EventMark::~EventMark() {
244  if (LogEvents) {
245    EventBuffer::dec_indent();
246    EventBuffer::add_event("done", 0, 0, 0);
247  }
248}
249
250///////////////////////////////////////////////////////////////////////////
251
252void eventlog_init() {
253  EventBuffer::init();
254}
255
256int print_all_events(outputStream *st) {
257  EventBuffer::print_all(st);
258  return 1;
259}
260
261#else
262
263void eventlog_init() {}
264int print_all_events(outputStream *st) { return 0; }
265
266#endif // PRODUCT
267