Mercurial > hg > truffle
annotate src/share/vm/utilities/events.cpp @ 4530:6c6cb7be1324
bugfix
author | Christian Haeubl <christian.haeubl@oracle.com> |
---|---|
date | Wed, 08 Feb 2012 21:13:35 -0800 |
parents | f08d439fab8c |
children | aa3d708d67c4 |
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 | |
3960 | 41 #ifdef TARGET_OS_FAMILY_bsd |
42 # include "thread_bsd.inline.hpp" | |
43 #endif | |
0 | 44 |
45 | |
46 #ifndef PRODUCT | |
47 | |
48 //////////////////////////////////////////////////////////////////////////// | |
49 // Event | |
50 | |
51 typedef u4 EventID; | |
52 | |
53 class 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 | |
108 class 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 | |
196 Event* EventBuffer::buffer; | |
197 int EventBuffer::size; | |
198 volatile EventID EventBuffer::_current_event_id; | |
199 int EventBuffer::indent; | |
200 | |
201 //////////////////////////////////////////////////////////////////////////// | |
202 // Events | |
203 | |
204 // Events::log() is safe for signal handlers | |
205 void 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 | |
218 void Events::print_all(outputStream *st) { | |
219 EventBuffer::print_all(st); | |
220 } | |
221 | |
222 void Events::print_last(outputStream *st, int number) { | |
223 EventBuffer::print_last(st, number); | |
224 } | |
225 | |
226 /////////////////////////////////////////////////////////////////////////// | |
227 // EventMark | |
228 | |
229 EventMark::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 | |
243 EventMark::~EventMark() { | |
244 if (LogEvents) { | |
245 EventBuffer::dec_indent(); | |
246 EventBuffer::add_event("done", 0, 0, 0); | |
247 } | |
248 } | |
249 | |
250 /////////////////////////////////////////////////////////////////////////// | |
251 | |
252 void eventlog_init() { | |
253 EventBuffer::init(); | |
254 } | |
255 | |
256 int print_all_events(outputStream *st) { | |
257 EventBuffer::print_all(st); | |
258 return 1; | |
259 } | |
260 | |
261 #else | |
262 | |
263 void eventlog_init() {} | |
264 int print_all_events(outputStream *st) { return 0; } | |
265 | |
266 #endif // PRODUCT |