8318444: Write details about compilation bailouts into crash reports
Reviewed-by: thartmann, chagedorn
This commit is contained in:
parent
29397d29ba
commit
c90768c93b
@ -33,10 +33,12 @@
|
||||
#include "c1/c1_ValueMap.hpp"
|
||||
#include "c1/c1_ValueStack.hpp"
|
||||
#include "code/debugInfoRec.hpp"
|
||||
#include "compiler/compilationFailureInfo.hpp"
|
||||
#include "compiler/compilationMemoryStatistic.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "compiler/compileLog.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -582,6 +584,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
|
||||
, _has_monitors(false)
|
||||
, _install_code(install_code)
|
||||
, _bailout_msg(nullptr)
|
||||
, _first_failure_details(nullptr)
|
||||
, _exception_info_list(nullptr)
|
||||
, _allocator(nullptr)
|
||||
, _code(buffer_blob)
|
||||
@ -626,7 +629,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho
|
||||
Compilation::~Compilation() {
|
||||
// simulate crash during compilation
|
||||
assert(CICrashAt < 0 || (uintx)_env->compile_id() != (uintx)CICrashAt, "just as planned");
|
||||
|
||||
delete _first_failure_details;
|
||||
_env->set_compiler_data(nullptr);
|
||||
}
|
||||
|
||||
@ -652,6 +655,9 @@ void Compilation::bailout(const char* msg) {
|
||||
// keep first bailout message
|
||||
if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg);
|
||||
_bailout_msg = msg;
|
||||
if (CaptureBailoutInformation) {
|
||||
_first_failure_details = new CompilationFailureInfo(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
|
||||
class CompilationFailureInfo;
|
||||
class CompilationResourceObj;
|
||||
class XHandlers;
|
||||
class ExceptionInfo;
|
||||
@ -85,6 +86,7 @@ class Compilation: public StackObj {
|
||||
bool _has_monitors; // Fastpath monitors detection for Continuations
|
||||
bool _install_code;
|
||||
const char* _bailout_msg;
|
||||
CompilationFailureInfo* _first_failure_details; // Details for the first failure happening during compilation
|
||||
bool _oom;
|
||||
ExceptionInfoList* _exception_info_list;
|
||||
ExceptionHandlerTable _exception_handler_table;
|
||||
@ -212,6 +214,7 @@ class Compilation: public StackObj {
|
||||
void bailout(const char* msg);
|
||||
bool bailed_out() const { return _bailout_msg != nullptr; }
|
||||
const char* bailout_msg() const { return _bailout_msg; }
|
||||
const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; }
|
||||
|
||||
static uint desired_max_code_buffer_size() {
|
||||
return (uint)NMethodSizeLimit; // default 64K
|
||||
|
@ -362,7 +362,7 @@ public:
|
||||
|
||||
// The compiler task which has created this env.
|
||||
// May be useful to find out compile_id, comp_level, etc.
|
||||
CompileTask* task() { return _task; }
|
||||
CompileTask* task() const { return _task; }
|
||||
|
||||
// Handy forwards to the task:
|
||||
int comp_level(); // task()->comp_level()
|
||||
@ -444,7 +444,7 @@ public:
|
||||
static ciEnv* current(CompilerThread *thread) { return thread->env(); }
|
||||
|
||||
// Per-compiler data. (Used by C2 to publish the Compile* pointer.)
|
||||
void* compiler_data() { return _compiler_data; }
|
||||
void* compiler_data() const { return _compiler_data; }
|
||||
void set_compiler_data(void* x) { _compiler_data = x; }
|
||||
|
||||
// Notice that a method has been inlined in the current compile;
|
||||
|
121
src/hotspot/share/compiler/compilationFailureInfo.cpp
Normal file
121
src/hotspot/share/compiler/compilationFailureInfo.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Compilation.hpp"
|
||||
#endif
|
||||
#include "ci/ciEnv.hpp"
|
||||
#include "compiler/abstractCompiler.hpp"
|
||||
#include "compiler/compilationFailureInfo.hpp"
|
||||
#include "compiler/compileTask.hpp"
|
||||
#ifdef COMPILER2
|
||||
#include "opto/node.hpp"
|
||||
#include "opto/compile.hpp"
|
||||
#endif
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#include "utilities/nativeCallStack.hpp"
|
||||
|
||||
CompilationFailureInfo::CompilationFailureInfo(const char* failure_reason) :
|
||||
_stack(2),
|
||||
_failure_reason(os::strdup(failure_reason)),
|
||||
_elapsed_seconds(os::elapsedTime()),
|
||||
_compile_id(ciEnv::current()->task()->compile_id())
|
||||
{}
|
||||
|
||||
CompilationFailureInfo::~CompilationFailureInfo() {
|
||||
os::free(_failure_reason);
|
||||
}
|
||||
|
||||
void CompilationFailureInfo::print_on(outputStream* st) const {
|
||||
st->print(" Time: ");
|
||||
os::print_elapsed_time(st, _elapsed_seconds);
|
||||
st->print_cr(" Compile id: %d", _compile_id);
|
||||
st->print_cr(" Reason: '%s'", _failure_reason);
|
||||
st->print_cr(" Callstack: ");
|
||||
_stack.print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
// Convenience function to print current compile failure iff
|
||||
// current thread is compiler thread and there is a pending failure.
|
||||
// Otherwise prints nothing.
|
||||
bool CompilationFailureInfo::print_pending_compilation_failure(outputStream* st) {
|
||||
|
||||
const CompilationFailureInfo* info = nullptr;
|
||||
|
||||
// Carefully tiptoeing because we are called from the error reporter and
|
||||
// nothing is certain.
|
||||
|
||||
const Thread* const t = Thread::current();
|
||||
if (t == nullptr || !t->is_Compiler_thread()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ciEnv* const env = ciEnv::current();
|
||||
if (env == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const CompileTask* const task = env->task();
|
||||
if (task == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const AbstractCompiler* const compiler = task->compiler();
|
||||
if (compiler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef COMPILER1
|
||||
if (compiler->type() == compiler_c1) {
|
||||
const Compilation* const C = (Compilation*)env->compiler_data();
|
||||
if (C != nullptr) {
|
||||
info = C->first_failure_details();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef COMPILER2
|
||||
if (compiler->type() == compiler_c2) {
|
||||
const Compile* const C = (Compile*)env->compiler_data();
|
||||
if (C != nullptr) {
|
||||
info = C->first_failure_details();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info != nullptr) {
|
||||
st->print_cr("Pending compilation failure details for thread " PTR_FORMAT ":", p2i(t));
|
||||
info->print_on(st);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // defined(COMPILER1) || defined(COMPILER2)
|
57
src/hotspot/share/compiler/compilationFailureInfo.hpp
Normal file
57
src/hotspot/share/compiler/compilationFailureInfo.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP
|
||||
#define SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/nativeCallStack.hpp"
|
||||
|
||||
class outputStream;
|
||||
class Symbol;
|
||||
|
||||
class CompilationFailureInfo : public CHeapObj<mtCompiler> {
|
||||
NativeCallStack _stack;
|
||||
char* const _failure_reason;
|
||||
const double _elapsed_seconds;
|
||||
const int _compile_id;
|
||||
public:
|
||||
CompilationFailureInfo(const char* failure_reason);
|
||||
~CompilationFailureInfo();
|
||||
void print_on(outputStream* st) const;
|
||||
|
||||
// Convenience function to print, safely, current compile failure iff
|
||||
// current thread is compiler thread and there is an ongoing compilation
|
||||
// and a pending failure.
|
||||
// Otherwise prints nothing.
|
||||
static bool print_pending_compilation_failure(outputStream* st);
|
||||
};
|
||||
|
||||
#endif // defined(COMPILER1) || defined(COMPILER2)
|
||||
|
||||
#endif // SHARE_COMPILER_COMPILATIONFAILUREINFO_HPP
|
@ -379,6 +379,10 @@
|
||||
"Don't compile methods larger than this if " \
|
||||
"+DontCompileHugeMethods") \
|
||||
\
|
||||
product(bool, CaptureBailoutInformation, trueInDebug, DIAGNOSTIC, \
|
||||
"If compilation is stopped with an error, capture diagnostic " \
|
||||
"information at the bailout point") \
|
||||
\
|
||||
|
||||
// end of COMPILER_FLAGS
|
||||
|
||||
|
@ -29,9 +29,11 @@
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "code/exceptionHandlerTable.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "compiler/compilationFailureInfo.hpp"
|
||||
#include "compiler/compilationMemoryStatistic.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/compileLog.hpp"
|
||||
#include "compiler/compiler_globals.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "compiler/oopMap.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
@ -637,6 +639,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
_directive(directive),
|
||||
_log(ci_env->log()),
|
||||
_failure_reason(nullptr),
|
||||
_first_failure_details(nullptr),
|
||||
_intrinsics (comp_arena(), 0, 0, nullptr),
|
||||
_macro_nodes (comp_arena(), 8, 0, nullptr),
|
||||
_parse_predicates (comp_arena(), 8, 0, nullptr),
|
||||
@ -926,6 +929,7 @@ Compile::Compile( ciEnv* ci_env,
|
||||
_directive(directive),
|
||||
_log(ci_env->log()),
|
||||
_failure_reason(nullptr),
|
||||
_first_failure_details(nullptr),
|
||||
_congraph(nullptr),
|
||||
NOT_PRODUCT(_igv_printer(nullptr) COMMA)
|
||||
_unique(0),
|
||||
@ -989,6 +993,11 @@ Compile::Compile( ciEnv* ci_env,
|
||||
Code_Gen();
|
||||
}
|
||||
|
||||
Compile::~Compile() {
|
||||
delete _print_inlining_stream;
|
||||
delete _first_failure_details;
|
||||
};
|
||||
|
||||
//------------------------------Init-------------------------------------------
|
||||
// Prepare for a single compilation
|
||||
void Compile::Init(bool aliasing) {
|
||||
@ -4358,6 +4367,9 @@ void Compile::record_failure(const char* reason) {
|
||||
if (_failure_reason == nullptr) {
|
||||
// Record the first failure reason.
|
||||
_failure_reason = reason;
|
||||
if (CaptureBailoutInformation) {
|
||||
_first_failure_details = new CompilationFailureInfo(reason);
|
||||
}
|
||||
}
|
||||
|
||||
if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
|
||||
|
@ -53,6 +53,7 @@ class Bundle;
|
||||
class CallGenerator;
|
||||
class CallStaticJavaNode;
|
||||
class CloneMap;
|
||||
class CompilationFailureInfo;
|
||||
class ConnectionGraph;
|
||||
class IdealGraphPrinter;
|
||||
class InlineTree;
|
||||
@ -363,6 +364,7 @@ class Compile : public Phase {
|
||||
DirectiveSet* _directive; // Compiler directive
|
||||
CompileLog* _log; // from CompilerThread
|
||||
const char* _failure_reason; // for record_failure/failing pattern
|
||||
CompilationFailureInfo* _first_failure_details; // Details for the first failure happening during compilation
|
||||
GrowableArray<CallGenerator*> _intrinsics; // List of intrinsics.
|
||||
GrowableArray<Node*> _macro_nodes; // List of nodes which need to be expanded before matching.
|
||||
GrowableArray<ParsePredicateNode*> _parse_predicates; // List of Parse Predicates.
|
||||
@ -809,6 +811,7 @@ private:
|
||||
CompileLog* log() const { return _log; }
|
||||
bool failing() const { return _env->failing() || _failure_reason != nullptr; }
|
||||
const char* failure_reason() const { return (_env->failing()) ? _env->failure_reason() : _failure_reason; }
|
||||
const CompilationFailureInfo* first_failure_details() const { return _first_failure_details; }
|
||||
|
||||
bool failure_reason_is(const char* r) const {
|
||||
return (r == _failure_reason) || (r != nullptr && _failure_reason != nullptr && strcmp(r, _failure_reason) == 0);
|
||||
@ -1125,9 +1128,7 @@ private:
|
||||
int is_fancy_jump, bool pass_tls,
|
||||
bool return_pc, DirectiveSet* directive);
|
||||
|
||||
~Compile() {
|
||||
delete _print_inlining_stream;
|
||||
};
|
||||
~Compile();
|
||||
|
||||
// Are we compiling a method?
|
||||
bool has_method() { return method() != nullptr; }
|
||||
|
@ -1105,10 +1105,11 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
static constexpr int secs_per_day = 86400;
|
||||
static constexpr int secs_per_hour = 3600;
|
||||
static constexpr int secs_per_min = 60;
|
||||
|
||||
void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
const int secs_per_day = 86400;
|
||||
const int secs_per_hour = 3600;
|
||||
const int secs_per_min = 60;
|
||||
|
||||
time_t tloc;
|
||||
(void)time(&tloc);
|
||||
@ -1134,9 +1135,15 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
}
|
||||
|
||||
double t = os::elapsedTime();
|
||||
st->print(" elapsed time: ");
|
||||
print_elapsed_time(st, t);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_elapsed_time(outputStream* st, double time) {
|
||||
// NOTE: a crash using printf("%f",...) on Linux was historically noted here.
|
||||
int eltime = (int)t; // elapsed time in seconds
|
||||
int eltimeFraction = (int) ((t - eltime) * 1000000);
|
||||
int eltime = (int)time; // elapsed time in seconds
|
||||
int eltimeFraction = (int) ((time - eltime) * 1000000);
|
||||
|
||||
// print elapsed time in a human-readable format:
|
||||
int eldays = eltime / secs_per_day;
|
||||
@ -1146,7 +1153,7 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
int elmins = (eltime - day_secs - hour_secs) / secs_per_min;
|
||||
int minute_secs = elmins * secs_per_min;
|
||||
int elsecs = (eltime - day_secs - hour_secs - minute_secs);
|
||||
st->print_cr(" elapsed time: %d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
|
||||
st->print("%d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
|
||||
}
|
||||
|
||||
|
||||
|
@ -789,6 +789,7 @@ class os: AllStatic {
|
||||
static void print_siginfo(outputStream* st, const void* siginfo);
|
||||
static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
|
||||
static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
|
||||
static void print_elapsed_time(outputStream* st, double time);
|
||||
|
||||
static void print_user_info(outputStream* st);
|
||||
static void print_active_locale(outputStream* st);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/compilationFailureInfo.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "gc/shared/gcConfig.hpp"
|
||||
@ -1053,6 +1054,12 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
check_failing_cds_access(st, _siginfo);
|
||||
st->cr();
|
||||
|
||||
#if defined(COMPILER1) || defined(COMPILER2)
|
||||
STEP_IF("printing pending compilation failure",
|
||||
_verbose && _thread != nullptr && _thread->is_Compiler_thread())
|
||||
CompilationFailureInfo::print_pending_compilation_failure(st);
|
||||
#endif
|
||||
|
||||
STEP_IF("printing registers", _verbose && _context != nullptr)
|
||||
// printing registers
|
||||
os::print_context(st, _context);
|
||||
|
Loading…
Reference in New Issue
Block a user