# HG changeset patch # User never # Date 1328111941 28800 # Node ID aa3d708d67c4f5e84cb677f34ef5f83f70a0d70c # Parent f067b4e0e04b9fef275f7b79e7e2da82eeb2fa97 7141200: log some interesting information in ring buffers for crashes Reviewed-by: kvn, jrose, kevinw, brutisso, twisti, jmasa diff -r f067b4e0e04b -r aa3d708d67c4 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/os/windows/vm/os_windows.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -2088,7 +2088,6 @@ #elif _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; - NOT_PRODUCT(Events::log("idiv overflow exception at " INTPTR_FORMAT , pc)); assert(pc[0] == 0xF7, "not an idiv opcode"); assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); assert(ctx->Rax == min_jint, "unexpected idiv exception"); @@ -2100,7 +2099,6 @@ #else PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Eip; - NOT_PRODUCT(Events::log("idiv overflow exception at " INTPTR_FORMAT , pc)); assert(pc[0] == 0xF7, "not an idiv opcode"); assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); assert(ctx->Eax == min_jint, "unexpected idiv exception"); @@ -5331,4 +5329,3 @@ } #endif - diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/c1/c1_Runtime1.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, 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 @@ -597,7 +597,6 @@ JRT_ENTRY(void, Runtime1::throw_range_check_exception(JavaThread* thread, int index)) NOT_PRODUCT(_throw_range_check_exception_count++;) - Events::log("throw_range_check"); char message[jintAsStringSize]; sprintf(message, "%d", index); SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); @@ -606,7 +605,6 @@ JRT_ENTRY(void, Runtime1::throw_index_exception(JavaThread* thread, int index)) NOT_PRODUCT(_throw_index_exception_count++;) - Events::log("throw_index"); char message[16]; sprintf(message, "%d", index); SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_IndexOutOfBoundsException(), message); @@ -804,11 +802,7 @@ // Note also that in the presence of inlining it is not guaranteed // that caller_method() == caller_code->method() - int bci = vfst.bci(); - - Events::log("patch_code @ " INTPTR_FORMAT , caller_frame.pc()); - Bytecodes::Code code = caller_method()->java_code_at(bci); #ifndef PRODUCT diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/ci/ciEnv.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, 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 @@ -284,6 +284,20 @@ // Return state of appropriate compilability int compilable() { return _compilable; } + const char* retry_message() const { + switch (_compilable) { + case ciEnv::MethodCompilable_not_at_tier: + return "retry at different tier"; + case ciEnv::MethodCompilable_never: + return "not retryable"; + case ciEnv::MethodCompilable: + return NULL; + default: + ShouldNotReachHere(); + return NULL; + } + } + bool break_at_compile() { return _break_at_compile; } void set_break_at_compile(bool z) { _break_at_compile = z; } diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/code/compiledIC.cpp --- a/src/share/vm/code/compiledIC.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/code/compiledIC.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -165,7 +165,6 @@ instruction_address(), method->print_value_string(), entry); } - Events::log("compiledIC " INTPTR_FORMAT " --> megamorphic " INTPTR_FORMAT, this, (address)method()); // We can't check this anymore. With lazy deopt we could have already // cleaned this IC entry before we even return. This is possible if // we ran out of space in the inline cache buffer trying to do the diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/code/nmethod.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -704,7 +704,6 @@ xtty->tail("print_native_nmethod"); } } - Events::log("Create nmethod " INTPTR_FORMAT, this); } // For dtrace wrappers @@ -781,7 +780,6 @@ xtty->tail("print_dtrace_nmethod"); } } - Events::log("Create nmethod " INTPTR_FORMAT, this); } #endif // def HAVE_DTRACE_H @@ -889,13 +887,6 @@ if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { print_nmethod(printnmethods); } - - // Note: Do not verify in here as the CodeCache_lock is - // taken which would conflict with the CompiledIC_lock - // which taken during the verification of call sites. - // (was bug - gri 10/25/99) - - Events::log("Create nmethod " INTPTR_FORMAT, this); } @@ -1386,7 +1377,7 @@ assert_locked_or_safepoint(CodeCache_lock); // completely deallocate this method - EventMark m("flushing nmethod " INTPTR_FORMAT " %s", this, ""); + Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this); if (PrintMethodFlushing) { tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb", _compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity()/1024); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, 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 @@ -44,6 +44,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/sweeper.hpp" #include "utilities/dtrace.hpp" +#include "utilities/events.hpp" #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -189,6 +190,43 @@ GrowableArray* CompileBroker::_method_threads = NULL; +class CompilationLog : public StringEventLog { + public: + CompilationLog() : StringEventLog("Compilation events") { + } + + void log_compile(JavaThread* thread, CompileTask* task) { + StringLogMessage lm; + stringStream msg = lm.stream(); + // msg.time_stamp().update_to(tty->time_stamp().ticks()); + task->print_compilation(&msg, true); + log(thread, "%s", (const char*)lm); + } + + void log_nmethod(JavaThread* thread, nmethod* nm) { + log(thread, "nmethod " INTPTR_FORMAT " code ["INTPTR_FORMAT ", " INTPTR_FORMAT "]", + nm, nm->code_begin(), nm->code_end()); + } + + void log_failure(JavaThread* thread, CompileTask* task, const char* reason, const char* retry_message) { + StringLogMessage lm; + lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason); + if (retry_message != NULL) { + lm.append(" (%s)", retry_message); + } + lm.print("\n"); + log(thread, "%s", (const char*)lm); + } +}; + +static CompilationLog* _compilation_log = NULL; + +void compileBroker_init() { + if (LogEvents) { + _compilation_log = new CompilationLog(); + } +} + CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); @@ -326,8 +364,12 @@ // ------------------------------------------------------------------ // CompileTask::print_compilation_impl -void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, const char* msg) { - st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp +void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, + bool is_osr_method, int osr_bci, bool is_blocking, + const char* msg, bool short_form) { + if (!short_form) { + st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp + } st->print("%4d ", compile_id); // print compilation number // For unloaded methods the transition to zombie occurs after the @@ -370,7 +412,9 @@ if (msg != NULL) { st->print(" %s", msg); } - st->cr(); + if (!short_form) { + st->cr(); + } } // ------------------------------------------------------------------ @@ -426,12 +470,12 @@ // ------------------------------------------------------------------ // CompileTask::print_compilation -void CompileTask::print_compilation(outputStream* st) { +void CompileTask::print_compilation(outputStream* st, bool short_form) { oop rem = JNIHandles::resolve(method_handle()); assert(rem != NULL && rem->is_method(), "must be"); methodOop method = (methodOop) rem; bool is_osr_method = osr_bci() != InvocationEntryBci; - print_compilation_impl(st, method, compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking()); + print_compilation_impl(st, method, compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), NULL, short_form); } // ------------------------------------------------------------------ @@ -1648,6 +1692,10 @@ CompilerThread* thread = CompilerThread::current(); ResourceMark rm(thread); + if (LogEvents) { + _compilation_log->log_compile(thread, task); + } + // Common flags. uint compile_id = task->compile_id(); int osr_bci = task->osr_bci(); @@ -1716,22 +1764,30 @@ ci_env.record_method_not_compilable("compile failed", !TieredCompilation); } + // Copy this bit to the enclosing block: + compilable = ci_env.compilable(); + if (ci_env.failing()) { - // Copy this bit to the enclosing block: - compilable = ci_env.compilable(); + const char* retry_message = ci_env.retry_message(); + if (_compilation_log != NULL) { + _compilation_log->log_failure(thread, task, ci_env.failure_reason(), retry_message); + } if (PrintCompilation) { - const char* reason = ci_env.failure_reason(); - if (compilable == ciEnv::MethodCompilable_not_at_tier) { - tty->print_cr("%4d COMPILE SKIPPED: %s (retry at different tier)", compile_id, reason); - } else if (compilable == ciEnv::MethodCompilable_never) { - tty->print_cr("%4d COMPILE SKIPPED: %s (not retryable)", compile_id, reason); - } else if (compilable == ciEnv::MethodCompilable) { - tty->print_cr("%4d COMPILE SKIPPED: %s", compile_id, reason); + tty->print("%4d COMPILE SKIPPED: %s", compile_id, ci_env.failure_reason()); + if (retry_message != NULL) { + tty->print(" (%s)", retry_message); } + tty->cr(); } } else { task->mark_success(); task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes()); + if (_compilation_log != NULL) { + nmethod* code = task->code(); + if (code != NULL) { + _compilation_log->log_nmethod(thread, code); + } + } } } pop_jni_handle_block(); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/compiler/compileBroker.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, 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 @@ -98,12 +98,16 @@ void set_prev(CompileTask* prev) { _prev = prev; } private: - static void print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, const char* msg = NULL); + static void print_compilation_impl(outputStream* st, methodOop method, int compile_id, int comp_level, + bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, + const char* msg = NULL, bool short_form = false); public: - void print_compilation(outputStream* st = tty); + void print_compilation(outputStream* st = tty, bool short_form = false); static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL) { - print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, msg); + print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), + nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, + msg); } static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1228,9 +1228,7 @@ SvcGCMarker sgcm(SvcGCMarker::FULL); ResourceMark rm; - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + print_heap_before_gc(); HRSPhaseSetter x(HRSPhaseFullGC); verify_region_sets_optional(); @@ -1470,9 +1468,7 @@ _hrs.verify_optional(); verify_region_sets_optional(); - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + print_heap_after_gc(); g1mm()->update_sizes(); post_full_gc_dump(); @@ -3537,9 +3533,7 @@ SvcGCMarker sgcm(SvcGCMarker::MINOR); ResourceMark rm; - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + print_heap_before_gc(); HRSPhaseSetter x(HRSPhaseEvacuation); verify_region_sets_optional(); @@ -3890,9 +3884,7 @@ TASKQUEUE_STATS_ONLY(if (ParallelGCVerbose) print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + print_heap_after_gc(); g1mm()->update_sizes(); if (G1SummarizeRSetStats && diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -126,7 +126,6 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - EventMark m("1 mark object"); TraceTime tm("phase 1", PrintGC && Verbose, true, gclog_or_tty); GenMarkSweep::trace(" 1"); @@ -292,7 +291,6 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); Generation* pg = g1h->perm_gen(); - EventMark m("2 compute new addresses"); TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty); GenMarkSweep::trace("2"); @@ -337,7 +335,6 @@ Generation* pg = g1h->perm_gen(); // Adjust the pointers to reflect the new locations - EventMark m("3 adjust pointers"); TraceTime tm("phase 3", PrintGC && Verbose, true, gclog_or_tty); GenMarkSweep::trace("3"); @@ -402,7 +399,6 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); Generation* pg = g1h->perm_gen(); - EventMark m("4 compact heap"); TraceTime tm("phase 4", PrintGC && Verbose, true, gclog_or_tty); GenMarkSweep::trace("4"); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -132,9 +132,7 @@ AdaptiveSizePolicyOutput(size_policy, heap->total_collections()); - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + heap->print_heap_before_gc(); // Fill in TLABs heap->accumulate_statistics_all_tlabs(); @@ -377,9 +375,7 @@ NOT_PRODUCT(ref_processor()->verify_no_references_recorded()); - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + heap->print_heap_after_gc(); heap->post_full_gc_dump(); @@ -504,7 +500,6 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - EventMark m("1 mark object"); TraceTime tm("phase 1", PrintGCDetails && Verbose, true, gclog_or_tty); trace(" 1"); @@ -563,7 +558,6 @@ void PSMarkSweep::mark_sweep_phase2() { - EventMark m("2 compute new addresses"); TraceTime tm("phase 2", PrintGCDetails && Verbose, true, gclog_or_tty); trace("2"); @@ -608,7 +602,6 @@ void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - EventMark m("3 adjust pointers"); TraceTime tm("phase 3", PrintGCDetails && Verbose, true, gclog_or_tty); trace("3"); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, 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 @@ -983,9 +983,7 @@ // We need to track unique mark sweep invocations as well. _total_invocations++; - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + heap->print_heap_before_gc(); // Fill in TLABs heap->accumulate_statistics_all_tlabs(); @@ -1838,7 +1836,6 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - EventMark m("2 summarize"); TraceTime tm("summary phase", print_phases(), true, gclog_or_tty); // trace("2"); @@ -2237,9 +2234,7 @@ collection_exit.update(); - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + heap->print_heap_after_gc(); if (PrintGCTaskTimeStamps) { gclog_or_tty->print_cr("VM-Thread " INT64_FORMAT " " INT64_FORMAT " " INT64_FORMAT, @@ -2352,7 +2347,6 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm, bool maximum_heap_compaction) { // Recursively traverse all live objects and mark them - EventMark m("1 mark object"); TraceTime tm("marking phase", print_phases(), true, gclog_or_tty); ParallelScavengeHeap* heap = gc_heap(); @@ -2438,7 +2432,6 @@ void PSParallelCompact::adjust_roots() { // Adjust the pointers to reflect the new locations - EventMark m("3 adjust roots"); TraceTime tm("adjust roots", print_phases(), true, gclog_or_tty); // General strong roots. @@ -2469,7 +2462,6 @@ } void PSParallelCompact::compact_perm(ParCompactionManager* cm) { - EventMark m("4 compact perm"); TraceTime tm("compact perm gen", print_phases(), true, gclog_or_tty); // trace("4"); @@ -2647,7 +2639,6 @@ } void PSParallelCompact::compact() { - EventMark m("5 compact"); // trace("5"); TraceTime tm("compaction phase", print_phases(), true, gclog_or_tty); @@ -3502,4 +3493,3 @@ _updated_int_array_klass_obj = (klassOop) summary_data().calc_new_pointer(Universe::intArrayKlassObj()); } - diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, 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 @@ -295,9 +295,7 @@ heap->record_gen_tops_before_GC(); } - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - } + heap->print_heap_before_gc(); assert(!NeverTenure || _tenuring_threshold == markOopDesc::max_age + 1, "Sanity"); assert(!AlwaysTenure || _tenuring_threshold == 0, "Sanity"); @@ -643,9 +641,7 @@ Universe::verify(false); } - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + heap->print_heap_after_gc(); if (ZapUnusedHeapArea) { young_gen->eden_space()->check_mangled_unused_area_complete(); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_interface/collectedHeap.cpp --- a/src/share/vm/gc_interface/collectedHeap.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -51,6 +51,31 @@ size_t CollectedHeap::_filler_array_max_size = 0; +template <> +void EventLogBase::print(outputStream* st, GCMessage& m) { + st->print_cr("GC heap %s", m.is_before ? "before" : "after"); + st->print_raw(m); +} + +void GCHeapLog::log_heap(bool before) { + if (!should_log()) { + return; + } + + jlong timestamp = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; + MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag); + int index = compute_log_index(); + _records[index].thread = NULL; // Its the GC thread so it's not that interesting. + _records[index].timestamp = timestamp; + _records[index].data.is_before = before; + stringStream st(_records[index].data.buffer(), _records[index].data.size()); + if (before) { + Universe::print_heap_before_gc(&st); + } else { + Universe::print_heap_after_gc(&st); + } +} + // Memory state functions. @@ -81,6 +106,12 @@ 80, GCCause::to_string(_gc_lastcause), CHECK); } _defer_initial_card_mark = false; // strengthened by subclass in pre_initialize() below. + // Create the ring log + if (LogEvents) { + _gc_heap_log = new GCHeapLog(); + } else { + _gc_heap_log = NULL; + } } void CollectedHeap::pre_initialize() { diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -31,6 +31,7 @@ #include "runtime/handles.hpp" #include "runtime/perfData.hpp" #include "runtime/safepoint.hpp" +#include "utilities/events.hpp" // A "CollectedHeap" is an implementation of a java heap for HotSpot. This // is an abstract class: there may be many different kinds of heaps. This @@ -43,6 +44,29 @@ class Thread; class CollectorPolicy; +class GCMessage : public FormatBuffer<1024> { + public: + bool is_before; + + public: + GCMessage() {} +}; + +class GCHeapLog : public EventLogBase { + private: + void log_heap(bool before); + + public: + GCHeapLog() : EventLogBase("GC Heap History") {} + + void log_heap_before() { + log_heap(true); + } + void log_heap_after() { + log_heap(false); + } +}; + // // CollectedHeap // SharedHeap @@ -62,6 +86,8 @@ // Used for filler objects (static, but initialized in ctor). static size_t _filler_array_max_size; + GCHeapLog* _gc_heap_log; + // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used bool _defer_initial_card_mark; @@ -618,6 +644,27 @@ // Default implementation does nothing. virtual void print_tracing_info() const = 0; + // If PrintHeapAtGC is set call the appropriate routi + void print_heap_before_gc() { + if (PrintHeapAtGC) { + Universe::print_heap_before_gc(); + } + if (_gc_heap_log != NULL) { + _gc_heap_log->log_heap_before(); + } + } + void print_heap_after_gc() { + if (PrintHeapAtGC) { + Universe::print_heap_after_gc(); + } + if (_gc_heap_log != NULL) { + _gc_heap_log->log_heap_after(); + } + } + + // Allocate GCHeapLog during VM startup + static void initialize_heap_log(); + // Heap verification virtual void verify(bool allow_dirty, bool silent, VerifyOption option) = 0; diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/memory/genCollectedHeap.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, 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 @@ -479,11 +479,9 @@ const size_t perm_prev_used = perm_gen()->used(); - if (PrintHeapAtGC) { - Universe::print_heap_before_gc(); - if (Verbose) { - gclog_or_tty->print_cr("GC Cause: %s", GCCause::to_string(gc_cause())); - } + print_heap_before_gc(); + if (Verbose) { + gclog_or_tty->print_cr("GC Cause: %s", GCCause::to_string(gc_cause())); } { @@ -685,9 +683,7 @@ AdaptiveSizePolicy* sp = gen_policy()->size_policy(); AdaptiveSizePolicyOutput(sp, total_collections()); - if (PrintHeapAtGC) { - Universe::print_heap_after_gc(); - } + print_heap_after_gc(); #ifdef TRACESPINNING ParallelTaskTerminator::print_termination_counts(); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/memory/genMarkSweep.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -254,7 +254,6 @@ void GenMarkSweep::mark_sweep_phase1(int level, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - EventMark m("1 mark object"); TraceTime tm("phase 1", PrintGC && Verbose, true, gclog_or_tty); trace(" 1"); @@ -325,7 +324,6 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); Generation* pg = gch->perm_gen(); - EventMark m("2 compute new addresses"); TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty); trace("2"); @@ -350,7 +348,6 @@ Generation* pg = gch->perm_gen(); // Adjust the pointers to reflect the new locations - EventMark m("3 adjust pointers"); TraceTime tm("phase 3", PrintGC && Verbose, true, gclog_or_tty); trace("3"); @@ -411,7 +408,6 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); Generation* pg = gch->perm_gen(); - EventMark m("4 compact heap"); TraceTime tm("phase 4", PrintGC && Verbose, true, gclog_or_tty); trace("4"); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/prims/jvm.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -2716,7 +2716,9 @@ } oop java_thread = JNIHandles::resolve_non_null(jthread); JavaThread* receiver = java_lang_Thread::thread(java_thread); - Events::log("JVM_StopThread thread JavaThread " INTPTR_FORMAT " as oop " INTPTR_FORMAT " [exception " INTPTR_FORMAT "]", receiver, (address)java_thread, throwable); + Events::log_exception(JavaThread::current(), + "JVM_StopThread thread JavaThread " INTPTR_FORMAT " as oop " INTPTR_FORMAT " [exception " INTPTR_FORMAT "]", + receiver, (address)java_thread, throwable); // First check if thread is alive if (receiver != NULL) { // Check if exception is getting thrown at self (use oop equality, since the diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -339,7 +339,6 @@ #ifdef ASSERT assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); - Events::log("fetch unroll sp " INTPTR_FORMAT, unpack_sp); #endif #else intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); @@ -577,6 +576,8 @@ tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", thread, array, exec_mode); } #endif + Events::log(thread, "DEOPT UNPACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT " mode %d", + stub_frame.pc(), stub_frame.sp(), exec_mode); UnrollBlock* info = array->unroll_block(); @@ -981,6 +982,7 @@ #endif // COMPILER2 vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk) { + Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp()); #ifndef PRODUCT if (TraceDeoptimization) { @@ -1026,7 +1028,6 @@ // Compare the vframeArray to the collected vframes assert(array->structural_compare(thread, chunk), "just checking"); - Events::log("# vframes = %d", (intptr_t)chunk->length()); #ifndef PRODUCT if (TraceDeoptimization) { @@ -1124,8 +1125,6 @@ gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal); - EventMark m("Deoptimization (pc=" INTPTR_FORMAT ", sp=" INTPTR_FORMAT ")", fr.pc(), fr.id()); - // Patch the nmethod so that when execution returns to it we will // deopt the execution state and return to the interpreter. fr.deoptimize(thread); @@ -1239,6 +1238,10 @@ // before we are done with it. nmethodLocker nl(fr.pc()); + // Log a message + Events::log_deopt_message(thread, "Uncommon trap %d fr.pc " INTPTR_FORMAT, + trap_request, fr.pc()); + { ResourceMark rm; @@ -1249,7 +1252,6 @@ DeoptAction action = trap_request_action(trap_request); jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 - Events::log("Uncommon trap occurred @" INTPTR_FORMAT " unloaded_class_index = %d", fr.pc(), (int) trap_request); vframe* vf = vframe::new_vframe(&fr, ®_map, thread); compiledVFrame* cvf = compiledVFrame::cast(vf); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/frame.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -570,7 +570,7 @@ InterpreterCodelet* desc = Interpreter::codelet_containing(pc()); if (desc != NULL) { st->print("~"); - desc->print(); + desc->print_on(st); NOT_PRODUCT(begin = desc->code_begin(); end = desc->code_end();) } else { st->print("~interpreter"); diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/globals.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -736,8 +736,11 @@ product(bool, MaxFDLimit, true, \ "Bump the number of file descriptors to max in solaris.") \ \ - notproduct(bool, LogEvents, trueInDebug, \ - "Enable Event log") \ + diagnostic(bool, LogEvents, true, \ + "Enable the various ring buffer event logs") \ + \ + diagnostic(intx, LogEventsBufferEntries, 10, \ + "Enable the various ring buffer event logs") \ \ product(bool, BytecodeVerificationRemote, true, \ "Enables the Java bytecode verifier for remote classes") \ diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/init.cpp --- a/src/share/vm/runtime/init.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/init.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -65,7 +65,7 @@ void InlineCacheBuffer_init(); void compilerOracle_init(); void compilationPolicy_init(); - +void compileBroker_init(); // Initialization after compiler initialization bool universe_post_init(); // must happen after compiler_init @@ -120,6 +120,7 @@ InlineCacheBuffer_init(); compilerOracle_init(); compilationPolicy_init(); + compileBroker_init(); VMRegImpl::set_regName(); if (!universe_post_init()) { diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/mutex.cpp --- a/src/share/vm/runtime/mutex.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/mutex.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, 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 @@ -1296,10 +1296,6 @@ assert(this->rank() >= 0, "bad lock rank"); - if (LogMultipleMutexLocking && locks != NULL) { - Events::log("thread " INTPTR_FORMAT " locks %s, already owns %s", new_owner, name(), locks->name()); - } - // Deadlock avoidance rules require us to acquire Mutexes only in // a global total order. For example m1 is the lowest ranked mutex // that the thread holds and m2 is the mutex the thread is trying @@ -1343,10 +1339,6 @@ #ifdef ASSERT Monitor *locks = old_owner->owned_locks(); - if (LogMultipleMutexLocking && locks != this) { - Events::log("thread " INTPTR_FORMAT " unlocks %s, still owns %s", old_owner, this->name(), locks->name()); - } - // remove "this" from the owned locks list Monitor *prev = NULL; diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/sharedRuntime.cpp --- a/src/share/vm/runtime/sharedRuntime.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/sharedRuntime.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -886,9 +886,9 @@ // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException")); if (exception_kind == IMPLICIT_NULL) { - Events::log("Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); + Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); } else { - Events::log("Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); + Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); } return target_pc; } @@ -1541,7 +1541,6 @@ if (caller.is_compiled_frame() && !caller.is_deoptimized_frame()) { address pc = caller.pc(); - Events::log("update call-site at pc " INTPTR_FORMAT, pc); // Default call_addr is the location of the "basic" call. // Determine the address of the call we a reresolving. With diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/runtime/thread.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -1600,8 +1600,6 @@ // java.lang.Thread.dispatchUncaughtException if (uncaught_exception.not_null()) { Handle group(this, java_lang_Thread::threadGroup(threadObj())); - Events::log("uncaught exception INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT", - (address)uncaught_exception(), (address)threadObj(), (address)group()); { EXCEPTION_MARK; // Check if the method Thread.dispatchUncaughtException() exists. If so @@ -3885,7 +3883,7 @@ ThreadService::add_thread(p, daemon); // Possible GC point. - Events::log("Thread added: " INTPTR_FORMAT, p); + Events::log(p, "Thread added: " INTPTR_FORMAT, p); } void Threads::remove(JavaThread* p) { @@ -3930,7 +3928,7 @@ } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock - Events::log("Thread exited: " INTPTR_FORMAT, p); + Events::log(p, "Thread exited: " INTPTR_FORMAT, p); } // Threads_lock must be held when this is called (or must be called during a safepoint) diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/debug.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -601,18 +601,6 @@ } -extern "C" void events() { - Command c("events"); - Events::print_last(tty, 50); -} - - -extern "C" void nevents(int n) { - Command c("events"); - Events::print_last(tty, n); -} - - // Given a heap address that was valid before the most recent GC, if // the oop that used to contain it is still live, prints the new // location of the oop and the address. Useful for tracking down diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/debug.hpp --- a/src/share/vm/utilities/debug.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/debug.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -33,16 +33,23 @@ // Simple class to format the ctor arguments into a fixed-sized buffer. template class FormatBuffer { -public: + public: inline FormatBuffer(const char * format, ...); inline void append(const char* format, ...); + inline void print(const char* format, ...); + inline void printv(const char* format, va_list ap); operator const char *() const { return _buf; } -private: + char* buffer() { return _buf; } + int size() { return bufsz; } + + private: FormatBuffer(const FormatBuffer &); // prevent copies -private: + protected: char _buf[bufsz]; + + inline FormatBuffer(); }; template @@ -54,6 +61,24 @@ } template +FormatBuffer::FormatBuffer() { + _buf[0] = '\0'; +} + +template +void FormatBuffer::print(const char * format, ...) { + va_list argp; + va_start(argp, format); + jio_vsnprintf(_buf, bufsz, format, argp); + va_end(argp); +} + +template +void FormatBuffer::printv(const char * format, va_list argp) { + jio_vsnprintf(_buf, bufsz, format, argp); +} + +template void FormatBuffer::append(const char* format, ...) { // Given that the constructor does a vsnprintf we can assume that // _buf is already initialized. diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/events.cpp --- a/src/share/vm/utilities/events.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/events.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -26,6 +26,7 @@ #include "memory/allocation.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/osThread.hpp" +#include "runtime/threadCritical.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/timer.hpp" #include "utilities/events.hpp" @@ -43,184 +44,40 @@ #endif -#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); } +EventLog* Events::_logs = NULL; +StringEventLog* Events::_messages = NULL; +StringEventLog* Events::_exceptions = NULL; +StringEventLog* Events::_deopt_messages = NULL; - 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("------------------------"); +EventLog::EventLog() { + // This normally done during bootstrap when we're only single + // threaded but use a ThreadCritical to ensure inclusion in case + // some are created slightly late. + ThreadCritical tc; + _next = Events::_logs; + Events::_logs = this; +} - 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); +// For each registered event logger, print out the current contents of +// the buffer. This is normally called when the JVM is crashing. +void Events::print_all(outputStream* out) { + EventLog* log = _logs; + while (log != NULL) { + log->print_log_on(out); + log = log->next(); } } -void Events::print_all(outputStream *st) { - EventBuffer::print_all(st); +void Events::init() { + if (LogEvents) { + _messages = new StringEventLog("Events"); + _exceptions = new StringEventLog("Internal exceptions"); + _deopt_messages = new StringEventLog("Deoptimization events"); + } } -void Events::print_last(outputStream *st, int number) { - EventBuffer::print_last(st, number); +void eventlog_init() { + Events::init(); } /////////////////////////////////////////////////////////////////////////// @@ -230,37 +87,17 @@ 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); + // Save a copy of begin message and log it. + _buffer.printv(format, ap); + Events::log(NULL, _buffer); 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); + // Append " done" to the begin message and log it + _buffer.append(" done"); + Events::log(NULL, _buffer); } } - -/////////////////////////////////////////////////////////////////////////// - -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 diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/events.hpp --- a/src/share/vm/utilities/events.hpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/events.hpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, 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 @@ -26,7 +26,10 @@ #define SHARE_VM_UTILITIES_EVENTS_HPP #include "memory/allocation.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/thread.hpp" #include "utilities/top.hpp" +#include "utilities/vmError.hpp" // Events and EventMark provide interfaces to log events taking place in the vm. // This facility is extremly useful for post-mortem debugging. The eventlog @@ -47,26 +50,246 @@ // Max 3 arguments are saved for each logged event. // -class Events : AllStatic { +// The base event log dumping class that is registered for dumping at +// crash time. This is a very generic interface that is mainly here +// for completeness. Normally the templated EventLogBase would be +// subclassed to provide different log types. +class EventLog : public CHeapObj { + friend class Events; + + private: + EventLog* _next; + + EventLog* next() const { return _next; } + public: - // Logs an event, format as printf - static void log(const char* format, ...) PRODUCT_RETURN; + // Automatically registers the log so that it will be printed during + // crashes. + EventLog(); + + virtual void print_log_on(outputStream* out) = 0; +}; + + +// A templated subclass of EventLog that provides basic ring buffer +// functionality. Most event loggers should subclass this, possibly +// providing a more featureful log function if the existing copy +// semantics aren't appropriate. The name is used as the label of the +// log when it is dumped during a crash. +template class EventLogBase : public EventLog { + template class EventRecord { + public: + jlong timestamp; + Thread* thread; + X data; + }; + + protected: + Mutex _mutex; + const char* _name; + int _length; + int _index; + int _count; + EventRecord* _records; + + public: + EventLogBase(const char* name, int length = LogEventsBufferEntries): + _name(name), + _length(length), + _count(0), + _index(0), + _mutex(Mutex::event, name) { + _records = new EventRecord[length]; + } - // Prints all events in the buffer - static void print_all(outputStream* st) PRODUCT_RETURN; + // move the ring buffer to next open slot and return the index of + // the slot to use for the current message. Should only be called + // while mutex is held. + int compute_log_index() { + int index = _index; + if (_count < _length) _count++; + _index++; + if (_index >= _length) _index = 0; + return index; + } + + bool should_log() { + // Don't bother adding new entries when we're crashing. This also + // avoids mutating the ring buffer when printing the log. + return !VMError::fatal_error_in_progress(); + } + + // Print the contents of the log + void print_log_on(outputStream* out); + + private: + void print_log_impl(outputStream* out); + + // Print a single element. A templated implementation might need to + // be declared by subclasses. + void print(outputStream* out, T& e); - // Prints last number events from the event buffer - static void print_last(outputStream *st, int number) PRODUCT_RETURN; + void print(outputStream* out, EventRecord& e) { + out->print("Event: " INT64_FORMAT " ", e.timestamp); + if (e.thread != NULL) { + out->print("Thread " INTPTR_FORMAT " ", e.thread); + } + print(out, e.data); + } +}; + +// A simple wrapper class for fixed size text messages. +class StringLogMessage : public FormatBuffer<132> { + public: + // Wrap this buffer in a stringStream. + stringStream stream() { + return stringStream(_buf, sizeof(_buf)); + } +}; + +// A simple ring buffer of fixed size text messages. +class StringEventLog : public EventLogBase { + public: + StringEventLog(const char* name, int count = LogEventsBufferEntries) : EventLogBase(name, count) {} + + void logv(Thread* thread, const char* format, va_list ap) { + if (!should_log()) return; + + jlong timestamp = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; + MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag); + int index = compute_log_index(); + _records[index].thread = thread; + _records[index].timestamp = timestamp; + _records[index].data.printv(format, ap); + } + + void log(Thread* thread, const char* format, ...) { + va_list ap; + va_start(ap, format); + logv(thread, format, ap); + va_end(ap); + } + }; + + +class Events : AllStatic { + friend class EventLog; + + private: + static EventLog* _logs; + + // A log for generic messages that aren't well categorized. + static StringEventLog* _messages; + + // A log for internal exception related messages, like internal + // throws and implicit exceptions. + static StringEventLog* _exceptions; + + // Deoptization related messages + static StringEventLog* _deopt_messages; + + public: + static void print_all(outputStream* out); + + static void print() { + print_all(tty); + } + + // Logs a generic message with timestamp and format as printf. + static void log(Thread* thread, const char* format, ...); + + // Log exception related message + static void log_exception(Thread* thread, const char* format, ...); + + static void log_deopt_message(Thread* thread, const char* format, ...); + + // Register default loggers + static void init(); +}; + + +inline void Events::log(Thread* thread, const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + _messages->logv(thread, format, ap); + va_end(ap); + } +} + +inline void Events::log_exception(Thread* thread, const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + _exceptions->logv(thread, format, ap); + va_end(ap); + } +} + +inline void Events::log_deopt_message(Thread* thread, const char* format, ...) { + if (LogEvents) { + va_list ap; + va_start(ap, format); + _deopt_messages->logv(thread, format, ap); + va_end(ap); + } +} + + +template +inline void EventLogBase::print_log_on(outputStream* out) { + if (ThreadLocalStorage::get_thread_slow() == NULL) { + // Not a regular Java thread so don't bother locking + print_log_impl(out); + } else { + MutexLockerEx ml(&_mutex, Mutex::_no_safepoint_check_flag); + print_log_impl(out); + } +} + +// Dump the ring buffer entries that current have entries. +template +inline void EventLogBase::print_log_impl(outputStream* out) { + out->print_cr("%s (%d events):", _name, _count); + if (_count == 0) { + out->print_cr("No events"); + return; + } + + if (_count < _length) { + for (int i = 0; i < _count; i++) { + print(out, _records[i]); + } + } else { + for (int i = _index; i < _length; i++) { + print(out, _records[i]); + } + for (int i = 0; i < _index; i++) { + print(out, _records[i]); + } + } + out->cr(); +} + +// Implement a printing routine for the StringLogMessage +template <> +inline void EventLogBase::print(outputStream* out, StringLogMessage& lm) { + out->print_raw(lm); + out->cr(); +} + +// Place markers for the beginning and end up of a set of events. +// These end up in the default log. class EventMark : public StackObj { + StringLogMessage _buffer; + public: // log a begin event, format as printf - EventMark(const char* format, ...) PRODUCT_RETURN; + EventMark(const char* format, ...); // log an end event - ~EventMark() PRODUCT_RETURN; + ~EventMark(); }; -int print_all_events(outputStream *st); - #endif // SHARE_VM_UTILITIES_EVENTS_HPP diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/exceptions.cpp --- a/src/share/vm/utilities/exceptions.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/exceptions.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, 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 @@ -160,7 +160,7 @@ thread->set_pending_exception(h_exception(), file, line); // vm log - Events::log("throw_exception " INTPTR_FORMAT, (address)h_exception()); + Events::log_exception(thread, "Threw " INTPTR_FORMAT " at %s:%d", (address)h_exception(), file, line); } diff -r f067b4e0e04b -r aa3d708d67c4 src/share/vm/utilities/vmError.cpp --- a/src/share/vm/utilities/vmError.cpp Wed Feb 01 10:36:58 2012 +0100 +++ b/src/share/vm/utilities/vmError.cpp Wed Feb 01 07:59:01 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, 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 @@ -36,6 +36,7 @@ #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/errorReporter.hpp" +#include "utilities/events.hpp" #include "utilities/top.hpp" #include "utilities/vmError.hpp" @@ -693,7 +694,14 @@ st->cr(); } - STEP(200, "(printing dynamic libraries)" ) + STEP(200, "(printing ring buffers)" ) + + if (_verbose) { + Events::print_all(st); + st->cr(); + } + + STEP(205, "(printing dynamic libraries)" ) if (_verbose) { // dynamic libraries, or memory map