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