Mercurial > hg > truffle
diff src/share/vm/utilities/events.cpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | c18cbe5936b8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/utilities/events.cpp Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,249 @@ +/* + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_events.cpp.incl" + + +#ifndef PRODUCT + +//////////////////////////////////////////////////////////////////////////// +// Event + +typedef u4 EventID; + +class Event VALUE_OBJ_CLASS_SPEC { + private: + jlong _time_tick; + intx _thread_id; + const char* _format; + int _indent; + intptr_t _arg_1; + intptr_t _arg_2; + intptr_t _arg_3; + + // only EventBuffer::add_event() can assign event id + friend class EventBuffer; + EventID _id; + + public: + + void clear() { _format = NULL; } + + EventID id() const { return _id; } + + void fill(int indent, const char* format, intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) { + _format = format; + _arg_1 = arg_1; + _arg_2 = arg_2; + _arg_3 = arg_3; + + _indent = indent; + + _thread_id = os::current_thread_id(); + _time_tick = os::elapsed_counter(); + } + + void print_on(outputStream *st) { + if (_format == NULL) return; + st->print(" %d", _thread_id); + st->print(" %3.2g ", (double)_time_tick / os::elapsed_frequency()); + st->fill_to(20); + for (int index = 0; index < _indent; index++) { + st->print("| "); + } + st->print_cr(_format, _arg_1, _arg_2, _arg_3); + } +}; + +//////////////////////////////////////////////////////////////////////////// +// EventBuffer +// +// Simple lock-free event queue. Every event has a unique 32-bit id. +// It's fine if two threads add events at the same time, because they +// will get different event id, and then write to different buffer location. +// However, it is assumed that add_event() is quick enough (or buffer size +// is big enough), so when one thread is adding event, there can't be more +// than "size" events created by other threads; otherwise we'll end up having +// two threads writing to the same location. + +class EventBuffer : AllStatic { + private: + static Event* buffer; + static int size; + static jint indent; + static volatile EventID _current_event_id; + + static EventID get_next_event_id() { + return (EventID)Atomic::add(1, (jint*)&_current_event_id); + } + + public: + static void inc_indent() { Atomic::inc(&indent); } + static void dec_indent() { Atomic::dec(&indent); } + + static bool get_event(EventID id, Event* event) { + int index = (int)(id % size); + if (buffer[index].id() == id) { + memcpy(event, &buffer[index], sizeof(Event)); + // check id again; if buffer[index] is being updated by another thread, + // event->id() will contain different value. + return (event->id() == id); + } else { + // id does not match - id is invalid, or event is overwritten + return false; + } + } + + // add a new event to the queue; if EventBuffer is full, this call will + // overwrite the oldest event in the queue + static EventID add_event(const char* format, + intptr_t arg_1, intptr_t arg_2, intptr_t arg_3) { + // assign a unique id + EventID id = get_next_event_id(); + + // event will be copied to buffer[index] + int index = (int)(id % size); + + // first, invalidate id, buffer[index] can't have event with id = index + 2 + buffer[index]._id = index + 2; + + // make sure everyone has seen that buffer[index] is invalid + OrderAccess::fence(); + + // ... before updating its value + buffer[index].fill(indent, format, arg_1, arg_2, arg_3); + + // finally, set up real event id, now buffer[index] contains valid event + OrderAccess::release_store(&(buffer[index]._id), id); + + return id; + } + + static void print_last(outputStream *st, int number) { + st->print_cr("[Last %d events in the event buffer]", number); + st->print_cr("-<thd>-<elapsed sec>-<description>---------------------"); + + int count = 0; + EventID id = _current_event_id; + while (count < number) { + Event event; + if (get_event(id, &event)) { + event.print_on(st); + } + id--; + count++; + } + } + + static void print_all(outputStream* st) { + print_last(st, size); + } + + static void init() { + // Allocate the event buffer + size = EventLogLength; + buffer = NEW_C_HEAP_ARRAY(Event, size); + + _current_event_id = 0; + + // Clear the event buffer + for (int index = 0; index < size; index++) { + buffer[index]._id = index + 1; // index + 1 is invalid id + buffer[index].clear(); + } + } +}; + +Event* EventBuffer::buffer; +int EventBuffer::size; +volatile EventID EventBuffer::_current_event_id; +int EventBuffer::indent; + +//////////////////////////////////////////////////////////////////////////// +// Events + +// Events::log() is safe for signal handlers +void Events::log(const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + intptr_t arg_1 = va_arg(ap, intptr_t); + intptr_t arg_2 = va_arg(ap, intptr_t); + intptr_t arg_3 = va_arg(ap, intptr_t); + va_end(ap); + + EventBuffer::add_event(format, arg_1, arg_2, arg_3); + } +} + +void Events::print_all(outputStream *st) { + EventBuffer::print_all(st); +} + +void Events::print_last(outputStream *st, int number) { + EventBuffer::print_last(st, number); +} + +/////////////////////////////////////////////////////////////////////////// +// EventMark + +EventMark::EventMark(const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + intptr_t arg_1 = va_arg(ap, intptr_t); + intptr_t arg_2 = va_arg(ap, intptr_t); + intptr_t arg_3 = va_arg(ap, intptr_t); + va_end(ap); + + EventBuffer::add_event(format, arg_1, arg_2, arg_3); + EventBuffer::inc_indent(); + } +} + +EventMark::~EventMark() { + if (LogEvents) { + EventBuffer::dec_indent(); + EventBuffer::add_event("done", 0, 0, 0); + } +} + +/////////////////////////////////////////////////////////////////////////// + +void eventlog_init() { + EventBuffer::init(); +} + +int print_all_events(outputStream *st) { + EventBuffer::print_all(st); + return 1; +} + +#else + +void eventlog_init() {} +int print_all_events(outputStream *st) { return 0; } + +#endif // PRODUCT