8170672: Event-based tracing to support classloader instances

Reviewed-by: hseigel, egahlin
This commit is contained in:
Markus Grönlund 2016-12-06 22:49:17 +01:00
parent 8bf0437430
commit 6a685f1d63
13 changed files with 95 additions and 59 deletions

View File

@ -5412,7 +5412,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
}
}
TRACE_INIT_KLASS_ID(ik);
TRACE_INIT_ID(ik);
// If we reach here, all is well.
// Now remove the InstanceKlass* from the _klass_to_deallocate field

View File

@ -97,7 +97,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
_next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
// empty
TRACE_INIT_ID(this);
}
void ClassLoaderData::init_dependencies(TRAPS) {
@ -167,9 +167,10 @@ void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
}
void ClassLoaderData::classes_do(void f(Klass * const)) {
assert_locked_or_safepoint(_metaspace_lock);
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
// Lock-free access requires load_ptr_acquire
for (Klass* k = load_ptr_acquire(&_klasses); k != NULL; k = k->next_link()) {
f(k);
assert(k != k->next_link(), "no loops!");
}
}
@ -812,6 +813,16 @@ void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
}
}
void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
// Only walk the head until any clds not purged from prior unloading
// (CMS doesn't purge right away).
for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) {
assert(cld->is_unloading(), "invariant");
cl->do_cld(cld);
}
}
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
CLDClosure* closure = cld->keep_alive() ? strong : weak;
@ -1042,7 +1053,7 @@ void ClassLoaderDataGraph::purge() {
}
}
void ClassLoaderDataGraph::post_class_unload_events(void) {
void ClassLoaderDataGraph::post_class_unload_events() {
#if INCLUDE_TRACE
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
if (Tracing::enabled()) {
@ -1191,9 +1202,7 @@ void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
EventClassUnload event(UNTIMED);
event.set_endtime(_class_unload_time);
event.set_unloadedClass(k);
oop defining_class_loader = k->class_loader();
event.set_definingClassLoader(defining_class_loader != NULL ?
defining_class_loader->klass() : (Klass*)NULL);
event.set_definingClassLoader(k->class_loader_data());
event.commit();
}

View File

@ -30,6 +30,7 @@
#include "memory/metaspace.hpp"
#include "memory/metaspaceCounters.hpp"
#include "runtime/mutex.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_TRACE
@ -78,7 +79,7 @@ class ClassLoaderDataGraph : public AllStatic {
static bool _metaspace_oom;
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
static void post_class_unload_events(void);
static void post_class_unload_events();
public:
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
@ -89,6 +90,7 @@ class ClassLoaderDataGraph : public AllStatic {
static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
// cld do
static void cld_do(CLDClosure* cl);
static void cld_unloading_do(CLDClosure* cl);
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
static void keep_alive_cld_do(CLDClosure* cl);
static void always_strong_cld_do(CLDClosure* cl);
@ -210,6 +212,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
static Metaspace* _ro_metaspace;
static Metaspace* _rw_metaspace;
TRACE_DEFINE_TRACE_ID_FIELD;
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
@ -342,6 +346,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
assert(_shared_class_loader_id <0, "cannot be assigned more than once");
_shared_class_loader_id = id;
}
TRACE_DEFINE_TRACE_ID_METHODS;
};
// An iterator that distributes Klasses to parallel worker threads.

View File

@ -309,7 +309,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle
}
}
TRACE_INIT_MODULE_ID(entry);
TRACE_INIT_ID(entry);
return entry;
}

View File

@ -214,7 +214,7 @@ PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, Modu
entry->set_hash(hash);
entry->set_literal(name);
TRACE_INIT_PACKAGE_ID(entry);
TRACE_INIT_ID(entry);
// Initialize fields specific to a PackageEntry
entry->init();

View File

@ -621,35 +621,28 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load(
return (nh);
}
// utility function for class load event
static void post_class_load_event(const Ticks& start_time,
instanceKlassHandle k,
Handle initiating_loader) {
const ClassLoaderData* init_cld) {
#if INCLUDE_TRACE
EventClassLoad event(UNTIMED);
if (event.should_commit()) {
event.set_starttime(start_time);
event.set_loadedClass(k());
oop defining_class_loader = k->class_loader();
event.set_definingClassLoader(defining_class_loader != NULL ?
defining_class_loader->klass() : (Klass*)NULL);
oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
event.set_initiatingClassLoader(class_loader != NULL ?
class_loader->klass() : (Klass*)NULL);
event.set_definingClassLoader(k->class_loader_data());
event.set_initiatingClassLoader(init_cld);
event.commit();
}
#endif // INCLUDE_TRACE
}
// utility function for class define event
static void class_define_event(instanceKlassHandle k) {
static void class_define_event(instanceKlassHandle k,
const ClassLoaderData* def_cld) {
#if INCLUDE_TRACE
EventClassDefine event(UNTIMED);
EventClassDefine event;
if (event.should_commit()) {
event.set_definedClass(k());
oop defining_class_loader = k->class_loader();
event.set_definingClassLoader(defining_class_loader != NULL ?
defining_class_loader->klass() : (Klass*)NULL);
event.set_definingClassLoader(def_cld);
event.commit();
}
#endif // INCLUDE_TRACE
@ -907,7 +900,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
return NULL;
}
post_class_load_event(class_load_start_time, k, class_loader);
post_class_load_event(class_load_start_time, k, loader_data);
#ifdef ASSERT
{
@ -1090,7 +1083,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
JvmtiExport::post_class_load((JavaThread *) THREAD, k());
}
post_class_load_event(class_load_start_time, k, class_loader);
post_class_load_event(class_load_start_time, k, loader_data);
}
assert(host_klass != NULL || NULL == cp_patches,
"cp_patches only found with host_klass");
@ -1641,7 +1634,7 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) {
JvmtiExport::post_class_load((JavaThread *) THREAD, k());
}
class_define_event(k);
class_define_event(k, loader_data);
}
// Support parallel classloading

View File

@ -62,18 +62,12 @@ void MetaspaceTracer::send_allocation_failure_event(ClassLoaderData *cld,
Metaspace::MetadataType mdtype) const {
E event;
if (event.should_commit()) {
event.set_classLoader(cld);
if (cld->is_anonymous()) {
event.set_classLoader(NULL);
event.set_anonymousClassLoader(true);
} else {
if (cld->is_the_null_class_loader_data()) {
event.set_classLoader((Klass*) NULL);
} else {
event.set_classLoader(cld->class_loader()->klass());
}
event.set_anonymousClassLoader(false);
}
event.set_size(word_size * BytesPerWord);
event.set_metadataType((u1) mdtype);
event.set_metaspaceObjectType((u1) objtype);

View File

@ -90,7 +90,7 @@ ArrayKlass::ArrayKlass(Symbol* name) :
set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
set_layout_helper(Klass::_lh_neutral_value);
set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
TRACE_INIT_KLASS_ID(this);
TRACE_INIT_ID(this);
}

View File

@ -488,7 +488,7 @@ void Klass::oops_do(OopClosure* cl) {
void Klass::remove_unshareable_info() {
assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
TRACE_REMOVE_KLASS_ID(this);
TRACE_REMOVE_ID(this);
set_subklass(NULL);
set_next_sibling(NULL);
@ -501,7 +501,7 @@ void Klass::remove_unshareable_info() {
}
void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
TRACE_RESTORE_KLASS_ID(this);
TRACE_RESTORE_ID(this);
// If an exception happened during CDS restore, some of these fields may already be
// set. We leave the class on the CLD list, even if incomplete so that we don't

View File

@ -31,13 +31,9 @@ typedef u8 traceid;
#define EVENT_THREAD_DESTRUCT(thread)
#define TRACE_KLASS_CREATION(k, p, t)
#define TRACE_INIT_KLASS_ID(k)
#define TRACE_REMOVE_KLASS_ID(k)
#define TRACE_RESTORE_KLASS_ID(k)
#define TRACE_INIT_MODULE_ID(m)
#define TRACE_INIT_PACKAGE_ID(p)
#define TRACE_INIT_THREAD_ID(td)
#define TRACE_INIT_ID(k)
#define TRACE_REMOVE_ID(k)
#define TRACE_RESTORE_ID(k)
#define TRACE_DATA TraceThreadData
#define THREAD_TRACE_ID(thread) ((traceid)thread->osthread()->thread_id())

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016, 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
@ -27,6 +27,8 @@
#include "utilities/macros.hpp"
#if INCLUDE_TRACE
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/klass.hpp"
#include "oops/method.hpp"
@ -101,6 +103,33 @@ class TraceStream : public StackObj {
_st.print("%s = %s", label, description);
}
void print_val(const char* label, const ClassLoaderData* const cld) {
ResourceMark rm;
if (cld == NULL || cld->is_anonymous()) {
_st.print("%s = NULL", label);
return;
}
const oop class_loader_oop = cld->class_loader();
if (class_loader_oop == NULL) {
_st.print("%s = NULL", label);
return;
}
const char* class_loader_name = "NULL";
const char* klass_name = "NULL";
const oop class_loader_name_oop =
java_lang_ClassLoader::name(class_loader_oop);
if (class_loader_name_oop != NULL) {
class_loader_name =
java_lang_String::as_utf8_string(class_loader_name_oop);
}
const Klass* const k = class_loader_oop->klass();
const Symbol* klass_name_sym = k->name();
if (klass_name_sym != NULL) {
klass_name = klass_name_sym->as_C_string();
}
_st.print("%s = name=%s class=%s", label, class_loader_name, klass_name);
}
void print_val(const char* label, const char* val) {
_st.print("%s = '%s'", label, val);
}

View File

@ -113,20 +113,20 @@ Declares a structure type that can be used in other events.
<event id="ClassLoad" path="vm/class/load" label="Class Load"
has_thread="true" has_stacktrace="true" is_instant="false">
<value type="CLASS" field="loadedClass" label="Loaded Class"/>
<value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
<value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
<value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
<value type="CLASSLOADER" field="initiatingClassLoader" label="Initiating Class Loader"/>
</event>
<event id="ClassDefine" path="vm/class/define" label="Class Define"
has_thread="true" has_stacktrace="true" is_instant="true">
<value type="CLASS" field="definedClass" label="Defined Class"/>
<value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
<value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
</event>
<event id="ClassUnload" path="vm/class/unload" label="Class Unload"
has_thread="true" is_instant="true">
<value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
<value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
<value type="CLASSLOADER" field="definingClassLoader" label="Defining Class Loader"/>
</event>
<event id="IntFlagChanged" path="vm/flag/int_changed" label="Int Flag Changed"
@ -229,7 +229,7 @@ Declares a structure type that can be used in other events.
</event>
<event id="MetaspaceAllocationFailure" path="vm/gc/metaspace/allocation_failure" label="Metaspace Allocation Failure" is_instant="true" has_stacktrace="true">
<value type="CLASS" field="classLoader" label="Class Loader" />
<value type="CLASSLOADER" field="classLoader" label="Class Loader" />
<value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
<value type="BYTES64" field="size" label="Size" />
<value type="METADATATYPE" field="metadataType" label="Metadata Type" />
@ -237,7 +237,7 @@ Declares a structure type that can be used in other events.
</event>
<event id="MetaspaceOOM" path="vm/gc/metaspace/out_of_memory" label="Metaspace Out of Memory" is_instant="true" has_stacktrace="true">
<value type="CLASS" field="classLoader" label="Class Loader" />
<value type="CLASSLOADER" field="classLoader" label="Class Loader" />
<value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
<value type="BYTES64" field="size" label="Size" />
<value type="METADATATYPE" field="metadataType" label="Metadata Type" />

View File

@ -68,21 +68,27 @@ Now we can use the content + data type in declaring event fields.
<value type="THREADGROUP" field="group" label="Java Thread Group"/>
</content_type>
<content_type id="ThreadGroup" hr_name="Thread group"
<content_type id="ThreadGroup" hr_name="Thread Group"
type="U8" jvm_type="THREADGROUP">
<value type="THREADGROUP" field="parent" label="Parent"/>
<value type="STRING" field="name" label="Name"/>
</content_type>
<content_type id="Class" hr_name="Java class"
<content_type id="Class" hr_name="Java Class"
type="U8" builtin_type="CLASS">
<value type="CLASS" field="classLoaderType" label="Class Loader"/>
<value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
<value type="SYMBOL" field="name" label="Name"/>
<value type="PACKAGE" field="package" label="Package"/>
<value type="INTEGER" field="modifiers" label="Access Modifiers"/>
</content_type>
<content_type id="Method" hr_name="Java method"
<content_type id="ClassLoader" hr_name="Java Class Loader"
type="U8" jvm_type="CLASSLOADER">
<value type="CLASS" field="type" label="Type"/>
<value type="SYMBOL" field="name" label="Name"/>
</content_type>
<content_type id="Method" hr_name="Java Method"
type="U8" jvm_type="METHOD">
<value type="CLASS" field="type" label="Type"/>
<value type="SYMBOL" field="name" label="Name"/>
@ -126,7 +132,7 @@ Now we can use the content + data type in declaring event fields.
<value type="STRING" field="type" label="Type" />
</content_type>
<content_type id="GCThresholdUpdater" hr_name="GC Treshold Updater"
<content_type id="GCThresholdUpdater" hr_name="GC Threshold Updater"
type="U8" jvm_type="GCTHRESHOLDUPDATER">
<value type="STRING" field="updater" label="Updater" />
</content_type>
@ -146,7 +152,7 @@ Now we can use the content + data type in declaring event fields.
<value type="STRING" field="type" label="Type" />
</content_type>
<content_type id="NarrowOopMode" hr_name="Narrow oop Mode"
<content_type id="NarrowOopMode" hr_name="Narrow Oop Mode"
type="U8" jvm_type="NARROWOOPMODE">
<value type="STRING" field="mode" label="Mode" />
</content_type>
@ -181,7 +187,7 @@ Now we can use the content + data type in declaring event fields.
<value type="SYMBOL" field="name" label="Name"/>
<value type="SYMBOL" field="version" label="Version"/>
<value type="SYMBOL" field="location" label="Location"/>
<value type="CLASS" field="classLoader" label="Class Loader"/>
<value type="CLASSLOADER" field="classLoader" label="Class Loader"/>
</content_type>
<content_type id="Package" hr_name="Package"
@ -303,6 +309,9 @@ Now we can use the content + data type in declaring event fields.
<primary_type symbol="CLASS" datatype="U8" contenttype="CLASS"
type="const Klass*" sizeop="sizeof(u8)"/>
<primary_type symbol="CLASSLOADER" datatype="U8" contenttype="CLASSLOADER"
type="const ClassLoaderData*" sizeop="sizeof(u8)"/>
<primary_type symbol="MODULE" datatype="U8" contenttype="MODULE"
type="const ModuleEntry*" sizeop="sizeof(u8)"/>