8330198: Add some class loading related perf counters to measure VM startup

Co-authored-by: Vladimir Ivanov <vlivanov@openjdk.org>
Reviewed-by: iklam, dholmes
This commit is contained in:
Calvin Cheung 2024-06-14 01:18:30 +00:00
parent c4702ca8c0
commit eb2488fd17
14 changed files with 154 additions and 16 deletions

View File

@ -31,6 +31,7 @@
#include "cds/classPrelinker.hpp"
#include "cds/dynamicArchive.hpp"
#include "cds/regeneratedClasses.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
@ -118,6 +119,9 @@ public:
return;
}
log_info(cds,dynamic)("CDS dynamic dump: clinit = " JLONG_FORMAT "ms)",
ClassLoader::class_init_time_ms());
init_header();
gather_source_objs();
gather_array_klasses();

View File

@ -78,6 +78,7 @@
#include "utilities/classpathStream.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/utf8.hpp"
// Entry point in java.dll for path canonicalization
@ -118,9 +119,40 @@ PerfCounter* ClassLoader::_perf_define_appclass_time = nullptr;
PerfCounter* ClassLoader::_perf_define_appclass_selftime = nullptr;
PerfCounter* ClassLoader::_perf_app_classfile_bytes_read = nullptr;
PerfCounter* ClassLoader::_perf_sys_classfile_bytes_read = nullptr;
PerfCounter* ClassLoader::_perf_ik_link_methods_time = nullptr;
PerfCounter* ClassLoader::_perf_method_adapters_time = nullptr;
PerfCounter* ClassLoader::_perf_ik_link_methods_count = nullptr;
PerfCounter* ClassLoader::_perf_method_adapters_count = nullptr;
PerfCounter* ClassLoader::_unsafe_defineClassCallCounter = nullptr;
PerfCounter* ClassLoader::_perf_secondary_hash_time = nullptr;
PerfCounter* ClassLoader::_perf_resolve_indy_time = nullptr;
PerfCounter* ClassLoader::_perf_resolve_invokehandle_time = nullptr;
PerfCounter* ClassLoader::_perf_resolve_mh_time = nullptr;
PerfCounter* ClassLoader::_perf_resolve_mt_time = nullptr;
PerfCounter* ClassLoader::_perf_resolve_indy_count = nullptr;
PerfCounter* ClassLoader::_perf_resolve_invokehandle_count = nullptr;
PerfCounter* ClassLoader::_perf_resolve_mh_count = nullptr;
PerfCounter* ClassLoader::_perf_resolve_mt_count = nullptr;
void ClassLoader::print_counters(outputStream *st) {
// The counters are only active if the logging is enabled, but
// we print to the passed in outputStream as requested.
if (log_is_enabled(Info, perf, class, link)) {
st->print_cr("ClassLoader:");
st->print_cr(" clinit: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", ClassLoader::class_init_time_ms(), ClassLoader::class_init_count());
st->print_cr(" link methods: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_ik_link_methods_time->get_value()) , _perf_ik_link_methods_count->get_value());
st->print_cr(" method adapters: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_method_adapters_time->get_value()) , _perf_method_adapters_count->get_value());
st->print_cr(" resolve...");
st->print_cr(" invokedynamic: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_resolve_indy_time->get_value()) , _perf_resolve_indy_count->get_value());
st->print_cr(" invokehandle: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_resolve_invokehandle_time->get_value()) , _perf_resolve_invokehandle_count->get_value());
st->print_cr(" CP_MethodHandle: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_resolve_mh_time->get_value()) , _perf_resolve_mh_count->get_value());
st->print_cr(" CP_MethodType: " JLONG_FORMAT "ms / " JLONG_FORMAT " events", Management::ticks_to_ms(_perf_resolve_mt_time->get_value()) , _perf_resolve_mt_count->get_value());
st->cr();
}
}
GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = nullptr;
GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = nullptr;
ClassPathEntry* ClassLoader::_jrt_entry = nullptr;
@ -1336,9 +1368,25 @@ void ClassLoader::initialize(TRAPS) {
NEWPERFTICKCOUNTER(_perf_define_appclass_selftime, SUN_CLS, "defineAppClassTime.self");
NEWPERFBYTECOUNTER(_perf_app_classfile_bytes_read, SUN_CLS, "appClassBytes");
NEWPERFBYTECOUNTER(_perf_sys_classfile_bytes_read, SUN_CLS, "sysClassBytes");
NEWPERFEVENTCOUNTER(_unsafe_defineClassCallCounter, SUN_CLS, "unsafeDefineClassCalls");
NEWPERFTICKCOUNTER(_perf_secondary_hash_time, SUN_CLS, "secondarySuperHashTime");
if (log_is_enabled(Info, perf, class, link)) {
NEWPERFTICKCOUNTER(_perf_ik_link_methods_time, SUN_CLS, "linkMethodsTime");
NEWPERFTICKCOUNTER(_perf_method_adapters_time, SUN_CLS, "makeAdaptersTime");
NEWPERFEVENTCOUNTER(_perf_ik_link_methods_count, SUN_CLS, "linkMethodsCount");
NEWPERFEVENTCOUNTER(_perf_method_adapters_count, SUN_CLS, "makeAdaptersCount");
NEWPERFTICKCOUNTER(_perf_resolve_indy_time, SUN_CLS, "resolve_invokedynamic_time");
NEWPERFTICKCOUNTER(_perf_resolve_invokehandle_time, SUN_CLS, "resolve_invokehandle_time");
NEWPERFTICKCOUNTER(_perf_resolve_mh_time, SUN_CLS, "resolve_MethodHandle_time");
NEWPERFTICKCOUNTER(_perf_resolve_mt_time, SUN_CLS, "resolve_MethodType_time");
NEWPERFEVENTCOUNTER(_perf_resolve_indy_count, SUN_CLS, "resolve_invokedynamic_count");
NEWPERFEVENTCOUNTER(_perf_resolve_invokehandle_count, SUN_CLS, "resolve_invokehandle_count");
NEWPERFEVENTCOUNTER(_perf_resolve_mh_count, SUN_CLS, "resolve_MethodHandle_count");
NEWPERFEVENTCOUNTER(_perf_resolve_mt_count, SUN_CLS, "resolve_MethodType_count");
}
}
// lookup java library entry points

View File

@ -30,6 +30,7 @@
#include "runtime/perfDataTypes.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/zipLibrary.hpp"
// The VM class loader.
@ -166,6 +167,20 @@ class ClassLoader: AllStatic {
static PerfCounter* _perf_define_appclass_selftime;
static PerfCounter* _perf_app_classfile_bytes_read;
static PerfCounter* _perf_sys_classfile_bytes_read;
static PerfCounter* _perf_ik_link_methods_time;
static PerfCounter* _perf_method_adapters_time;
static PerfCounter* _perf_ik_link_methods_count;
static PerfCounter* _perf_method_adapters_count;
static PerfCounter* _perf_resolve_indy_time;
static PerfCounter* _perf_resolve_invokehandle_time;
static PerfCounter* _perf_resolve_mh_time;
static PerfCounter* _perf_resolve_mt_time;
static PerfCounter* _perf_resolve_indy_count;
static PerfCounter* _perf_resolve_invokehandle_count;
static PerfCounter* _perf_resolve_mh_count;
static PerfCounter* _perf_resolve_mt_count;
static PerfCounter* _unsafe_defineClassCallCounter;
@ -285,6 +300,23 @@ class ClassLoader: AllStatic {
static PerfCounter* perf_app_classfile_bytes_read() { return _perf_app_classfile_bytes_read; }
static PerfCounter* perf_sys_classfile_bytes_read() { return _perf_sys_classfile_bytes_read; }
static PerfCounter* perf_ik_link_methods_time() { return _perf_ik_link_methods_time; }
static PerfCounter* perf_method_adapters_time() { return _perf_method_adapters_time; }
static PerfCounter* perf_ik_link_methods_count() { return _perf_ik_link_methods_count; }
static PerfCounter* perf_method_adapters_count() { return _perf_method_adapters_count; }
static PerfCounter* perf_resolve_invokedynamic_time() { return _perf_resolve_indy_time; }
static PerfCounter* perf_resolve_invokehandle_time() { return _perf_resolve_invokehandle_time; }
static PerfCounter* perf_resolve_method_handle_time() { return _perf_resolve_mh_time; }
static PerfCounter* perf_resolve_method_type_time() { return _perf_resolve_mt_time; }
static PerfCounter* perf_resolve_invokedynamic_count() { return _perf_resolve_indy_count; }
static PerfCounter* perf_resolve_invokehandle_count() { return _perf_resolve_invokehandle_count; }
static PerfCounter* perf_resolve_method_handle_count() { return _perf_resolve_mh_count; }
static PerfCounter* perf_resolve_method_type_count() { return _perf_resolve_mt_count; }
static void print_counters(outputStream *st);
// Record how many calls to Unsafe_DefineClass
static PerfCounter* unsafe_defineClassCallCounter() {
return _unsafe_defineClassCallCounter;

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "cds/archiveUtils.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
@ -55,7 +56,8 @@
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
@ -1728,6 +1730,10 @@ bool LinkResolver::resolve_previously_linked_invokehandle(CallInfo& result, cons
}
void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokehandle_time(),
ClassLoader::perf_resolve_invokehandle_count());
LinkInfo link_info(pool, index, Bytecodes::_invokehandle, CHECK);
if (log_is_enabled(Info, methodhandles)) {
ResourceMark rm(THREAD);
@ -1779,6 +1785,9 @@ void LinkResolver::resolve_handle_call(CallInfo& result,
}
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {
PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokedynamic_time(),
ClassLoader::perf_resolve_invokedynamic_count());
int pool_index = pool->resolved_indy_entry_at(indy_index)->constant_pool_index();
// Resolve the bootstrap specifier (BSM + optional arguments).

View File

@ -110,6 +110,7 @@ class outputStream;
LOG_TAG(jvmti) \
LOG_TAG(lambda) \
LOG_TAG(library) \
LOG_TAG(link) \
LOG_TAG(liveness) \
LOG_TAG(load) /* Trace all classes loaded */ \
LOG_TAG(loader) \

View File

@ -29,6 +29,7 @@
#include "cds/cdsConfig.hpp"
#include "cds/classPrelinker.hpp"
#include "cds/heapShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/metadataOnStackMark.hpp"
@ -62,7 +63,8 @@
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/signature.hpp"
#include "runtime/vframe.inline.hpp"
#include "utilities/checkedCast.hpp"
@ -1014,7 +1016,9 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
}
case JVM_CONSTANT_Dynamic:
{
{ PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokedynamic_time(),
ClassLoader::perf_resolve_invokedynamic_count());
// Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
BootstrapInfo bootstrap_specifier(this_cp, cp_index);
@ -1072,7 +1076,9 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
break;
case JVM_CONSTANT_MethodHandle:
{
{ PerfTraceTimedEvent timer(ClassLoader::perf_resolve_method_handle_time(),
ClassLoader::perf_resolve_method_handle_count());
int ref_kind = this_cp->method_handle_ref_kind_at(cp_index);
int callee_index = this_cp->method_handle_klass_index_at(cp_index);
Symbol* name = this_cp->method_handle_name_ref_at(cp_index);
@ -1120,7 +1126,9 @@ oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
}
case JVM_CONSTANT_MethodType:
{
{ PerfTraceTimedEvent timer(ClassLoader::perf_resolve_method_type_time(),
ClassLoader::perf_resolve_method_type_count());
Symbol* signature = this_cp->method_type_signature_at(cp_index);
{ ResourceMark rm(THREAD);
log_debug(class, resolve)("resolve JVM_CONSTANT_MethodType [%d/%d] %s",

View File

@ -978,6 +978,8 @@ void InstanceKlass::rewrite_class(TRAPS) {
// This is outside is_rewritten flag. In case of an exception, it can be
// executed more than once.
void InstanceKlass::link_methods(TRAPS) {
PerfTraceTime timer(ClassLoader::perf_ik_link_methods_time());
int len = methods()->length();
for (int i = len-1; i >= 0; i--) {
methodHandle m(THREAD, methods()->at(i));

View File

@ -26,6 +26,7 @@
#include "cds/cdsConfig.hpp"
#include "cds/cppVtables.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
@ -62,12 +63,14 @@
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/atomic.hpp"
#include "runtime/arguments.hpp"
#include "runtime/continuationEntry.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/java.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/perfData.hpp"
#include "runtime/relocator.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
@ -1168,6 +1171,10 @@ void Method::remove_unshareable_flags() {
// Called when the method_holder is getting linked. Setup entrypoints so the method
// is ready to be called from interpreter, compiler, and vtables.
void Method::link_method(const methodHandle& h_method, TRAPS) {
if (log_is_enabled(Info, perf, class, link)) {
ClassLoader::perf_ik_link_methods_count()->inc();
}
// If the code cache is full, we may reenter this function for the
// leftover methods that weren't linked.
if (adapter() != nullptr) {
@ -1219,6 +1226,8 @@ void Method::link_method(const methodHandle& h_method, TRAPS) {
}
address Method::make_adapters(const methodHandle& mh, TRAPS) {
PerfTraceTime timer(ClassLoader::perf_method_adapters_time());
// Adapters for compiled code are made eagerly here. They are fairly
// small (generally < 100 bytes) and quick to make (and cached and shared)
// so making them eagerly shouldn't be too expensive.

View File

@ -3729,6 +3729,13 @@ jint Arguments::apply_ergo() {
}
#endif // COMPILER2_OR_JVMCI
if (log_is_enabled(Info, perf, class, link)) {
if (!UsePerfData) {
warning("Disabling -Xlog:perf+class+link since UsePerfData is turned off.");
LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(perf, class, link));
}
}
if (FLAG_IS_CMDLINE(DiagnoseSyncOnValueBasedClasses)) {
if (DiagnoseSyncOnValueBasedClasses == ObjectSynchronizer::LOG_WARNING && !log_is_enabled(Info, valuebasedclasses)) {
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(valuebasedclasses));

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "cds/cds_globals.hpp"
#include "cds/dynamicArchive.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
@ -156,7 +157,6 @@ static void print_method_profiling_data() {
}
}
#ifndef PRODUCT
// Statistics printing (method invocation histogram)
@ -356,6 +356,8 @@ void print_statistics() {
}
ThreadsSMRSupport::log_statistics();
ClassLoader::print_counters(tty);
}
// Note: before_exit() can be executed only once, if more than one threads

View File

@ -296,7 +296,7 @@ void PerfDataManager::add_item(PerfData* p, bool sampled) {
_has_PerfData = true;
}
assert(!_all->contains(p->name()), "duplicate name added");
assert(!_all->contains(p->name()), "duplicate name added: %s", p->name());
// add to the list of all perf data items
_all->append(p);
@ -527,8 +527,3 @@ PerfDataList* PerfDataList::clone() {
return copy;
}
PerfTraceTime::~PerfTraceTime() {
if (!UsePerfData) return;
_t.stop();
_timerp->inc(_t.ticks());
}

View File

@ -831,11 +831,20 @@ class PerfTraceTime : public StackObj {
public:
inline PerfTraceTime(PerfLongCounter* timerp) : _timerp(timerp) {
if (!UsePerfData) return;
if (!UsePerfData || timerp == nullptr) { return; }
_t.start();
}
~PerfTraceTime();
const char* name() const {
assert(_timerp != nullptr, "sanity");
return _timerp->name();
}
~PerfTraceTime() {
if (!UsePerfData || !_t.is_active()) { return; }
_t.stop();
_timerp->inc(_t.ticks());
}
};
/* The PerfTraceTimedEvent class is responsible for counting the
@ -864,7 +873,7 @@ class PerfTraceTimedEvent : public PerfTraceTime {
public:
inline PerfTraceTimedEvent(PerfLongCounter* timerp, PerfLongCounter* eventp): PerfTraceTime(timerp), _eventp(eventp) {
if (!UsePerfData) return;
if (!UsePerfData || timerp == nullptr) { return; }
_eventp->inc();
}

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/vmClasses.hpp"
@ -55,6 +56,7 @@
#include "prims/jvmtiThreadState.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
@ -63,6 +65,7 @@
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/perfData.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stackWatermarkSet.hpp"
#include "runtime/stubRoutines.hpp"
@ -2570,6 +2573,9 @@ AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_ada
int total_args_passed,
BasicType* sig_bt,
bool allocate_code_blob) {
if (log_is_enabled(Info, perf, class, link)) {
ClassLoader::perf_method_adapters_count()->inc();
}
// StubRoutines::_final_stubs_code is initialized after this function can be called. As a result,
// VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated prior

View File

@ -821,6 +821,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
MetaspaceShared::preload_and_dump();
}
if (log_is_enabled(Info, perf, class, link)) {
LogStreamHandle(Info, perf, class, link) log;
log.print_cr("At VM initialization completion:");
ClassLoader::print_counters(&log);
}
return JNI_OK;
}