From 831a6f90556254aa9d59f00fe3cff5820508103d Mon Sep 17 00:00:00 2001
From: Synzura <867380348@qq.com>
Date: Fri, 6 Mar 2026 15:33:10 +0800
Subject: [PATCH] JProfileCache: add JProfileCache Conservative Init
.../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 17 +-
src/hotspot/cpu/aarch64/globals_aarch64.hpp | 8 +-
src/hotspot/share/compiler/compileBroker.cpp | 24 ++-
.../share/jprofilecache/jitProfileCache.cpp | 13 +-
.../jitProfileCacheFileParser.cpp | 24 ++-
.../jitProfileCacheFileParser.hpp | 4 +-
.../jprofilecache/jitProfileClassChain.cpp | 195 ++++++++++++++++--
.../jprofilecache/jitProfileClassChain.hpp | 15 +-
.../share/jprofilecache/jitProfileRecord.cpp | 64 ++++--
.../share/jprofilecache/jitProfileRecord.hpp | 28 ++-
src/hotspot/share/oops/instanceKlass.cpp | 20 +-
src/hotspot/share/runtime/arguments.cpp | 6 +
.../share/services/diagnosticCommand.cpp | 27 +++
.../share/services/diagnosticCommand.hpp | 18 ++
14 files changed, 403 insertions(+), 60 deletions(-)
@@ -34,6 +34,7 @@
#include "c1/c1_ValueStack.hpp"
#include "ci/ciArrayKlass.hpp"
#include "ci/ciInstance.hpp"
+#include "compiler/compileTask.hpp"
#include "code/compiledIC.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/gc_globals.hpp"
@@ -74,6 +75,18 @@ static void select_different_registers(Register preserve,
assert_different_registers(preserve, tmp1, tmp2);
}
+#ifdef ASSERT
+static bool is_linked_jprofile_conservative_c1_compilation(ciMethod* method, Compilation* compilation) {
+ CompileTask* task = compilation->env()->task();
+ return task != nullptr &&
+ task->is_jprofilecache_compilation() &&
+ JProfilingCacheCompileAdvance &&
+ !ProfileCacheAggressiveInit &&
+ method->holder()->is_instance_klass() &&
+ method->holder()->is_linked();
+}
+#endif
+
static void select_different_registers(Register preserve,
@@ -318,7 +331,9 @@ int LIR_Assembler::check_icache() {
void LIR_Assembler::clinit_barrier(ciMethod* method) {
assert(VM_Version::supports_fast_class_init_checks(), "sanity");
- assert(!method->holder()->is_not_initialized(), "initialization should have been started");
+ assert(!method->holder()->is_not_initialized() ||
+ is_linked_jprofile_conservative_c1_compilation(method, compilation()),
+ "initialization should have been started or be a linked JProfileCache conservative C1 compile");
Label L_skip_barrier;
@@ -125,6 +125,11 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(bool, JProfilingCacheCompileAdvance, false, EXPERIMENTAL, \
"Enable JProfilingCacheCompileAdvance from a log file") \
\
+ product(bool, ProfileCacheAggressiveInit, false, EXPERIMENTAL, \
+ "JProfileCache replay precompile strategy: "\
+ "false=conservative (link-only verify+prepare, no proactive <clinit>); "\
+ "true=aggressive (proactively initialize replay classes)") \
+ \
product(ccstr, CompilationProfileCacheExclude, nullptr, EXPERIMENTAL, \
"JProfilingCacheCompileAdvance excluding list ") \
\
@@ -133,7 +138,8 @@ define_pd_global(intx, InlineSmallCode, 1000);
\
product(uintx, JProfilingCacheDelayLoadTime, 1000, EXPERIMENTAL, \
"Sleep time (in milliseconds) before JProfileCache loads " \
- "classes and methods profile ") \
+ "classes and methods profile. In aggressive replay mode, " \
+ "values smaller than 50 are adjusted to 50 automatically.") \
range(0, 3600000) \
\
develop(bool, CompilationProfileCacheResolveClassEagerly, true, \
@@ -1149,6 +1149,21 @@ void CompileBroker::mark_on_stack() {
// CompileBroker::compile_method
//
// Request compilation of a method.
+#ifdef ASSERT
+static bool is_linked_jprofile_conservative_compilation(const methodHandle& method,
+ CompileTask::CompileReason compile_reason) {
+#ifdef AARCH64
+ return compile_reason == CompileTask::CompileReason::Reason_JitProfile &&
+ JProfilingCacheCompileAdvance &&
+ !ProfileCacheAggressiveInit &&
+ method->method_holder()->is_instance_klass() &&
+ method->method_holder()->is_linked();
+#else
+ return false;
+#endif
+}
+#endif
+
void CompileBroker::compile_method_base(const methodHandle& method,
int osr_bci,
int comp_level,
@@ -1160,8 +1175,9 @@ void CompileBroker::compile_method_base(const methodHandle& method,
guarantee(!method->is_abstract(), "cannot compile abstract methods");
assert(method->method_holder()->is_instance_klass(),
"sanity check");
- assert(!method->method_holder()->is_not_initialized(),
- "method holder must be initialized");
+ assert(!method->method_holder()->is_not_initialized() ||
+ is_linked_jprofile_conservative_compilation(method, compile_reason),
+ "method holder must be initialized or be a linked JProfileCache conservative compile");
assert(!method->is_method_handle_intrinsic(), "do not enqueue these guys");
if (CIPrintRequests) {
@@ -1363,7 +1379,9 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
assert(method->method_holder()->is_instance_klass(), "not an instance method");
assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range");
assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods");
- assert(!method->method_holder()->is_not_initialized(), "method holder must be initialized");
+ assert(!method->method_holder()->is_not_initialized() ||
+ is_linked_jprofile_conservative_compilation(method, compile_reason),
+ "method holder must be initialized or be a linked JProfileCache conservative compile");
// return quickly if possible
// lock, make sure that the compilation
@@ -120,12 +120,15 @@ JitProfileCache::JitProfileCacheState JitProfileCache::flush_recorder() {
if(_jit_profile_cache_state == IS_ERR) {
return _jit_profile_cache_state;
}
- _jit_profile_cache_recorder->flush_record();
- if (_jit_profile_cache_recorder->is_valid()) {
- _jit_profile_cache_state = IS_OK;
- } else {
+ if (!_jit_profile_cache_recorder->flush_record()) {
+ // Dump I/O failures are transient. Keep recorder/cache state so next jcmd can retry.
+ return IS_ERR;
+ }
+ if (!_jit_profile_cache_recorder->is_valid()) {
_jit_profile_cache_state = IS_ERR;
+ return _jit_profile_cache_state;
}
+ _jit_profile_cache_state = IS_OK;
return _jit_profile_cache_state;
}
@@ -284,4 +287,4 @@ void JitProfileCacheInfo::init() {
parser.increment_parsed_number_count();
}
log_info(jprofilecache)("JProfileCache [INFO]: parsed method number %d successful loaded %" PRIu64, parser.parsed_methods(), _method_loaded_count);
-}
\ No newline at end of file
+}
@@ -81,6 +81,7 @@ JitProfileCacheFileParser::JitProfileCacheFileParser(randomAccessFileStream* fs,
_position(0),
_parsed_method_count(0),
_total_recorder_method(0),
+ _parsed_version(0),
_file_stream(fs),
_max_symbol_length(0),
_parse_str_buf(nullptr),
@@ -211,11 +212,13 @@ bool JitProfileCacheFileParser::parse_header() {
u4 appid = read_u4();
unsigned int version = JitProfileCache::instance()->version();
- if (parse_version != version) {
+ if (parse_version < JITPROFILECACHE_VERSION_V1 || parse_version > version) {
_is_valid = false;
- log_error(jprofilecache)("[JitProfileCache] ERROR : Version mismatch, expect %d but %d", version, parse_version);
+ log_error(jprofilecache)("unsupported profile version %d, supported range is [%d, %d]",
+ parse_version, JITPROFILECACHE_VERSION_V1, version);
return false;
}
+ _parsed_version = parse_version;
if (parse_magic_number != JPROFILECACHE_MAGIC_NUMBER
|| (long)parse_file_size != this->file_size()) {
_is_valid = false;
@@ -260,6 +263,7 @@ bool JitProfileCacheFileParser::parse_class() {
int end_position = begin_position + (int)section_size;
u4 parse_cnt = read_u4();
logparse_illegal_count_check(parse_cnt, false, end_position);
+ const bool has_clinit_status = parsed_version() >= JITPROFILECACHE_VERSION_V2;
ProfileCacheClassChain* chain = new ProfileCacheClassChain(parse_cnt);
info_holder()->set_chain(chain);
@@ -271,6 +275,17 @@ bool JitProfileCacheFileParser::parse_class() {
logparse_illegal_check(parse_loader_char, false, end_position);
const char* parse_path_char = read_string();
logparse_illegal_check(parse_path_char, false, end_position);
+ bool clinit_succeeded = true;
+ if (has_clinit_status) {
+ u1 parse_clinit_status = read_u1();
+ logparse_illegal_count_check(parse_clinit_status, false, end_position);
+ if (parse_clinit_status != 0 && parse_clinit_status != 1) {
+ log_error(jprofilecache)("illegal class init status %u", parse_clinit_status);
+ _position = end_position;
+ return false;
+ }
+ clinit_succeeded = parse_clinit_status == 1;
+ }
Symbol* name = create_symbol(parse_name_char);
Symbol* loader_name = create_symbol(parse_loader_char);
Symbol* path = create_symbol(parse_path_char);
@@ -278,6 +293,7 @@ bool JitProfileCacheFileParser::parse_class() {
chain->at(i)->set_class_name(name);
chain->at(i)->set_class_loader_name(loader_name);
chain->at(i)->set_class_path(path);
+ chain->at(i)->set_recorded_clinit_succeeded(clinit_succeeded);
check_class(i, name, loader_name, path, chain);
@@ -285,7 +301,7 @@ bool JitProfileCacheFileParser::parse_class() {
// check section size
if (_position - begin_position != (int)section_size) {
- log_error(jprofilecache)("[JitProfileCache] ERROR : JitProfile class parse fail");
+ log_error(jprofilecache)("class section parse failed");
return false;
}
return true;
@@ -430,4 +446,4 @@ void JitProfileCacheFileParser::parse_profile_data(ProfileCacheMethodHold* mh) {
profile_list->append(bpr);
count--;
}
-}
\ No newline at end of file
+}
@@ -58,6 +58,7 @@ public:
int parsed_methods() { return _parsed_method_count; }
int total_recorder_method() { return _total_recorder_method; }
+ unsigned int parsed_version() const { return _parsed_version; }
long file_size() { return _file_size; }
void set_file_size(long size) { _file_size = size; }
@@ -81,6 +82,7 @@ private:
int _position;
int _parsed_method_count;
int _total_recorder_method;
+ unsigned int _parsed_version;
randomAccessFileStream* _file_stream;
int _max_symbol_length;
@@ -97,4 +99,4 @@ private:
};
-#endif // LINUX_AARCH64_NORMAL_SERVER_FASTDEBUG_JITPROFILECACHELOGPARSER_H
\ No newline at end of file
+#endif // LINUX_AARCH64_NORMAL_SERVER_FASTDEBUG_JITPROFILECACHELOGPARSER_H
@@ -79,6 +79,20 @@ bool ProfileCacheClassChain::ProfileCacheClassChainEntry::is_all_initialized() {
return true;
}
+bool ProfileCacheClassChain::ProfileCacheClassChainEntry::is_all_linked() {
+ int len = resolved_klasses()->length();
+ if (len == 0) {
+ return false;
+ }
+ for (int i = 0; i < len; i++) {
+ InstanceKlass* k = resolved_klasses()->at(i);
+ if (k != nullptr && !k->is_linked() && !k->is_in_error_state()) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool ProfileCacheClassChain::ProfileCacheClassChainEntry::contains_redefined_class() {
int len = resolved_klasses()->length();
for (int i = 0; i < len; i++) {
@@ -105,6 +119,17 @@ InstanceKlass* ProfileCacheClassChain::ProfileCacheClassChainEntry::get_first_un
return nullptr;
}
+InstanceKlass* ProfileCacheClassChain::ProfileCacheClassChainEntry::get_first_unlinked_klass() {
+ int len = resolved_klasses()->length();
+ for (int i = 0; i < len; i++) {
+ InstanceKlass* k = resolved_klasses()->at(i);
+ if (k != nullptr && !k->is_linked() && !k->is_in_error_state()) {
+ return k;
+ }
+ }
+ return nullptr;
+}
+
ProfileCacheClassChain::ProfileCacheClassChain(unsigned int size)
: _class_chain_inited_index(-1),
_loaded_class_index(-1),
@@ -274,6 +299,23 @@ void ProfileCacheClassChain::update_loaded_index(int index) {
set_loaded_index(index - 1);
}
+static bool mark_skipped_if_redefined(ProfileCacheClassChain::ProfileCacheClassChainEntry* entry) {
+ if (entry->contains_redefined_class()) {
+ entry->set_skipped();
+ return true;
+ }
+ return false;
+}
+
+static void enqueue_methods(ProfileCacheClassChain::ProfileCacheClassChainEntry* entry,
+ Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue) {
+ ProfileCacheMethodHold* mh = entry->method_holder();
+ while (mh != nullptr) {
+ compile_queue.push(mh);
+ mh = mh->next();
+ }
+}
+
void ProfileCacheClassChain::compile_methodholders_queue(Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue) {
while (!compile_queue.is_empty()) {
ProfileCacheMethodHold* pmh = compile_queue.pop();
@@ -290,14 +332,134 @@ void ProfileCacheClassChain::compile_methodholders_queue(Stack<ProfileCacheMetho
}
void ProfileCacheClassChain::precompilation() {
- Thread* THREAD = Thread::current();
if (!try_transition_to_state(PROFILECACHE_COMPILING)) {
log_warning(jprofilecache)("JProfileCache [WARNING]: The compilation cannot be started in the current state");
return;
}
+ const bool aggressive_mode = ProfileCacheAggressiveInit;
+ log_info(jprofilecache)("precompile mode=%s",
+ aggressive_mode ? "aggressive" : "conservative");
+ if (aggressive_mode) {
+ precompile_aggressive();
+ } else {
+ precompile_conservative();
+ }
+}
+
+void ProfileCacheClassChain::precompile_conservative() {
+ Thread* THREAD = Thread::current();
bool cancel_precompilation = false;
+ for (int index = 0; index < length(); index++) {
+ if (cancel_precompilation) {
+ break;
+ }
+ InstanceKlass* klass = nullptr;
+ Stack<ProfileCacheMethodHold*, mtInternal> compile_queue;
+ {
+ MutexLocker mu(ProfileCacheClassChain_lock);
+ ProfileCacheClassChainEntry* entry = &_entries[index];
+ switch (entry->class_state()) {
+ case ProfileCacheClassChainEntry::_not_loaded:
+ // Keep conservative mode consistent so index refresh can progress.
+ entry->set_skipped();
+ case ProfileCacheClassChainEntry::_load_skipped:
+ break;
+ case ProfileCacheClassChainEntry::_class_loaded:
+ klass = entry->get_first_unlinked_klass();
+ if (klass == nullptr && entry->is_all_linked()) {
+ entry->set_inited();
+ if (!mark_skipped_if_redefined(entry)) {
+ enqueue_methods(entry, compile_queue);
+ }
+ }
+ break;
+ case ProfileCacheClassChainEntry::_class_inited:
+ if (!mark_skipped_if_redefined(entry)) {
+ enqueue_methods(entry, compile_queue);
+ }
+ break;
+ default:
+ {
+ ResourceMark rm;
+ log_error(jprofilecache)("[JitProfileCache] ERROR: class %s has an invalid state %d",
+ entry->class_name()->as_C_string(),
+ entry->class_state());
+ return;
+ }
+ }
+ }
+
+ // Conservative mode is link-only: drive verify+prepare without proactive <clinit>.
+ while (klass != nullptr) {
+ assert(THREAD->is_Java_thread(), "sanity check");
+ klass->link_class((JavaThread*)THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ Symbol* loader = JitProfileCacheUtils::get_class_loader_name(klass->class_loader_data());
+ ResourceMark rm;
+ log_warning(jprofilecache)("[JitProfileCache] WARNING: Exceptions happened in linking %s being loaded by %s",
+ klass->name()->as_C_string(), loader->as_C_string());
+ CLEAR_PENDING_EXCEPTION;
+ MutexLocker mu(ProfileCacheClassChain_lock);
+ _entries[index].set_skipped();
+ klass = nullptr;
+ break;
+ }
+
+ {
+ MutexLocker mu(ProfileCacheClassChain_lock);
+ ProfileCacheClassChainEntry* entry = &_entries[index];
+ klass = entry->get_first_unlinked_klass();
+ if (klass == nullptr && entry->is_loaded() && entry->is_all_linked()) {
+ entry->set_inited();
+ if (!mark_skipped_if_redefined(entry)) {
+ enqueue_methods(entry, compile_queue);
+ }
+ }
+ }
+ }
+
+ {
+ MutexLocker mu(ProfileCacheClassChain_lock);
+ refresh_indexes();
+ if (index > class_chain_inited_index()) {
+ cancel_precompilation = true;
+ }
+ }
+
+ compile_methodholders_queue(compile_queue);
+ }
+}
+
+void ProfileCacheClassChain::precompile_aggressive() {
+ Thread* THREAD = Thread::current();
+ bool cancel_precompilation = false;
+ int aggressive_upper_bound = length() - 1;
+ int first_recorded_clinit_failure_index = -1;
+ {
+ MutexLocker mu(ProfileCacheClassChain_lock);
+ for (int i = 0; i < length(); i++) {
+ if (!_entries[i].recorded_clinit_succeeded()) {
+ first_recorded_clinit_failure_index = i;
+ aggressive_upper_bound = i - 1;
+ break;
+ }
+ }
+ }
+ if (first_recorded_clinit_failure_index >= 0) {
+ log_info(jprofilecache)("aggressive replay stops before first recorded <clinit> failure at index=%d (upper_bound=%d)",
+ first_recorded_clinit_failure_index, aggressive_upper_bound);
+ } else {
+ log_info(jprofilecache)("aggressive replay has no recorded <clinit> failure (upper_bound=%d)",
+ aggressive_upper_bound);
+ }
+
for ( int index = 0; index < length(); index++ ) {
+ if (index > aggressive_upper_bound) {
+ log_info(jprofilecache)("aggressive replay reached configured stop index=%d",
+ aggressive_upper_bound);
+ break;
+ }
if (cancel_precompilation) {
break;
}
@@ -372,19 +534,24 @@ bool ProfileCacheClassChain::compile_method(ProfileCacheMethodHold* mh) {
}
InstanceKlass* klass = m->constants()->pool_holder();
-
- // if klass not initialize return
- if (!klass->is_initialized()) {
- return false;
+ const int comp_level = mh->compile_level();
+ if (!ProfileCacheAggressiveInit) {
+ // Conservative replay keeps class handling at link-only.
+ if (!klass->is_linked() || klass->is_in_error_state()) {
+ return false;
+ }
+ } else {
+ // Aggressive mode keeps initialized gate.
+ if (!klass->is_initialized()) {
+ return false;
+ }
}
- m->set_compiled_by_jprofilecache(true);
- m->set_jpc_method_holder(mh);
- int bci = InvocationEntryBci;
-
- // commit compile
- bool ret = JitProfileCacheUtils::commit_compilation(m, mh->compile_level(), bci, t);
+ const int bci = InvocationEntryBci;
+ bool ret = JitProfileCacheUtils::commit_compilation(m, comp_level, bci, t);
if (ret) {
+ m->set_compiled_by_jprofilecache(true);
+ m->set_jpc_method_holder(mh);
ResourceMark rm;
log_info(jprofilecache)("[JitProfileCache] method %s successfully compiled",
m->name_and_sig_as_C_string());
@@ -396,6 +563,7 @@ void ProfileCacheClassChain::refresh_indexes() {
assert_lock_strong(ProfileCacheClassChain_lock);
int loaded = loaded_index();
int inited = class_chain_inited_index();
+ const bool use_linked_gate = !ProfileCacheAggressiveInit;
for (int i = inited + 1; i < length(); i++) {
ProfileCacheClassChainEntry* e = &_entries[i];
int len = e->resolved_klasses()->length();
@@ -404,7 +572,7 @@ void ProfileCacheClassChain::refresh_indexes() {
}
if (e->is_loaded()) {
assert(len > 0, "class init chain entry state error");
- if (e->is_all_initialized()) {
+ if (use_linked_gate ? e->is_all_linked() : e->is_all_initialized()) {
e->set_inited();
}
}
@@ -514,10 +682,11 @@ void ProfileCacheClassChain::preload_class_in_constantpool() {
}
if (current_k != nullptr) {
+ ResourceMark rm;
current_k->constants()->preload_jprofilecache_classes(JavaThread::current());
log_info(jprofilecache)("[JitProfileCache] class %s is preloaded",
current_k->internal_name());
}
klass_index++;
}
-}
\ No newline at end of file
+}
@@ -79,6 +79,7 @@ public:
_class_loader_name(nullptr),
_class_path(nullptr),
_class_state(_not_loaded),
+ _recorded_clinit_succeeded(true),
_method_holder(nullptr),
_resolved_klasses(new (mtClass) GrowableArray<InstanceKlass*>(1, mtClass)),
_method_keep_holders(new (mtClass) GrowableArray<jobject>(1, mtClass)) { }
@@ -88,6 +89,7 @@ public:
_class_loader_name(loader_name),
_class_path(path),
_class_state(_not_loaded),
+ _recorded_clinit_succeeded(true),
_method_holder(nullptr),
_resolved_klasses(new (mtClass) GrowableArray<InstanceKlass*>(1, mtClass)),
_method_keep_holders(new (mtClass) GrowableArray<jobject>(1, mtClass)) { }
@@ -127,6 +129,8 @@ public:
void set_class_state(int state) { _class_state = state;}
int class_state() { return _class_state; }
+ bool recorded_clinit_succeeded() const { return _recorded_clinit_succeeded; }
+ void set_recorded_clinit_succeeded(bool value) { _recorded_clinit_succeeded = value; }
void add_method_holder(ProfileCacheMethodHold* h) {
h->set_next(_method_holder);
@@ -135,10 +139,14 @@ public:
bool is_all_initialized();
+ bool is_all_linked();
+
bool contains_redefined_class();
InstanceKlass* get_first_uninitialized_klass();
+ InstanceKlass* get_first_unlinked_klass();
+
ProfileCacheMethodHold* method_holder() { return _method_holder; }
private:
@@ -147,6 +155,7 @@ public:
Symbol* _class_loader_name;
Symbol* _class_path;
int _class_state;
+ bool _recorded_clinit_succeeded;
ProfileCacheMethodHold* _method_holder;
GrowableArray<InstanceKlass*>* _resolved_klasses;
@@ -220,6 +229,10 @@ private:
void update_class_chain(InstanceKlass* ky, int chain_index);
+ void precompile_conservative();
+
+ void precompile_aggressive();
+
void compile_methodholders_queue(Stack<ProfileCacheMethodHold*, mtInternal>& compile_queue);
void update_loaded_index(int index);
@@ -228,4 +241,4 @@ private:
ProfileCacheClassHolder* holder);
};
-#endif // SHARED_VM_JPROFILECACHE_JITPROFILECLASSCHAIN_HPP
\ No newline at end of file
+#endif // SHARED_VM_JPROFILECACHE_JITPROFILECLASSCHAIN_HPP
@@ -77,18 +77,19 @@ JitProfileRecorder::JitProfileRecorder():
_max_symbol_length(0),
_pos(0),
_class_init_order_num(-1),
- _flushed(false),
_record_file_name(nullptr),
_profilelog(nullptr),
_recorder_state(NOT_INIT),
_class_init_list(nullptr),
_init_list_tail_node(nullptr),
+ _class_init_nodes(nullptr),
_profile_record_dict(nullptr){}
JitProfileRecorder::~JitProfileRecorder() {
if (!ProfilingCacheFile) {
os::free((void*)logfile_name());
}
+ delete _class_init_nodes;
delete _class_init_list;
}
@@ -156,6 +157,7 @@ void JitProfileRecorder::init() {
}
_class_init_list = new (mtInternal) LinkedListImpl<ClassSymbolEntry>();
+ _class_init_nodes = new (mtInternal) GrowableArray<LinkedListNode<ClassSymbolEntry>*>(128, mtInternal);
_profile_record_dict = new JitProfileRecordDictionary(PROFILE_RECORDER_HT_SIZE);
_recorder_state = IS_OK;
@@ -174,14 +176,19 @@ int JitProfileRecorder::assign_class_init_order(InstanceKlass* klass) {
return -1;
}
MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
+ LinkedListNode<ClassSymbolEntry>* node = nullptr;
if (_init_list_tail_node == nullptr) {
- _class_init_list->add(ClassSymbolEntry(record_name, record_loader_name, record_path));
- _init_list_tail_node = _class_init_list->head();
+ node = _class_init_list->add(ClassSymbolEntry(record_name, record_loader_name, record_path));
+ _init_list_tail_node = node;
} else {
- _class_init_list->insert_after(ClassSymbolEntry(record_name, record_loader_name, record_path),
- _init_list_tail_node);
- _init_list_tail_node = _init_list_tail_node->next();
+ node = _class_init_list->insert_after(ClassSymbolEntry(record_name, record_loader_name, record_path),
+ _init_list_tail_node);
+ _init_list_tail_node = node;
}
+ if (node == nullptr) {
+ return -1;
+ }
+ _class_init_nodes->append(node);
_class_init_order_num++;
#ifndef PRODUCT
klass->set_initialize_order(_class_init_order_num);
@@ -189,12 +196,22 @@ int JitProfileRecorder::assign_class_init_order(InstanceKlass* klass) {
return _class_init_order_num;
}
-void JitProfileRecorder::add_method(Method* method, int method_bci) {
+void JitProfileRecorder::mark_class_init_result(int init_order, bool success) {
+ if (init_order < 0) {
+ return;
+ }
MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
- // if is flushed, stop adding method
- if (is_flushed()) {
+ if (_class_init_nodes == nullptr || init_order >= _class_init_nodes->length()) {
return;
}
+ LinkedListNode<ClassSymbolEntry>* node = _class_init_nodes->at(init_order);
+ if (node != nullptr) {
+ node->data()->set_clinit_succeeded(success);
+ }
+}
+
+void JitProfileRecorder::add_method(Method* method, int method_bci) {
+ MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
// not deal with OSR Compilation
if (method_bci != InvocationEntryBci) {
return;
@@ -375,6 +392,7 @@ void JitProfileRecorder::write_inited_class() {
write_u4((u4)class_init_count());
int cnt = 0;
+ int success_cnt = 0;
const LinkedListNode<ClassSymbolEntry>* node = class_init_list()->head();
while (node != nullptr) {
const ClassSymbolEntry* record_entry = node->peek();
@@ -394,10 +412,16 @@ void JitProfileRecorder::write_inited_class() {
write_string(record_class_name, strlen(record_class_name));
write_string(record_class_loader_name, strlen(record_class_loader_name));
write_string(path, strlen(path));
+ write_u1(record_entry->clinit_succeeded() ? (u1)1 : (u1)0);
+ if (record_entry->clinit_succeeded()) {
+ success_cnt++;
+ }
node = node->next();
cnt++;
}
assert(cnt == class_init_count(), "error happened in profile info record");
+ log_info(jprofilecache)("class init records total=%d success=%d failed=%d",
+ cnt, success_cnt, cnt - success_cnt);
unsigned int end_position = _pos;
unsigned int section_size = end_position - begin_position;
overwrite_u4(section_size, size_anchor);
@@ -538,12 +562,13 @@ void JitProfileRecorder::record_method_info(Method *method, ConstMethod* const_m
void JitProfileRecorder::write_profilecache_footer() {
}
-void JitProfileRecorder::flush_record() {
+bool JitProfileRecorder::flush_record() {
MutexLocker mu(JitProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
- if (!is_valid() || is_flushed()) {
- return;
+ if (!is_valid()) {
+ return false;
}
- set_flushed(true);
+ _pos = 0;
+ _max_symbol_length = 0;
// open randomAccessFileStream
if (JProfilingCacheAutoArchiveDir != nullptr) {
@@ -552,8 +577,7 @@ void JitProfileRecorder::flush_record() {
int fd = open(logfile_name(), O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
log_error(jprofilecache)("[JitProfileCache] ERROR : open log file fail! path is %s", logfile_name());
- _recorder_state = IS_ERR;
- return;
+ return false;
}
close(fd);
@@ -561,8 +585,9 @@ void JitProfileRecorder::flush_record() {
}
if (_profilelog == nullptr || !_profilelog->is_open()) {
log_error(jprofilecache)("[JitProfileCache] ERROR : open log file fail! path is %s", logfile_name());
- _recorder_state = IS_ERR;
- return;
+ delete _profilelog;
+ _profilelog = nullptr;
+ return false;
}
// head section
@@ -598,7 +623,7 @@ void JitProfileRecorder::flush_record() {
_profilelog = nullptr;
::unlink(logfile_name());
log_error(jprofilecache)("[JitProfileCache] Autogenerate jprofilecache file failed to rename!");
- return;
+ return false;
}
}
@@ -607,4 +632,5 @@ void JitProfileRecorder::flush_record() {
_profilelog = nullptr;
log_info(jprofilecache)("[JitProfileCache] Profile information output completed. File: %s", logfile_name());
-}
\ No newline at end of file
+ return true;
+}
@@ -30,6 +30,7 @@
#include "oops/method.hpp"
#include "oops/methodData.hpp"
#include "utilities/linkedlist.hpp"
+#include "utilities/growableArray.hpp"
class JitProfileRecorderEntry : public HashtableEntry<Method*, mtInternal> {
public:
@@ -83,10 +84,11 @@ private:
class ClassSymbolEntry {
public:
- ClassSymbolEntry(Symbol* class_name, Symbol* class_loader_name, Symbol* path)
+ ClassSymbolEntry(Symbol* class_name, Symbol* class_loader_name, Symbol* path, bool clinit_succeeded = false)
: _class_name(class_name),
_class_loader_name(class_loader_name),
- _class_path(path) {
+ _class_path(path),
+ _clinit_succeeded(clinit_succeeded) {
if (_class_name != nullptr) _class_name->increment_refcount();
if (_class_loader_name != nullptr) _class_loader_name->increment_refcount();
if (_class_path != nullptr) _class_path->increment_refcount();
@@ -95,7 +97,8 @@ public:
ClassSymbolEntry()
: _class_name(nullptr),
_class_loader_name(nullptr),
- _class_path(nullptr) {
+ _class_path(nullptr),
+ _clinit_succeeded(false) {
}
~ClassSymbolEntry() {
@@ -107,6 +110,8 @@ public:
Symbol* class_name() const { return _class_name; }
Symbol* class_loader_name() const { return _class_loader_name; }
Symbol* path() const { return _class_path; }
+ bool clinit_succeeded() const { return _clinit_succeeded; }
+ void set_clinit_succeeded(bool succeeded) { _clinit_succeeded = succeeded; }
bool equals(const ClassSymbolEntry& rhs) const {
return _class_name == rhs._class_name;
@@ -116,11 +121,14 @@ private:
Symbol* _class_name;
Symbol* _class_loader_name;
Symbol* _class_path;
+ bool _clinit_succeeded;
};
#define KNUTH_HASH_MULTIPLIER 2654435761UL
#define ADDR_CHANGE_NUMBER 3
-#define JITPROFILECACHE_VERSION 0x1
+#define JITPROFILECACHE_VERSION_V1 0x1
+#define JITPROFILECACHE_VERSION_V2 0x2
+#define JITPROFILECACHE_VERSION JITPROFILECACHE_VERSION_V2
class JitProfileRecorder : public CHeapObj<mtInternal> {
public:
@@ -141,9 +149,6 @@ public:
address current_init_order_addr() { return (address)&_class_init_order_num;}
- unsigned int is_flushed() { return _flushed; }
- void set_flushed(bool value) { _flushed = value; }
-
const char* logfile_name() { return _record_file_name; }
unsigned int recorded_count() { return _profile_record_dict->count(); }
@@ -158,9 +163,10 @@ public:
void add_method(Method* method, int method_bci);
- void flush_record();
+ bool flush_record();
int assign_class_init_order(InstanceKlass* klass);
+ void mark_class_init_result(int init_order, bool success);
unsigned int compute_hash(Method* method) {
uint64_t m_addr = (uint64_t)method;
@@ -179,7 +185,6 @@ private:
int _max_symbol_length;
unsigned int _pos;
volatile int _class_init_order_num;
- volatile bool _flushed;
const char* _record_file_name;
static const char* _auto_jpcfile_name;
static const char* _auto_temp_jpcfile_name;
@@ -189,7 +194,8 @@ private:
RecorderState _recorder_state;
LinkedListImpl<ClassSymbolEntry>* _class_init_list;
LinkedListNode<ClassSymbolEntry>* _init_list_tail_node;
- JitProfileRecordDictionary* _profile_record_dict;
+ GrowableArray<LinkedListNode<ClassSymbolEntry>*>* _class_init_nodes;
+ JitProfileRecordDictionary* _profile_record_dict;
private:
void write_u1(u1 value);
@@ -210,4 +216,4 @@ private:
void update_max_symbol_length(int len);
};
-#endif // SHARED_VM_JPROFILECACHE_JITPROFILERECORD_HPP
\ No newline at end of file
+#endif // SHARED_VM_JPROFILECACHE_JITPROFILERECORD_HPP
@@ -1070,6 +1070,9 @@ void InstanceKlass::initialize_impl(TRAPS) {
bool wait = false;
JavaThread* jt = THREAD;
+#ifdef AARCH64
+ int jpc_init_order = -1;
+#endif
bool debug_logging_enabled = log_is_enabled(Debug, class, init);
@@ -1152,7 +1155,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
#ifdef AARCH64
if (JProfilingCacheRecording) {
- JitProfileCache::instance()->recorder()->assign_class_init_order(this);
+ jpc_init_order = JitProfileCache::instance()->recorder()->assign_class_init_order(this);
}
#endif
}
@@ -1177,6 +1180,11 @@ void InstanceKlass::initialize_impl(TRAPS) {
if (HAS_PENDING_EXCEPTION) {
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
+#ifdef AARCH64
+ if (JProfilingCacheRecording) {
+ JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, false);
+ }
+#endif
{
EXCEPTION_MARK;
add_initialization_error(THREAD, e);
@@ -1215,12 +1223,22 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 9
if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, CHECK);
+#ifdef AARCH64
+ if (JProfilingCacheRecording) {
+ JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, true);
+ }
+#endif
debug_only(vtable().verify(tty, true);)
}
else {
// Step 10 and 11
Handle e(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
+#ifdef AARCH64
+ if (JProfilingCacheRecording) {
+ JitProfileCache::instance()->recorder()->mark_class_init_result(jpc_init_order, false);
+ }
+#endif
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
JvmtiExport::clear_detected_exception(jt);
@@ -3227,6 +3227,12 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
}
}
}
+
+ if (JProfilingCacheCompileAdvance && ProfileCacheAggressiveInit && JProfilingCacheDelayLoadTime < 50) {
+ warning("JProfilingCacheDelayLoadTime (%u) is too small in aggressive replay mode, adjusted to 50 ms",
+ (uint)JProfilingCacheDelayLoadTime);
+ JProfilingCacheDelayLoadTime = 50;
+ }
#endif
return JNI_OK;
@@ -35,6 +35,9 @@
#include "compiler/directivesParser.hpp"
#include "gc/shared/gcVMOperations.hpp"
#include "gc/shared/gcArguments.hpp"
+#ifdef AARCH64
+#include "jprofilecache/jitProfileCache.hpp"
+#endif
#include "jvm.h"
#include "memory/metaspace/metaspaceDCmd.hpp"
#include "memory/resourceArea.hpp"
@@ -103,6 +106,9 @@ void DCmd::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMInfoDCmd>(full_export, true, false));
+#ifdef AARCH64
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JProfileCacheDumpDCmd>(full_export, true, false));
+#endif
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
@@ -400,6 +406,27 @@ void VMInfoDCmd::execute(DCmdSource source, TRAPS) {
VMError::print_vm_info(_output);
}
+#ifdef AARCH64
+void JProfileCacheDumpDCmd::execute(DCmdSource source, TRAPS) {
+ if (!JProfilingCacheRecording) {
+ output()->print_cr("JProfileCache recording is not enabled.");
+ return;
+ }
+
+ JitProfileCache* jpc = JitProfileCache::instance();
+ if (jpc == nullptr) {
+ output()->print_cr("JProfileCache is not initialized.");
+ return;
+ }
+
+ if (jpc->flush_recorder() == JitProfileCache::IS_OK) {
+ output()->print_cr("JProfileCache dump completed.");
+ } else {
+ output()->print_cr("JProfileCache dump failed.");
+ }
+}
+#endif
+
void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
Universe::heap()->collect(GCCause::_dcmd_gc_run);
}
@@ -248,6 +248,24 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
+#ifdef AARCH64
+class JProfileCacheDumpDCmd : public DCmd {
+public:
+ JProfileCacheDumpDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
+ static const char* name() { return "VM.jprofilecache_dump"; }
+ static const char* description() {
+ return "Dump JProfileCache recording data immediately.";
+ }
+ static const char* impact() { return "Low"; }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "monitor", nullptr};
+ return p;
+ }
+ virtual void execute(DCmdSource source, TRAPS);
+};
+#endif
+
class SystemGCDCmd : public DCmd {
public:
SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
--
2.43.0