8318444: Write details about compilation bailouts into crash reports

Reviewed-by: thartmann, chagedorn
This commit is contained in:
Thomas Stuefe 2024-01-08 13:47:43 +00:00
parent 29397d29ba
commit c90768c93b
11 changed files with 231 additions and 12 deletions

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;

View 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)

View 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

View File

@ -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

View File

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

View File

@ -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; }

View File

@ -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);
}

View File

@ -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);

View File

@ -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);