/* * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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("------------------------"); 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