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 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