7141200: log some interesting information in ring buffers for crashes

Reviewed-by: kvn, jrose, kevinw, brutisso, twisti, jmasa
This commit is contained in:
Tom Rodriguez 2012-02-01 07:59:01 -08:00
parent a59952f4c9
commit 5a41427b37
30 changed files with 539 additions and 369 deletions

View File

@ -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 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
#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 @@ LONG Handle_IDiv_Exception(struct _EXCEPTION_POINTERS* exceptionInfo) {
#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 @@ BOOL os::Advapi32Dll::AdvapiAvailable() {
}
#endif

View File

@ -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 @@ address Runtime1::exception_handler_for_pc(JavaThread* thread) {
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_END
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 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
// 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

View File

@ -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 @@ public:
// 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; }

View File

@ -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 @@ void CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
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

View File

@ -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 @@ nmethod::nmethod(
xtty->tail("print_native_nmethod");
}
}
Events::log("Create nmethod " INTPTR_FORMAT, this);
}
// For dtrace wrappers
@ -781,7 +780,6 @@ nmethod::nmethod(
xtty->tail("print_dtrace_nmethod");
}
}
Events::log("Create nmethod " INTPTR_FORMAT, this);
}
#endif // def HAVE_DTRACE_H
@ -889,13 +887,6 @@ nmethod::nmethod(
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 @@ void nmethod::flush() {
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);

View File

@ -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 @@ CompileTask* CompileBroker::_task_free_list = NULL;
GrowableArray<CompilerThread*>* 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 @@ void CompileTask::print_line() {
// ------------------------------------------------------------------
// 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) {
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,8 +412,10 @@ void CompileTask::print_compilation_impl(outputStream* st, methodOop method, int
if (msg != NULL) {
st->print(" %s", msg);
}
if (!short_form) {
st->cr();
}
}
// ------------------------------------------------------------------
// CompileTask::print_inlining
@ -426,12 +470,12 @@ void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
// ------------------------------------------------------------------
// 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 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
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 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
ci_env.record_method_not_compilable("compile failed", !TieredCompilation);
}
if (ci_env.failing()) {
// Copy this bit to the enclosing block:
compilable = ci_env.compilable();
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);
if (ci_env.failing()) {
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) {
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();

View File

@ -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 @@ class CompileTask : public CHeapObj {
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);

View File

@ -1228,9 +1228,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
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 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
_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 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
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 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
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 &&

View File

@ -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::allocate_stacks() {
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 @@ void G1MarkSweep::mark_sweep_phase2() {
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 @@ void G1MarkSweep::mark_sweep_phase3() {
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 @@ void G1MarkSweep::mark_sweep_phase4() {
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");

View File

@ -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 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
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 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
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::deallocate_stacks() {
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_phase1(bool clear_all_softrefs) {
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 @@ static PSAlwaysTrueClosure always_true;
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");

View File

@ -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 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values)
// 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_msg(SpaceId dst_space_id,
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 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
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 @@ GCTaskManager* const PSParallelCompact::gc_task_manager() {
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 @@ static PSAlwaysTrueClosure always_true;
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::adjust_roots() {
}
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::enqueue_region_stealing_tasks(
}
void PSParallelCompact::compact() {
EventMark m("5 compact");
// trace("5");
TraceTime tm("compaction phase", print_phases(), true, gclog_or_tty);
@ -3502,4 +3493,3 @@ void PSParallelCompact::compact_prologue() {
_updated_int_array_klass_obj = (klassOop)
summary_data().calc_new_pointer(Universe::intArrayKlassObj());
}

View File

@ -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 @@ bool PSScavenge::invoke_no_policy() {
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 @@ bool PSScavenge::invoke_no_policy() {
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();

View File

@ -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 @@ int CollectedHeap::_fire_out_of_memory_count = 0;
size_t CollectedHeap::_filler_array_max_size = 0;
template <>
void EventLogBase<GCMessage>::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 @@ CollectedHeap::CollectedHeap() : _n_par_threads(0)
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() {

View File

@ -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 AdaptiveSizePolicy;
class Thread;
class CollectorPolicy;
class GCMessage : public FormatBuffer<1024> {
public:
bool is_before;
public:
GCMessage() {}
};
class GCHeapLog : public EventLogBase<GCMessage> {
private:
void log_heap(bool before);
public:
GCHeapLog() : EventLogBase<GCMessage>("GC Heap History") {}
void log_heap_before() {
log_heap(true);
}
void log_heap_after() {
log_heap(false);
}
};
//
// CollectedHeap
// SharedHeap
@ -62,6 +86,8 @@ class CollectedHeap : public CHeapObj {
// 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 @@ class CollectedHeap : public CHeapObj {
// 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;

View File

@ -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,12 +479,10 @@ void GenCollectedHeap::do_collection(bool full,
const size_t perm_prev_used = perm_gen()->used();
if (PrintHeapAtGC) {
Universe::print_heap_before_gc();
print_heap_before_gc();
if (Verbose) {
gclog_or_tty->print_cr("GC Cause: %s", GCCause::to_string(gc_cause()));
}
}
{
FlagSetting fl(_is_gc_active, true);
@ -685,9 +683,7 @@ void GenCollectedHeap::do_collection(bool full,
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();

View File

@ -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::deallocate_stacks() {
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 @@ void GenMarkSweep::mark_sweep_phase2() {
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 @@ void GenMarkSweep::mark_sweep_phase3(int level) {
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 @@ void GenMarkSweep::mark_sweep_phase4() {
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");

View File

@ -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 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable))
}
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

View File

@ -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 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
#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 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
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 @@ void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects) {
#endif // COMPILER2
vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk) {
Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp());
#ifndef PRODUCT
if (TraceDeoptimization) {
@ -1026,7 +1028,6 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re
// 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 @@ void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) {
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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// 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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
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, &reg_map, thread);
compiledVFrame* cvf = compiledVFrame::cast(vf);

View File

@ -570,7 +570,7 @@ void frame::print_value_on(outputStream* st, JavaThread *thread) const {
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");

View File

@ -736,8 +736,11 @@ class CommandLineFlags {
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") \

View File

@ -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 vtableStubs_init();
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 @@ jint init_globals() {
InlineCacheBuffer_init();
compilerOracle_init();
compilationPolicy_init();
compileBroker_init();
VMRegImpl::set_regName();
if (!universe_post_init()) {

View File

@ -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 @@ void Monitor::set_owner_implementation(Thread *new_owner) {
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 @@ void Monitor::set_owner_implementation(Thread *new_owner) {
#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;

View File

@ -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 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
// 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 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) {
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

View File

@ -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 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// 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 @@ void Threads::add(JavaThread* p, bool force_daemon) {
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 @@ void Threads::remove(JavaThread* p) {
} // 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)

View File

@ -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 flush() {
}
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

View File

@ -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
@ -36,13 +36,20 @@ class FormatBuffer {
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; }
char* buffer() { return _buf; }
int size() { return bufsz; }
private:
FormatBuffer(const FormatBuffer &); // prevent copies
private:
protected:
char _buf[bufsz];
inline FormatBuffer();
};
template <size_t bufsz>
@ -53,6 +60,24 @@ FormatBuffer<bufsz>::FormatBuffer(const char * format, ...) {
va_end(argp);
}
template <size_t bufsz>
FormatBuffer<bufsz>::FormatBuffer() {
_buf[0] = '\0';
}
template <size_t bufsz>
void FormatBuffer<bufsz>::print(const char * format, ...) {
va_list argp;
va_start(argp, format);
jio_vsnprintf(_buf, bufsz, format, argp);
va_end(argp);
}
template <size_t bufsz>
void FormatBuffer<bufsz>::printv(const char * format, va_list argp) {
jio_vsnprintf(_buf, bufsz, format, argp);
}
template <size_t bufsz>
void FormatBuffer<bufsz>::append(const char* format, ...) {
// Given that the constructor does a vsnprintf we can assume that

View File

@ -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
EventLog* Events::_logs = NULL;
StringEventLog* Events::_messages = NULL;
StringEventLog* Events::_exceptions = NULL;
StringEventLog* Events::_deopt_messages = NULL;
////////////////////////////////////////////////////////////////////////////
// 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();
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;
}
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;
// 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();
}
}
// 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, ...) {
void Events::init() {
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);
_messages = new StringEventLog("Events");
_exceptions = new StringEventLog("Internal exceptions");
_deopt_messages = new StringEventLog("Deoptimization events");
}
}
void Events::print_all(outputStream *st) {
EventBuffer::print_all(st);
}
void Events::print_last(outputStream *st, int number) {
EventBuffer::print_last(st, number);
void eventlog_init() {
Events::init();
}
///////////////////////////////////////////////////////////////////////////
@ -230,37 +87,17 @@ 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);
// 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

View File

@ -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();
// Prints all events in the buffer
static void print_all(outputStream* st) PRODUCT_RETURN;
// Prints last number events from the event buffer
static void print_last(outputStream *st, int number) PRODUCT_RETURN;
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 T> class EventLogBase : public EventLog {
template <class X> class EventRecord {
public:
jlong timestamp;
Thread* thread;
X data;
};
protected:
Mutex _mutex;
const char* _name;
int _length;
int _index;
int _count;
EventRecord<T>* _records;
public:
EventLogBase<T>(const char* name, int length = LogEventsBufferEntries):
_name(name),
_length(length),
_count(0),
_index(0),
_mutex(Mutex::event, name) {
_records = new EventRecord<T>[length];
}
// 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);
void print(outputStream* out, EventRecord<T>& 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<StringLogMessage> {
public:
StringEventLog(const char* name, int count = LogEventsBufferEntries) : EventLogBase<StringLogMessage>(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 <class T>
inline void EventLogBase<T>::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 <class T>
inline void EventLogBase<T>::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<StringLogMessage>::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

View File

@ -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 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc
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);
}

View File

@ -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 @@ void VMError::report(outputStream* st) {
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