提交 0bb1ab9e 编写于 作者: D Denghui Dong 提交者: D-D-H

Revert "Revert "[JFR] add support for opto object allocations sampling""

This reverts commit 6585eb9c.
上级 7796cbc3
......@@ -468,6 +468,9 @@ arguments.obj: $(WorkSpace)\src\share\vm\runtime\arguments.cpp
{$(COMMONSRC)\share\vm\jfr\writers}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
{$(COMMONSRC)\share\vm\jfr\objectprofiler}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
default::
_build_pch_file.obj:
......
......@@ -25,14 +25,23 @@
#ifndef SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP
#define SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP
#include "memory/allocation.hpp"
#include "gc_implementation/shared/gcId.hpp"
#include "runtime/handles.hpp"
#include "utilities/globalDefinitions.hpp"
class AllocTracer : AllStatic {
private:
static void send_opto_array_allocation_event(KlassHandle klass, oop obj,size_t alloc_size, Thread* thread);
static void send_opto_instance_allocation_event(KlassHandle klass, oop obj, Thread* thread);
public:
static void send_allocation_outside_tlab_event(KlassHandle klass, HeapWord* obj, size_t alloc_size, Thread* thread);
static void send_allocation_in_new_tlab_event(KlassHandle klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, Thread* thread);
static void send_allocation_requiring_gc_event(size_t size, const GCId& gcId);
static void opto_slow_allocation_enter(bool is_array, Thread* thread);
static void opto_slow_allocation_leave(bool is_array, Thread* thread);
static void send_slow_allocation_event(KlassHandle klass, oop obj,size_t alloc_size, Thread* thread);
static void send_opto_fast_allocation_event(KlassHandle klass, oop obj, size_t alloc_size, Thread* thread);
};
#endif /* SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP */
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*
*/
#ifndef SHARE_VM_GC_INTERFACE_ALLOCTRACER_INLINE_HPP
#define SHARE_VM_GC_INTERFACE_ALLOCTRACER_INLINE_HPP
#include "gc_implementation/shared/gcId.hpp"
#include "jfr/jfrEvents.hpp"
#include "runtime/handles.hpp"
#include "utilities/globalDefinitions.hpp"
#include "gc_interface/allocTracer.hpp"
#if INCLUDE_JFR
#include "jfr/recorder/service/jfrOptionSet.hpp"
#include "jfr/objectprofiler/objectProfiler.hpp"
#endif // INCLUDE_JFR
inline void AllocTracer::opto_slow_allocation_enter(bool is_array, Thread* thread) {
#if INCLUDE_JFR
if (JfrOptionSet::sample_object_allocations() &&
ObjectProfiler::enabled()) {
assert(thread != NULL, "Invariant");
assert(thread->is_Java_thread(), "Invariant");
thread->jfr_thread_local()->incr_alloc_count(1);
if (is_array) {
thread->jfr_thread_local()->set_cached_event_id(JfrOptoArrayObjectAllocationEvent);
} else {
thread->jfr_thread_local()->set_cached_event_id(JfrOptoInstanceObjectAllocationEvent);
}
}
#endif // INCLUDE_JFR
}
inline void AllocTracer::opto_slow_allocation_leave(bool is_array, Thread* thread) {
#if INCLUDE_JFR
#ifndef PRODUCT
if (JfrOptionSet::sample_object_allocations()) {
JfrThreadLocal* jfr_thread_local = thread->jfr_thread_local();
assert(!jfr_thread_local->has_cached_event_id(), "Invariant");
assert(jfr_thread_local->alloc_count_until_sample() >= jfr_thread_local->alloc_count(), "Invariant");
}
#endif
#endif // INCLUDE_JFR
}
inline void AllocTracer::send_opto_array_allocation_event(KlassHandle klass, oop obj, size_t alloc_size, Thread* thread) {
EventOptoArrayObjectAllocation event;
if (event.should_commit()) {
event.set_objectClass(klass());
event.set_address(cast_from_oop<u8>(obj));
event.set_allocationSize(alloc_size);
event.commit();
}
}
inline void AllocTracer::send_opto_instance_allocation_event(KlassHandle klass, oop obj, Thread* thread) {
EventOptoInstanceObjectAllocation event;
if (event.should_commit()) {
event.set_objectClass(klass());
event.set_address(cast_from_oop<u8>(obj));
event.commit();
}
}
inline void AllocTracer::send_slow_allocation_event(KlassHandle klass, oop obj, size_t alloc_size, Thread* thread) {
#if INCLUDE_JFR
if (JfrOptionSet::sample_object_allocations()) {
assert(thread != NULL, "Illegal parameter: thread is NULL");
assert(thread == Thread::current(), "Invariant");
if (thread->jfr_thread_local()->has_cached_event_id()) {
assert(thread->is_Java_thread(), "Only allow to be called from java thread");
jlong alloc_count = thread->jfr_thread_local()->alloc_count();
jlong alloc_count_until_sample = thread->jfr_thread_local()->alloc_count_until_sample();
assert(alloc_count > 0 || alloc_count <= alloc_count_until_sample, "Invariant");
if (alloc_count == alloc_count_until_sample) {
JfrEventId event_id = thread->jfr_thread_local()->cached_event_id();
if (event_id ==JfrOptoArrayObjectAllocationEvent) {
send_opto_array_allocation_event(klass, obj, alloc_size, thread);
} else if(event_id == JfrOptoInstanceObjectAllocationEvent) {
send_opto_instance_allocation_event(klass, obj, thread);
} else {
ShouldNotReachHere();
}
jlong interval = JfrOptionSet::object_allocations_sampling_interval();
thread->jfr_thread_local()->incr_alloc_count_until_sample(interval);
}
thread->jfr_thread_local()->clear_cached_event_id();
}
}
#endif // INCLUDE_JFR
}
inline void AllocTracer::send_opto_fast_allocation_event(KlassHandle klass, oop obj, size_t alloc_size, Thread* thread) {
#if INCLUDE_JFR
assert(JfrOptionSet::sample_object_allocations(), "Invariant");
assert(thread != NULL, "Invariant");
assert(thread->is_Java_thread(), "Invariant");
assert(!thread->jfr_thread_local()->has_cached_event_id(), "Invariant");
Klass* k = klass();
if (k->oop_is_array()) {
send_opto_array_allocation_event(klass, obj, alloc_size, thread);
} else {
send_opto_instance_allocation_event(klass, obj, thread);
}
jlong interval = JfrOptionSet::object_allocations_sampling_interval();
thread->jfr_thread_local()->incr_alloc_count_until_sample(interval);
#endif // INCLUDE_JFR
}
#endif /* SHARE_VM_GC_INTERFACE_ALLOCTRACER_INLINE_HPP */
......@@ -26,6 +26,7 @@
#define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP
#include "gc_interface/gcCause.hpp"
#include "gc_interface/allocTracer.hpp"
#include "gc_implementation/shared/gcWhen.hpp"
#include "memory/allocation.hpp"
#include "memory/barrierSet.hpp"
......@@ -323,6 +324,15 @@ class CollectedHeap : public CHeapObj<mtInternal> {
inline static void check_array_size(int size, int length, TRAPS);
public:
// Implicit Jfr inline methods.
static void trace_slow_allocation(KlassHandle klass, oop obj, size_t alloc_size, Thread* thread) {
AllocTracer::send_slow_allocation_event(klass, obj, alloc_size, thread);
}
static void trace_allocation_outside_tlab(KlassHandle klass, HeapWord* obj, size_t alloc_size, Thread* thread) {
AllocTracer::send_allocation_outside_tlab_event(klass, obj, alloc_size, thread);
}
inline static void post_allocation_install_obj_klass(KlassHandle klass,
oop obj);
......
......@@ -25,7 +25,6 @@
#ifndef SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP
#define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP
#include "gc_interface/allocTracer.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "memory/threadLocalAllocBuffer.inline.hpp"
#include "memory/universe.hpp"
......@@ -69,7 +68,7 @@ void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
"missing klass");
}
// Support for jvmti and dtrace
// Support for jvmti, jfr and dtrace
inline void post_allocation_notify(KlassHandle klass, oop obj, int size) {
// support low memory notifications (no-op if not enabled)
LowMemoryDetector::detect_low_memory_for_collected_pools();
......@@ -83,6 +82,9 @@ inline void post_allocation_notify(KlassHandle klass, oop obj, int size) {
SharedRuntime::dtrace_object_alloc(obj, size);
}
}
// support for jfr
CollectedHeap::trace_slow_allocation(klass, obj, size * HeapWordSize, Thread::current());
}
void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
......@@ -91,7 +93,7 @@ void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
post_allocation_setup_common(klass, obj);
assert(Universe::is_bootstrapping() ||
!((oop)obj)->is_array(), "must not be an array");
// notify jvmti and dtrace
// notify jvmti, jfr and dtrace
post_allocation_notify(klass, (oop)obj, size);
}
......@@ -106,7 +108,7 @@ void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
post_allocation_setup_common(klass, obj);
oop new_obj = (oop)obj;
assert(new_obj->is_array(), "must be an array");
// notify jvmti and dtrace (must be after length is set for dtrace)
// notify jvmti, jfr and dtrace (must be after length is set for dtrace)
post_allocation_notify(klass, new_obj, new_obj->size());
}
......@@ -140,7 +142,7 @@ HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t si
"Unexpected exception, will result in uninitialized storage");
THREAD->incr_allocated_bytes(size * HeapWordSize);
AllocTracer::send_allocation_outside_tlab_event(klass, result, size * HeapWordSize, Thread::current());
CollectedHeap::trace_allocation_outside_tlab(klass, result, size * HeapWordSize, THREAD);
return result;
}
......
......@@ -544,6 +544,7 @@ void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
bool heap) : DCmdWithParser(output, heap),
_on_vm_start(false),
_repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
_dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
_stack_depth("stackdepth", "Stack Depth", "JULONG", false, "64"),
......@@ -552,7 +553,9 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out
_thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "MEMORY SIZE", false, "8k"),
_memory_size("memorysize", "Overall memory size, ", "MEMORY SIZE", false, "10m"),
_max_chunk_size("maxchunksize", "Size of an individual disk chunk", "MEMORY SIZE", false, "12m"),
_sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true") {
_sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true"),
_sample_object_allocations("sampleobjectallocations","object allocations sampling enable / disable", "BOOLEAN", false, "false"),
_object_allocations_sampling_interval("objectallocationssamplinginterval", "object allocations sampling interval", "JLONG", false, "1024") {
_dcmdparser.add_dcmd_option(&_repository_path);
_dcmdparser.add_dcmd_option(&_dump_path);
_dcmdparser.add_dcmd_option(&_stack_depth);
......@@ -562,6 +565,8 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out
_dcmdparser.add_dcmd_option(&_memory_size);
_dcmdparser.add_dcmd_option(&_max_chunk_size);
_dcmdparser.add_dcmd_option(&_sample_threads);
_dcmdparser.add_dcmd_option(&_sample_object_allocations);
_dcmdparser.add_dcmd_option(&_object_allocations_sampling_interval);
};
int JfrConfigureFlightRecorderDCmd::num_arguments() {
......@@ -592,6 +597,8 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
Handle h_dcmd_instance(THREAD, dcmd);
assert(h_dcmd_instance.not_null(), "invariant");
jobject on_vm_start = JfrJavaSupport::new_java_lang_Boolean(_on_vm_start, CHECK);
jstring repository_path = NULL;
if (_repository_path.is_set() && _repository_path.value() != NULL) {
repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK);
......@@ -637,16 +644,27 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK);
}
jobject sample_object_allocations = NULL;
if (_sample_object_allocations.is_set()) {
sample_object_allocations = JfrJavaSupport::new_java_lang_Boolean(_sample_object_allocations.value(), CHECK);
}
jobject object_allocations_sampling_interval = NULL;
if (_object_allocations_sampling_interval.is_set()) {
object_allocations_sampling_interval = JfrJavaSupport::new_java_lang_Long(_object_allocations_sampling_interval.value(), CHECK);
}
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
static const char method[] = "execute";
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
static const char signature[] = "(Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
"Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
"Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Long;)Ljava/lang/String;";
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
execute_args.set_receiver(h_dcmd_instance);
// params
execute_args.push_jobject(on_vm_start);
execute_args.push_jobject(repository_path);
execute_args.push_jobject(dump_path);
execute_args.push_jobject(stack_depth);
......@@ -656,6 +674,8 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
execute_args.push_jobject(memory_size);
execute_args.push_jobject(max_chunk_size);
execute_args.push_jobject(sample_threads);
execute_args.push_jobject(sample_object_allocations);
execute_args.push_jobject(object_allocations_sampling_interval);
JfrJavaSupport::call_virtual(&execute_args, THREAD);
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
......
......@@ -140,6 +140,11 @@ class JfrRuntimeOptions;
class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
friend class JfrOptionSet;
private:
bool _on_vm_start;
void set_on_vm_start(bool on_vm_start) {
_on_vm_start = on_vm_start;
}
protected:
DCmdArgument<char*> _repository_path;
DCmdArgument<char*> _dump_path;
......@@ -150,6 +155,8 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
DCmdArgument<MemorySizeArgument> _memory_size;
DCmdArgument<MemorySizeArgument> _max_chunk_size;
DCmdArgument<bool> _sample_threads;
DCmdArgument<bool> _sample_object_allocations;
DCmdArgument<jlong> _object_allocations_sampling_interval;
public:
JfrConfigureFlightRecorderDCmd(outputStream* output, bool heap);
......@@ -168,6 +175,9 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
bool on_vm_start() const {
return _on_vm_start;
}
};
class JfrUnlockCommercialFeaturesDCmd : public DCmd {
......
......@@ -44,6 +44,7 @@
#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/objectprofiler/objectProfiler.hpp"
#include "jfr/utilities/jfrJavaLog.hpp"
#include "jfr/utilities/jfrTimeConverter.hpp"
#include "jfr/utilities/jfrTime.hpp"
......@@ -110,6 +111,15 @@ NO_TRANSITION(void, jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_i
LeakProfiler::stop();
}
}
if (EventOptoInstanceObjectAllocation::eventId == event_type_id ||
EventOptoArrayObjectAllocation::eventId == event_type_id) {
ThreadInVMfromNative transition(JavaThread::thread_from_jni_environment(env));
if (JNI_TRUE == enabled) {
ObjectProfiler::start(event_type_id);
} else {
ObjectProfiler::stop(event_type_id);
}
}
NO_TRANSITION_END
NO_TRANSITION(void, jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong threshold))
......@@ -144,6 +154,14 @@ NO_TRANSITION(void, jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size))
JfrOptionSet::set_memory_size(size);
NO_TRANSITION_END
NO_TRANSITION(void, jfr_set_sample_object_allocations(JNIEnv* env, jobject jvm, jboolean sampleAllocations))
JfrOptionSet::set_sample_object_allocations(sampleAllocations);
NO_TRANSITION_END
NO_TRANSITION(void, jfr_set_object_allocations_sampling_interval(JNIEnv* env, jobject jvm, jlong interval))
JfrOptionSet::set_object_allocations_sampling_interval(interval);
NO_TRANSITION_END
NO_TRANSITION(jboolean, jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks))
return JfrEventSetting::set_threshold(event_type_id, thresholdTicks) ? JNI_TRUE : JNI_FALSE;
NO_TRANSITION_END
......@@ -233,7 +251,7 @@ JVM_ENTRY_NO_ENV(jlong, jfr_class_id(JNIEnv* env, jclass jvm, jclass jc))
JVM_END
JVM_ENTRY_NO_ENV(jlong, jfr_stacktrace_id(JNIEnv* env, jobject jvm, jint skip))
return JfrStackTraceRepository::record(thread, skip);
return JfrStackTraceRepository::record(thread, skip, WALK_BY_DEFAULT);
JVM_END
JVM_ENTRY_NO_ENV(void, jfr_log(JNIEnv* env, jobject jvm, jint tag_set, jint level, jstring message))
......
......@@ -93,6 +93,10 @@ void JNICALL jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size);
jboolean JNICALL jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks);
void JNICALL jfr_set_sample_object_allocations(JNIEnv* env, jobject jvm, jboolean sampleAllocations);
void JNICALL jfr_set_object_allocations_sampling_interval(JNIEnv* env, jobject jvm, jlong interval);
void JNICALL jfr_store_metadata_descriptor(JNIEnv* env, jobject jvm, jbyteArray descriptor);
jlong JNICALL jfr_id_for_thread(JNIEnv* env, jobject jvm, jobject t);
......
......@@ -62,6 +62,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
(char*)"setThreadBufferSize", (char*)"(J)V", (void*)jfr_set_thread_buffer_size,
(char*)"setMemorySize", (char*)"(J)V", (void*)jfr_set_memory_size,
(char*)"setThreshold", (char*)"(JJ)Z", (void*)jfr_set_threshold,
(char*)"setSampleObjectAllocations", (char*)"(Z)V",(void*)jfr_set_sample_object_allocations,
(char*)"setObjectAllocationsSamplingInterval", (char*)"(J)V",(void*)jfr_set_object_allocations_sampling_interval,
(char*)"storeMetadataDescriptor", (char*)"([B)V", (void*)jfr_store_metadata_descriptor,
(char*)"getAllowedToDoEventRetransforms", (char*)"()Z", (void*)jfr_allow_event_retransforms,
(char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available,
......
......@@ -122,7 +122,7 @@ void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* threa
assert(stacktrace != NULL, "invariant");
assert(thread != NULL, "invariant");
if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0);
JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0, WALK_BY_DEFAULT);
}
}
......
......@@ -575,6 +575,17 @@
<Field type="ulong" contentType="bytes" name="allocationSize" label="Allocation Size" />
</Event>
<Event name="OptoInstanceObjectAllocation" category="Java Application" label="Opto instance object allocation" description="Allocation by Opto jitted method" thread="true" stackTrace="true" startTime="false">
<Field type="Class" name="objectClass" label="Object Class" description="Class of allocated instance object"/>
<Field type="ulong" contentType="address" name="address" label="Opto Instance Object Allocation Address" description="Address of allocated instance object"/>
</Event>
<Event name="OptoArrayObjectAllocation" category="Java Application" label="Opto array object allocation" description="Array Allocation by Opto jitted method" thread="true" stackTrace="true" startTime="false">
<Field type="Class" name="objectClass" label="Object Class" description="Class of allocated array object"/>
<Field type="ulong" contentType="address" name="address" label="Opto Array Object Allocation Address" description="Address of allocated instance object"/>
<Field type="ulong" contentType="bytes" name="allocationSize" label="Object Size" description="The Array Object Size" />
</Event>
<Event name="OldObjectSample" category="Java Virtual Machine, Profiling" label="Old Object Sample" description="A potential memory leak" stackTrace="true" thread="true"
startTime="false" cutoff="true">
<Field type="Ticks" name="allocationTime" label="Allocation Time" />
......@@ -949,6 +960,7 @@
<Field type="Symbol" name="name" label="Name" />
<Field type="Package" name="package" label="Package" />
<Field type="int" name="modifiers" label="Access Modifiers" />
<Field type="int" name="objectSize" label="Object Size" />
</Type>
<Type name="ClassLoader" label="Java Class Loader">
......
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*
*/
#include "precompiled.hpp"
#include "runtime/vmThread.hpp"
#include "jfr/objectprofiler/objectProfiler.hpp"
#include "jfr/utilities/jfrTryLock.hpp"
#include "jfrfiles/jfrEventClasses.hpp"
volatile jint ObjectProfiler::_enabled = JNI_FALSE;
bool ObjectProfiler::_sample_instance_obj_alloc = false;
bool ObjectProfiler::_sample_array_obj_alloc = false;
#ifndef PRODUCT
volatile int ObjectProfiler::_try_lock = 0;
#endif
void ObjectProfiler::start(jlong event_id) {
#ifndef PRODUCT
JfrTryLock try_lock(&_try_lock);
assert(try_lock.has_lock(), "Not allow contention");
#endif
if (EventOptoInstanceObjectAllocation::eventId == event_id) {
if (!_sample_instance_obj_alloc) {
_sample_instance_obj_alloc = true;
}
} else if (EventOptoArrayObjectAllocation::eventId == event_id) {
if (!_sample_array_obj_alloc) {
_sample_array_obj_alloc = true;
}
} else {
ShouldNotReachHere();
}
if (enabled() == JNI_TRUE) {
return;
}
OrderAccess::release_store((volatile jint*)&_enabled, JNI_TRUE);
}
void ObjectProfiler::stop(jlong event_id) {
#ifndef PRODUCT
JfrTryLock try_lock(&_try_lock);
assert(try_lock.has_lock(), "Not allow contention");
#endif
if (enabled() == JNI_FALSE) {
assert(!_sample_array_obj_alloc && !_sample_instance_obj_alloc, "Invariant");
return;
}
if (EventOptoInstanceObjectAllocation::eventId == event_id) {
if (_sample_instance_obj_alloc) {
_sample_instance_obj_alloc = false;
}
} else if (EventOptoArrayObjectAllocation::eventId == event_id) {
if (_sample_array_obj_alloc) {
_sample_array_obj_alloc = false;
}
} else {
ShouldNotReachHere();
}
bool should_enable = _sample_array_obj_alloc || _sample_instance_obj_alloc;
if (should_enable) {
return;
}
OrderAccess::release_store(&_enabled, JNI_FALSE);
}
jint ObjectProfiler::enabled() {
return OrderAccess::load_acquire((volatile jint*)&_enabled);
}
void* ObjectProfiler::enabled_flag_address() {
return (void*)&_enabled;
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*
*/
#ifndef SHARE_VM_JFR_OBJECTROFILER_OBJECTPROFILER_HPP
#define SHARE_VM_JFR_OBJECTROFILER_OBJECTPROFILER_HPP
#include "prims/jni.h"
class ObjectProfiler : public AllStatic {
private:
static volatile jint _enabled;
static bool _sample_instance_obj_alloc;
static bool _sample_array_obj_alloc;
#ifndef PRODUCT
static volatile int _try_lock;
#endif
public:
static void start(jlong event_id);
static void stop(jlong event_id);
static jint enabled();
static void* enabled_flag_address();
};
#endif // SHARE_VM_JFR_OBJECTROFILER_OBJECTPROFILER_HPP
......@@ -148,6 +148,16 @@ int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifact
writer->write((traceid)CREATE_SYMBOL_ID(symbol_id));
writer->write(pkg_id);
writer->write((s4)klass->access_flags().get_flags());
if (klass->oop_is_array()) {
// The object array size can not be determined statically from klass.
// It is determined by the elements length in object layout.
// So we put a place holder here to make the event parser ignore it.
writer->write((s4)ARRAY_OBJECT_SIZE_PLACE_HOLDER);
} else {
assert(klass->oop_is_instance(), "invariant");
jint instanceSize = ((InstanceKlass*) klass)->size_helper() * HeapWordSize;
writer->write((s4)instanceSize);
}
return 1;
}
......
......@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
JfrNativeSettings JfrEventSetting::_jvm_event_settings;
......@@ -53,6 +54,14 @@ void JfrEventSetting::set_enabled(jlong id, bool enabled) {
setting(event_id).enabled = enabled;
}
StackWalkMode JfrEventSetting::stack_walk_mode(JfrEventId event_id) {
if (event_id == JfrOptoArrayObjectAllocationEvent ||
event_id == JfrOptoInstanceObjectAllocationEvent) {
return WALK_BY_CURRENT_FRAME;
}
return WALK_BY_DEFAULT;
}
#ifdef ASSERT
bool JfrEventSetting::bounds_check_event(jlong id) {
if ((unsigned)id < NUM_RESERVED_EVENTS || (unsigned)id >= MaxJfrEventId) {
......
......@@ -28,6 +28,7 @@
#include "jni.h"
#include "jfr/utilities/jfrAllocation.hpp"
#include "jfrfiles/jfrEventControl.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
//
// Native event settings as an associative array using the event id as key.
......@@ -46,6 +47,7 @@ class JfrEventSetting : AllStatic {
static jlong threshold(JfrEventId event_id);
static bool set_cutoff(jlong event_id, jlong cutoff_ticks);
static jlong cutoff(JfrEventId event_id);
static StackWalkMode stack_walk_mode(JfrEventId event_id);
DEBUG_ONLY(static bool bounds_check_event(jlong id);)
};
......
......@@ -26,6 +26,7 @@
#define SHARE_VM_JFR_RECORDER_SERVICE_JFREVENT_HPP
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/jfrEventSetting.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/utilities/jfrTime.hpp"
#include "jfr/utilities/jfrTypes.hpp"
......@@ -176,7 +177,7 @@ class JfrEvent {
if (tl->has_cached_stack_trace()) {
writer.write(tl->cached_stack_trace_id());
} else {
writer.write(JfrStackTraceRepository::record(event_thread));
writer.write(JfrStackTraceRepository::record(event_thread, 0, JfrEventSetting::stack_walk_mode(T::eventId)));
}
} else {
writer.write<traceid>(0);
......
......@@ -35,6 +35,7 @@
#include "services/diagnosticFramework.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/ostream.hpp"
#include "utilities/debug.hpp"
struct ObsoleteOption {
const char* name;
......@@ -162,6 +163,22 @@ bool JfrOptionSet::allow_event_retransforms() {
return allow_retransforms() && (DumpSharedSpaces || can_retransform());
}
bool JfrOptionSet::sample_object_allocations() {
return _sample_object_allocations == JNI_TRUE;
}
void JfrOptionSet::set_sample_object_allocations(jboolean value) {
_sample_object_allocations = value;
}
jlong JfrOptionSet::object_allocations_sampling_interval() {
return _object_allocations_sampling_interval;
}
void JfrOptionSet::set_object_allocations_sampling_interval(jlong value) {
_object_allocations_sampling_interval = value;
}
// default options for the dcmd parser
const char* const default_repository = NULL;
const char* const default_global_buffer_size = "512k";
......@@ -174,6 +191,9 @@ const char* const default_stack_depth = "64";
const char* const default_retransform = "true";
const char* const default_old_object_queue_size = "256";
DEBUG_ONLY(const char* const default_sample_protection = "false";)
const char* const default_sample_object_allocations = "false";
// the unit of this value is not time but quantity
const char* const default_object_allocations_sampling_interval = "1024";
// statics
static DCmdArgument<char*> _dcmd_repository(
......@@ -255,6 +275,20 @@ static DCmdArgument<bool> _dcmd_retransform(
true,
default_retransform);
static DCmdArgument<bool> _dcmd_sampleobjectallocations(
"sampleobjectallocations",
"If object allocations should be sampled (by default false)",
"BOOLEAN",
false,
default_sample_object_allocations);
static DCmdArgument<jlong> _dcmd_objectallocationssamplinginterval(
"objectallocationssamplinginterval",
"object allocations sampling interval (by default 1024)",
"JLONG",
false,
default_object_allocations_sampling_interval);
static DCmdParser _parser;
static void register_parser_options() {
......@@ -269,6 +303,8 @@ static void register_parser_options() {
_parser.add_dcmd_option(&_dcmd_retransform);
_parser.add_dcmd_option(&_dcmd_old_object_queue_size);
DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
_parser.add_dcmd_option(&_dcmd_sampleobjectallocations);
_parser.add_dcmd_option(&_dcmd_objectallocationssamplinginterval);
}
static bool parse_flight_recorder_options_internal(TRAPS) {
......@@ -314,6 +350,9 @@ jboolean JfrOptionSet::_sample_protection = JNI_FALSE;
#else
jboolean JfrOptionSet::_sample_protection = JNI_TRUE;
#endif
volatile jboolean JfrOptionSet::_sample_object_allocations = JNI_FALSE;
// the unit of this value is not time but quantity
volatile jlong JfrOptionSet::_object_allocations_sampling_interval = 1024;
bool JfrOptionSet::initialize(Thread* thread) {
register_parser_options();
......@@ -335,6 +374,7 @@ bool JfrOptionSet::configure(TRAPS) {
bufferedStream st;
// delegate to DCmd execution
JfrConfigureFlightRecorderDCmd configure(&st, false);
configure.set_on_vm_start(true);
configure._repository_path.set_is_set(_dcmd_repository.is_set());
char* repo = _dcmd_repository.value();
if (repo != NULL) {
......@@ -368,6 +408,12 @@ bool JfrOptionSet::configure(TRAPS) {
configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
configure._sample_threads.set_value(_dcmd_sample_threads.value());
configure._sample_object_allocations.set_is_set(_dcmd_sampleobjectallocations.is_set());
configure._sample_object_allocations.set_value(_dcmd_sampleobjectallocations.value());
configure._object_allocations_sampling_interval.set_is_set(_dcmd_objectallocationssamplinginterval.is_set());
configure._object_allocations_sampling_interval.set_value(_dcmd_objectallocationssamplinginterval.value());
configure.execute(DCmd_Source_Internal, THREAD);
if (HAS_PENDING_EXCEPTION) {
......
......@@ -48,6 +48,8 @@ class JfrOptionSet : public AllStatic {
static jboolean _sample_threads;
static jboolean _retransform;
static jboolean _sample_protection;
static volatile jboolean _sample_object_allocations;
static volatile jlong _object_allocations_sampling_interval;
static bool initialize(Thread* thread);
static bool configure(TRAPS);
......@@ -77,6 +79,10 @@ class JfrOptionSet : public AllStatic {
static bool allow_event_retransforms();
static bool sample_protection();
DEBUG_ONLY(static void set_sample_protection(jboolean protection);)
static bool sample_object_allocations();
static void set_sample_object_allocations(jboolean value);
static jlong object_allocations_sampling_interval();
static void set_object_allocations_sampling_interval(jlong value);
static bool parse_flight_recorder_option(const JavaVMOption** option, char* delimiter);
static bool parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter);
......
......@@ -173,7 +173,7 @@ traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
return tid;
}
traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
traceid JfrStackTraceRepository::record(Thread* thread, int skip, StackWalkMode mode) {
assert(thread == Thread::current(), "invariant");
JfrThreadLocal* const tl = thread->jfr_thread_local();
assert(tl != NULL, "invariant");
......@@ -190,12 +190,12 @@ traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
}
assert(frames != NULL, "invariant");
assert(tl->stackframes() == frames, "invariant");
return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
return instance().record_for((JavaThread*)thread, skip, mode, frames, tl->stackdepth());
}
traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, StackWalkMode mode, JfrStackFrame *frames, u4 max_frames) {
JfrStackTrace stacktrace(frames, max_frames);
return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
return stacktrace.record_safe(thread, skip, false, mode) ? add(stacktrace) : 0;
}
traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
......@@ -205,7 +205,7 @@ traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread
return add(*stacktrace);
}
bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip, StackWalkMode mode) {
assert(thread == Thread::current(), "invariant");
assert(stacktrace != NULL, "invariant");
JfrThreadLocal* const tl = thread->jfr_thread_local();
......@@ -215,7 +215,7 @@ bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTr
stacktrace->set_hash(cached_stacktrace_hash);
return true;
}
return stacktrace->record_safe(thread, skip, true);
return stacktrace->record_safe(thread, skip, true, mode);
}
size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
......@@ -363,16 +363,45 @@ void JfrStackTrace::resolve_linenos() const {
_lineno = true;
}
bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp, StackWalkMode mode) {
assert(SafepointSynchronize::safepoint_safe(thread, thread->thread_state())
|| thread == Thread::current(), "Thread stack needs to be walkable");
bool success = false;
switch(mode) {
case WALK_BY_DEFAULT:
{
vframeStream vfs(thread);
success = fill_in(vfs, skip, leakp, mode);
break;
}
case WALK_BY_CURRENT_FRAME:
{
vframeStream vfs(thread, os::current_frame());
success = fill_in(vfs, skip, leakp, mode);
break;
}
default:
ShouldNotReachHere();
}
return success;
}
bool JfrStackTrace::fill_in(vframeStream& vfs, int skip, bool leakp, StackWalkMode mode) {
u4 count = 0;
_reached_root = true;
// Indicates whether the top frame is visited in this frames iteration.
// Top frame bci may be invalid and fill_in() will fix the top frame bci in a conservative way.
bool top_frame_visited = false;
for(int i = 0; i < skip; i++) {
if (vfs.at_end()) {
break;
}
// The top frame is in skip list.
// Mark top_frame_visited to avoid unnecessary top frame bci fixing.
if (!top_frame_visited) {
top_frame_visited = true;
}
vfs.next();
}
......@@ -387,8 +416,25 @@ bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* fals
int bci = 0;
if (method->is_native()) {
type = JfrStackFrame::FRAME_NATIVE;
// The top frame is in native.
// Mark top_frame_visited to avoid unnecessary top frame bci fixing.
if (!top_frame_visited) {
top_frame_visited = true;
}
} else {
bci = vfs.bci();
// Hit the top frame and fix bci here.
if (!top_frame_visited) {
if (mode == WALK_BY_CURRENT_FRAME) {
// Only fix opto fast path allocation.
// All fast path allocations do not have cached event id.
if (!vfs.thread_ref()->jfr_thread_local()->has_cached_event_id()) {
assert(vfs.thread_ref()->jfr_thread_local()->has_cached_top_frame_bci(), "Invariant");
bci = vfs.thread_ref()->jfr_thread_local()->cached_top_frame_bci();
}
}
top_frame_visited = true;
}
}
// Can we determine if it's inlined?
_hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
......
......@@ -33,6 +33,7 @@ class JavaThread;
class JfrCheckpointWriter;
class JfrChunkWriter;
class Method;
class vframeStream;
class JfrStackFrame {
private:
......@@ -61,6 +62,15 @@ class JfrStackFrame {
void resolve_lineno() const;
};
enum StackWalkMode {
// walk stack by vframeStream vfs(thread).
WALK_BY_DEFAULT = 0,
// walk stack by vframeStream vfs(thread, os::current_frame()).
// It is only used in JIT runtime leaf call. In JIT runtime leaf call,
// last_java_sp is not maintained and WALK_BY_DEFAULT can not walk stack.
WALK_BY_CURRENT_FRAME
};
class JfrStackTrace : public StackObj {
friend class JfrStackTraceRepository;
private:
......@@ -72,6 +82,7 @@ class JfrStackTrace : public StackObj {
bool _reached_root;
mutable bool _lineno;
bool fill_in(vframeStream& vfs, int skip, bool leakp, StackWalkMode mode);
public:
JfrStackTrace(JfrStackFrame* frames, u4 max_frames) : _frames(frames),
_id(0),
......@@ -81,7 +92,7 @@ class JfrStackTrace : public StackObj {
_max_frames(max_frames),
_lineno(false) {}
bool record_thread(JavaThread& thread, frame& frame);
bool record_safe(JavaThread* thread, int skip, bool leakp = false);
bool record_safe(JavaThread* thread, int skip, bool leakp, StackWalkMode stack_walk_mode);
void resolve_linenos() const;
void set_nr_of_frames(u4 nr_of_frames) { _nr_of_frames = nr_of_frames; }
void set_hash(unsigned int hash) { _hash = hash; }
......@@ -131,13 +142,13 @@ class JfrStackTraceRepository : public JfrCHeapObj {
traceid add_trace(const JfrStackTrace& stacktrace);
static traceid add(const JfrStackTrace* stacktrace, JavaThread* thread);
traceid record_for(JavaThread* thread, int skip, JfrStackFrame* frames, u4 max_frames);
traceid record_for(JavaThread* thread, int skip, StackWalkMode mode, JfrStackFrame* frames, u4 max_frames);
size_t write_impl(JfrChunkWriter& cw, bool clear);
const StackTrace* resolve_entry(unsigned int hash, traceid id) const;
static void write_metadata(JfrCheckpointWriter& cpw);
static bool fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip);
static bool fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip, StackWalkMode mode);
JfrStackTraceRepository();
static JfrStackTraceRepository* create();
......@@ -148,7 +159,7 @@ class JfrStackTraceRepository : public JfrCHeapObj {
public:
static traceid add(const JfrStackTrace& stacktrace);
static traceid record(Thread* thread, int skip = 0);
static traceid record(Thread* thread, int skip, StackWalkMode mode);
traceid write(JfrCheckpointWriter& cpw, traceid id, unsigned int hash);
size_t write(JfrChunkWriter& cw, bool clear);
size_t clear();
......
......@@ -70,12 +70,12 @@ void jfr_conditional_flush(JfrEventId id, size_t size, Thread* t) {
}
}
bool jfr_save_stacktrace(Thread* t) {
bool jfr_save_stacktrace(Thread* t, StackWalkMode mode) {
JfrThreadLocal* const tl = t->jfr_thread_local();
if (tl->has_cached_stack_trace()) {
return false; // no ownership
}
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t));
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t, 0, mode));
return true;
}
......
......@@ -27,6 +27,8 @@
#include "jfr/recorder/storage/jfrBuffer.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "jfr/recorder/jfrEventSetting.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "memory/allocation.hpp"
class Thread;
......@@ -43,7 +45,7 @@ class JfrFlush : public StackObj {
void jfr_conditional_flush(JfrEventId id, size_t size, Thread* t);
bool jfr_is_event_enabled(JfrEventId id);
bool jfr_has_stacktrace_enabled(JfrEventId id);
bool jfr_save_stacktrace(Thread* t);
bool jfr_save_stacktrace(Thread* t, StackWalkMode mode);
void jfr_clear_stacktrace(Thread* t);
template <typename Event>
......@@ -66,7 +68,7 @@ class JfrConditionalFlushWithStacktrace : public JfrConditionalFlush<Event> {
public:
JfrConditionalFlushWithStacktrace(Thread* t) : JfrConditionalFlush<Event>(t), _t(t), _owner(false) {
if (this->_enabled && Event::has_stacktrace() && jfr_has_stacktrace_enabled(Event::eventId)) {
_owner = jfr_save_stacktrace(t);
_owner = jfr_save_stacktrace(t, JfrEventSetting::stack_walk_mode(Event::eventId));
}
}
~JfrConditionalFlushWithStacktrace() {
......
......@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jfr/recorder/jfrEventSetting.inline.hpp"
#include "jfr/recorder/jfrEventSetting.hpp"
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
#include "jfr/support/jfrStackTraceMark.hpp"
#include "jfr/support/jfrThreadLocal.hpp"
......@@ -35,7 +36,7 @@ JfrStackTraceMark::JfrStackTraceMark() : _t(Thread::current()), _previous_id(0),
_previous_id = tl->cached_stack_trace_id();
_previous_hash = tl->cached_stack_trace_hash();
}
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(Thread::current()));
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(Thread::current(), 0, WALK_BY_DEFAULT));
}
JfrStackTraceMark::JfrStackTraceMark(Thread* t) : _t(t), _previous_id(0), _previous_hash(0) {
......@@ -44,7 +45,7 @@ JfrStackTraceMark::JfrStackTraceMark(Thread* t) : _t(t), _previous_id(0), _previ
_previous_id = tl->cached_stack_trace_id();
_previous_hash = tl->cached_stack_trace_hash();
}
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t));
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(t, 0, WALK_BY_DEFAULT));
}
JfrStackTraceMark::JfrStackTraceMark(JfrEventId eventId) : _t(NULL), _previous_id(0), _previous_hash(0) {
......@@ -55,7 +56,8 @@ JfrStackTraceMark::JfrStackTraceMark(JfrEventId eventId) : _t(NULL), _previous_i
_previous_id = tl->cached_stack_trace_id();
_previous_hash = tl->cached_stack_trace_hash();
}
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t));
StackWalkMode mode = JfrEventSetting::stack_walk_mode(eventId);
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t, 0, mode));
}
}
......@@ -67,7 +69,8 @@ JfrStackTraceMark::JfrStackTraceMark(JfrEventId eventId, Thread* t) : _t(NULL),
_previous_id = tl->cached_stack_trace_id();
_previous_hash = tl->cached_stack_trace_hash();
}
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t));
StackWalkMode mode = JfrEventSetting::stack_walk_mode(eventId);
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(_t, 0, mode));
}
}
......
......@@ -55,7 +55,11 @@ JfrThreadLocal::JfrThreadLocal() :
_stack_trace_hash(0),
_stackdepth(0),
_entering_suspend_flag(0),
_dead(false) {}
_dead(false),
_cached_top_frame_bci(max_jint),
_alloc_count(0),
_alloc_count_until_sample(1),
_cached_event_id(MaxJfrEventId) {}
u8 JfrThreadLocal::add_data_lost(u8 value) {
_data_lost += value;
......
......@@ -51,6 +51,27 @@ class JfrThreadLocal {
mutable u4 _stackdepth;
volatile jint _entering_suspend_flag;
bool _dead;
// Jfr callstack collection relies on vframeStream.
// But the bci of top frame can not be determined by vframeStream in some scenarios.
// For example, in the opto CallLeafNode runtime call of
// OptoRuntime::jfr_fast_object_alloc_C, the top frame bci
// returned by vframeStream is always invalid. This is largely due to the oopmap that
// is not correctly granted ( refer to PhaseMacroExpand::expand_allocate_common to get more details ).
// The opto fast path object allocation tracing occurs in the opto CallLeafNode,
// which has been broken by invalid top frame bci.
// To fix this, we get the top frame bci in opto compilation phase
// and pass it as parameter to runtime call. Our implementation will replace the invalid top
// frame bci with cached_top_frame_bci.
jint _cached_top_frame_bci;
jlong _alloc_count;
jlong _alloc_count_until_sample;
// This field is used to help to distinguish the object allocation request source.
// For example, for object allocation slow path, we trace it in CollectedHeap::obj_allocate.
// But in CollectedHeap::obj_allocate, it is impossible to determine where the allocation request
// is from, which could be from c1, opto, or even interpreter.
// We save this infomation in _event_id, which later can be retrieved in
// CollecetedHeap::obj_allocate to identify the real allocation request source.
JfrEventId _cached_event_id;
JfrBuffer* install_native_buffer() const;
JfrBuffer* install_java_buffer() const;
......@@ -207,6 +228,54 @@ class JfrThreadLocal {
return _dead;
}
void set_cached_top_frame_bci(jint bci) {
_cached_top_frame_bci = bci;
}
bool has_cached_top_frame_bci() const {
return _cached_top_frame_bci != max_jint;
}
jint cached_top_frame_bci() const {
return _cached_top_frame_bci;
}
void clear_cached_top_frame_bci() {
_cached_top_frame_bci = max_jint;
}
jlong alloc_count() const {
return _alloc_count;
}
void incr_alloc_count(jlong delta) {
_alloc_count += delta;
}
jlong alloc_count_until_sample() const {
return _alloc_count_until_sample;
}
void incr_alloc_count_until_sample(jlong delta) {
_alloc_count_until_sample += delta;
}
void set_cached_event_id(JfrEventId event_id) {
_cached_event_id = event_id;
}
JfrEventId cached_event_id() const {
return _cached_event_id;
}
bool has_cached_event_id() const {
return _cached_event_id != MaxJfrEventId;
}
void clear_cached_event_id() {
_cached_event_id = MaxJfrEventId;
}
bool has_thread_checkpoint() const;
void set_thread_checkpoint(const JfrCheckpointBlobHandle& handle);
const JfrCheckpointBlobHandle& thread_checkpoint() const;
......@@ -217,6 +286,9 @@ class JfrThreadLocal {
// Code generation
static ByteSize trace_id_offset();
static ByteSize java_event_writer_offset();
TRACE_DEFINE_THREAD_ALLOC_COUNT_UNTIL_SAMPLE_OFFSET;
TRACE_DEFINE_THREAD_ALLOC_COUNT_OFFSET;
};
#endif // SHARE_VM_JFR_SUPPORT_JFRTHREADLOCAL_HPP
......@@ -78,4 +78,24 @@ class JfrTraceFlag {
return _trace_flags.flags_addr(); \
}
#define ARRAY_OBJECT_SIZE_PLACE_HOLDER 0x1111baba
#define TRACE_OPTO_SLOW_ALLOCATION_ENTER(is_array, thread) \
AllocTracer::opto_slow_allocation_enter(is_array, thread)
#define TRACE_OPTO_SLOW_ALLOCATION_LEAVE(is_array, thread) \
AllocTracer::opto_slow_allocation_leave(is_array, thread)
#define TRACE_SLOW_ALLOCATION(klass, obj, alloc_size, thread) \
AllocTracer::send_slow_allocation_event(klass, obj, alloc_size, thread)
#define TRACE_DEFINE_THREAD_ALLOC_COUNT_OFFSET \
static ByteSize alloc_count_offset() { return in_ByteSize(offset_of(JfrThreadLocal, _alloc_count)); }
#define TRACE_THREAD_ALLOC_COUNT_OFFSET \
(JfrThreadLocal::alloc_count_offset() + Thread::jfr_thread_local_offset())
#define TRACE_DEFINE_THREAD_ALLOC_COUNT_UNTIL_SAMPLE_OFFSET \
static ByteSize alloc_count_until_sample_offset() { return in_ByteSize(offset_of(JfrThreadLocal, _alloc_count_until_sample)); }
#define TRACE_THREAD_ALLOC_COUNT_UNTIL_SAMPLE_OFFSET \
(JfrThreadLocal::alloc_count_until_sample_offset() + Thread::jfr_thread_local_offset())
#endif // SHARE_VM_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
......@@ -27,6 +27,7 @@
#include "libadt/vectset.hpp"
#include "opto/addnode.hpp"
#include "opto/callnode.hpp"
#include "opto/divnode.hpp"
#include "opto/cfgnode.hpp"
#include "opto/compile.hpp"
#include "opto/connode.hpp"
......@@ -41,6 +42,7 @@
#include "opto/subnode.hpp"
#include "opto/type.hpp"
#include "runtime/sharedRuntime.hpp"
#include "jfr/objectprofiler/objectProfiler.hpp"
//
......@@ -1087,15 +1089,21 @@ void PhaseMacroExpand::set_eden_pointers(Node* &eden_top_adr, Node* &eden_end_ad
}
}
Node* PhaseMacroExpand::make_load(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) {
Node* PhaseMacroExpand::load(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt, MemNode::MemOrd mo) {
Node* adr = basic_plus_adr(base, offset);
const TypePtr* adr_type = adr->bottom_type()->is_ptr();
Node* value = LoadNode::make(_igvn, ctl, mem, adr, adr_type, value_type, bt, MemNode::unordered);
Node* value = LoadNode::make(_igvn, ctl, mem, adr, adr_type, value_type, bt, mo);
transform_later(value);
return value;
}
Node* PhaseMacroExpand::make_load(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) {
return load(ctl, mem, base, offset, value_type, bt, MemNode::unordered);
}
Node* PhaseMacroExpand::make_load_acquire(Node* ctl, Node* mem, Node* base, int offset, const Type* value_type, BasicType bt) {
return load(ctl, mem, base, offset, value_type, bt, MemNode::acquire);
}
Node* PhaseMacroExpand::make_store(Node* ctl, Node* mem, Node* base, int offset, Node* value, BasicType bt) {
Node* adr = basic_plus_adr(base, offset);
......@@ -1434,6 +1442,12 @@ void PhaseMacroExpand::expand_allocate_common(
}
}
#if INCLUDE_JFR
if (JfrOptionSet::sample_object_allocations()) {
jfr_sample_fast_object_allocation(alloc, fast_oop, fast_oop_ctrl, fast_oop_rawmem);
}
#endif // INCLUDE_JFR
if (C->env()->dtrace_extended_probes()) {
// Slow-path call
int size = TypeFunc::Parms + 2;
......@@ -1619,6 +1633,116 @@ void PhaseMacroExpand::expand_allocate_common(
// This completes all paths into the result merge point
}
#if INCLUDE_JFR
static jint bottom_java_frame_bci(JVMState* state) {
assert(state != NULL, "Invariant");
JVMState* last = NULL;
JVMState* current = state;
while (current != NULL) {
last = current;
current = current->caller();
}
return last->bci();
}
//
// Pseudo code:
//
// int alloc_sample_enabled = *(int *)ObjectProfiler::enabled_flag_address();
// if (alloc_sample_enabled) {
// long alloc_count = thread->jfr_thread_local()->alloc_count();
// long alloc_count_new = alloc_count + 1;
// thread->jfr_thread_local()->set_alloc_count(alloc_count_new);
// long alloc_count_until_sample = thread->jfr_thread_local()->alloc_count_until_sample();
// if (alloc_count_until_sample == alloc_count_new) {
// jfr_fast_object_alloc_C(obj, thread);
// }
// }
void PhaseMacroExpand::jfr_sample_fast_object_allocation(
AllocateNode* alloc, Node* fast_oop,
Node*& fast_oop_ctrl, Node*& fast_oop_rawmem) {
Node* tls = transform_later(new (C) ThreadLocalNode());
Node* alloc_sample_enabled_addr = transform_later(ConPNode::make(C, (address) ObjectProfiler::enabled_flag_address()));
Node* alloc_sample_enabled = make_load_acquire(fast_oop_ctrl, fast_oop_rawmem, alloc_sample_enabled_addr, 0, TypeInt::INT, T_INT);
Node* alloc_sample_enabled_cmp = transform_later(new (C) CmpINode(alloc_sample_enabled, intcon(1)));
Node* alloc_sample_enabled_bool = transform_later(new (C) BoolNode(alloc_sample_enabled_cmp, BoolTest::eq));
IfNode* alloc_sample_enabled_if = (IfNode*)transform_later(new (C) IfNode(fast_oop_ctrl, alloc_sample_enabled_bool, PROB_MIN, COUNT_UNKNOWN));
Node* alloc_sample_enabled_ctrl = transform_later(new (C) IfTrueNode(alloc_sample_enabled_if));
Node* alloc_sample_enabled_mem = fast_oop_rawmem;
Node* alloc_sample_disabled_ctrl = transform_later(new (C) IfFalseNode(alloc_sample_enabled_if));
Node* alloc_sample_disabled_mem = fast_oop_rawmem;
Node* alloc_sample_enabled_region = transform_later(new (C) RegionNode(3));
Node* alloc_sample_enabled_region_phi_mem = transform_later(new (C) PhiNode(alloc_sample_enabled_region, Type::MEMORY, TypeRawPtr::BOTTOM));
enum { enabled_idx = 1, disabled_idx = 2 };
// if _enabled then
{
const int alloc_count_offset = in_bytes(TRACE_THREAD_ALLOC_COUNT_OFFSET);
Node* alloc_count = make_load(alloc_sample_enabled_ctrl, alloc_sample_enabled_mem, tls, alloc_count_offset, TypeLong::LONG, T_LONG);
Node* alloc_count_new = transform_later(new (C) AddLNode(alloc_count, longcon(1)));
alloc_sample_enabled_mem = make_store(alloc_sample_enabled_ctrl, alloc_sample_enabled_mem, tls, alloc_count_offset, alloc_count_new, T_LONG);
const int alloc_count_until_sample_offset = in_bytes(TRACE_THREAD_ALLOC_COUNT_UNTIL_SAMPLE_OFFSET);
Node* alloc_count_until_sample = make_load(alloc_sample_enabled_ctrl, alloc_sample_enabled_mem, tls, alloc_count_until_sample_offset, TypeLong::LONG, T_LONG);
Node* alloc_count_until_sample_cmp = transform_later(new (C) CmpLNode(alloc_count_until_sample, alloc_count_new));
Node* alloc_sample_hit_bool = transform_later(new (C) BoolNode(alloc_count_until_sample_cmp, BoolTest::eq));
IfNode* alloc_sample_hit_if = (IfNode*)transform_later(new (C) IfNode(alloc_sample_enabled_ctrl, alloc_sample_hit_bool, PROB_MIN, COUNT_UNKNOWN));
Node* alloc_sample_hit_ctrl = transform_later(new (C) IfTrueNode(alloc_sample_hit_if));
Node* alloc_sample_hit_mem = alloc_sample_enabled_mem;
Node* alloc_sample_miss_ctrl = transform_later(new (C) IfFalseNode(alloc_sample_hit_if));
Node* alloc_sample_miss_mem = alloc_sample_enabled_mem;
Node* alloc_sample_hit_region = transform_later(new (C) RegionNode(3));
Node* alloc_sample_hit_region_phi_mem = transform_later(new (C) PhiNode(alloc_sample_hit_region, Type::MEMORY, TypeRawPtr::BOTTOM));
// if sample_hit then
{
CallLeafNode *call = new (C) CallLeafNode(OptoRuntime::jfr_fast_object_alloc_Type(),
CAST_FROM_FN_PTR(address, OptoRuntime::jfr_fast_object_alloc_C),
"jfr_fast_object_alloc_C",
TypeRawPtr::BOTTOM);
call->init_req(TypeFunc::Parms+0, fast_oop);
call->init_req(TypeFunc::Parms+1, intcon(bottom_java_frame_bci(alloc->jvms())));
call->init_req(TypeFunc::Parms+2, tls);
call->init_req(TypeFunc::Control, alloc_sample_hit_ctrl);
call->init_req(TypeFunc::I_O , top());
call->init_req(TypeFunc::Memory , alloc_sample_hit_mem);
call->init_req(TypeFunc::ReturnAdr, alloc->in(TypeFunc::ReturnAdr));
call->init_req(TypeFunc::FramePtr, alloc->in(TypeFunc::FramePtr));
transform_later(call);
alloc_sample_hit_ctrl = new (C) ProjNode(call,TypeFunc::Control);
transform_later(alloc_sample_hit_ctrl);
alloc_sample_hit_mem = new (C) ProjNode(call,TypeFunc::Memory);
transform_later(alloc_sample_hit_mem);
alloc_sample_hit_region->init_req(enabled_idx, alloc_sample_hit_ctrl);
alloc_sample_hit_region_phi_mem->init_req(enabled_idx, alloc_sample_hit_mem);
}
{
alloc_sample_hit_region->init_req(disabled_idx, alloc_sample_miss_ctrl);
alloc_sample_hit_region_phi_mem->init_req(disabled_idx, alloc_sample_miss_mem);
}
{
alloc_sample_enabled_ctrl = alloc_sample_hit_region;
alloc_sample_enabled_mem = alloc_sample_hit_region_phi_mem;
}
alloc_sample_enabled_region->init_req(enabled_idx, alloc_sample_enabled_ctrl);
alloc_sample_enabled_region_phi_mem->init_req(enabled_idx, alloc_sample_enabled_mem);
}
{
alloc_sample_enabled_region->init_req(disabled_idx, alloc_sample_disabled_ctrl);
alloc_sample_enabled_region_phi_mem->init_req(disabled_idx, alloc_sample_disabled_mem);
}
{
fast_oop_ctrl = alloc_sample_enabled_region;
fast_oop_rawmem = alloc_sample_enabled_region_phi_mem;
}
}
#endif // INCLUDE_JFR
// Helper for PhaseMacroExpand::expand_allocate_common.
// Initializes the newly-allocated storage.
......
......@@ -61,8 +61,12 @@ private:
return n;
}
void set_eden_pointers(Node* &eden_top_adr, Node* &eden_end_adr);
Node* load( Node* ctl, Node* mem, Node* base, int offset,
const Type* value_type, BasicType bt, MemNode::MemOrd mo);
Node* make_load( Node* ctl, Node* mem, Node* base, int offset,
const Type* value_type, BasicType bt);
Node* make_load_acquire( Node* ctl, Node* mem, Node* base, int offset,
const Type* value_type, BasicType bt);
Node* make_store(Node* ctl, Node* mem, Node* base, int offset,
Node* value, BasicType bt);
......@@ -119,6 +123,10 @@ private:
Node* old_eden_top, Node* new_eden_top,
Node* length);
//JFR tracing
void jfr_sample_fast_object_allocation(AllocateNode* alloc, Node* fast_oop,
Node*& fast_oop_ctrl, Node*& fast_oop_rawmem);
public:
PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) {
_igvn.set_delay_transform(true);
......
......@@ -68,6 +68,7 @@
#include "runtime/vframe_hp.hpp"
#include "utilities/copy.hpp"
#include "utilities/preserveException.hpp"
#include "gc_interface/allocTracer.inline.hpp"
#if defined AD_MD_HPP
# include AD_MD_HPP
#elif defined TARGET_ARCH_MODEL_x86_32
......@@ -260,8 +261,10 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_instance_C(Klass* klass, JavaThread* thre
if (!HAS_PENDING_EXCEPTION) {
// Scavenge and allocate an instance.
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(false, THREAD);)
oop result = InstanceKlass::cast(klass)->allocate_instance(THREAD);
thread->set_vm_result(result);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(false, THREAD);)
// Pass oops back through thread local storage. Our apparent type to Java
// is that we return an oop, but we can block on exit from this routine and
......@@ -290,6 +293,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, JavaT
// Scavenge and allocate an instance.
oop result;
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
if (array_type->oop_is_typeArray()) {
// The oopFactory likes to work with the element type.
// (We could bypass the oopFactory, since it doesn't add much value.)
......@@ -303,6 +307,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, JavaT
Klass* elem_type = ObjArrayKlass::cast(array_type)->element_klass();
result = oopFactory::new_objArray(elem_type, len, THREAD);
}
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
// Pass oops back through thread local storage. Our apparent type to Java
// is that we return an oop, but we can block on exit from this routine and
......@@ -329,10 +334,12 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_nozero_C(Klass* array_type, int len
// Scavenge and allocate an instance.
oop result;
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
assert(array_type->oop_is_typeArray(), "should be called only for type array");
// The oopFactory likes to work with the element type.
BasicType elem_type = TypeArrayKlass::cast(array_type)->element_type();
result = oopFactory::new_typeArray_nozero(elem_type, len, THREAD);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
// Pass oops back through thread local storage. Our apparent type to Java
// is that we return an oop, but we can block on exit from this routine and
......@@ -379,7 +386,9 @@ JRT_ENTRY(void, OptoRuntime::multianewarray2_C(Klass* elem_type, int len1, int l
dims[0] = len1;
dims[1] = len2;
Handle holder(THREAD, elem_type->klass_holder()); // keep the klass alive
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
oop obj = ArrayKlass::cast(elem_type)->multi_allocate(2, dims, THREAD);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
deoptimize_caller_frame(thread, HAS_PENDING_EXCEPTION);
thread->set_vm_result(obj);
JRT_END
......@@ -396,7 +405,9 @@ JRT_ENTRY(void, OptoRuntime::multianewarray3_C(Klass* elem_type, int len1, int l
dims[1] = len2;
dims[2] = len3;
Handle holder(THREAD, elem_type->klass_holder()); // keep the klass alive
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
oop obj = ArrayKlass::cast(elem_type)->multi_allocate(3, dims, THREAD);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
deoptimize_caller_frame(thread, HAS_PENDING_EXCEPTION);
thread->set_vm_result(obj);
JRT_END
......@@ -414,7 +425,9 @@ JRT_ENTRY(void, OptoRuntime::multianewarray4_C(Klass* elem_type, int len1, int l
dims[2] = len3;
dims[3] = len4;
Handle holder(THREAD, elem_type->klass_holder()); // keep the klass alive
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
oop obj = ArrayKlass::cast(elem_type)->multi_allocate(4, dims, THREAD);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
deoptimize_caller_frame(thread, HAS_PENDING_EXCEPTION);
thread->set_vm_result(obj);
JRT_END
......@@ -451,7 +464,9 @@ JRT_ENTRY(void, OptoRuntime::multianewarrayN_C(Klass* elem_type, arrayOopDesc* d
Copy::conjoint_jints_atomic(j_dims, c_dims, len);
Handle holder(THREAD, elem_type->klass_holder()); // keep the klass alive
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_ENTER(true, THREAD);)
oop obj = ArrayKlass::cast(elem_type)->multi_allocate(len, c_dims, THREAD);
JFR_ONLY(TRACE_OPTO_SLOW_ALLOCATION_LEAVE(true, THREAD);)
deoptimize_caller_frame(thread, HAS_PENDING_EXCEPTION);
thread->set_vm_result(obj);
JRT_END
......@@ -1677,3 +1692,34 @@ JRT_LEAF(void, OptoRuntime::zap_dead_native_locals_C(JavaThread* thread))
JRT_END
# endif
#if INCLUDE_JFR
//-----------------------------------------------------------------------------
// JFR support.
const TypeFunc *OptoRuntime::jfr_fast_object_alloc_Type() {
const Type **fields = TypeTuple::fields(3);
fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM; // newly allocated object
fields[TypeFunc::Parms+1] = TypeInt::INT; // bci
fields[TypeFunc::Parms+2] = TypeRawPtr::BOTTOM; // tls
const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+3, fields);
// create result type (range)
fields = TypeTuple::fields(1);
fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM; // returned oop
const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+1, fields);
return TypeFunc::make(domain, range);
}
void OptoRuntime::jfr_fast_object_alloc_C(oopDesc* obj, jint top_frame_bci, JavaThread* thread) {
KlassHandle kh(thread, obj->klass());
assert(obj != NULL, "invariant");
assert(obj->klass() != NULL, "invariant");
thread->jfr_thread_local()->set_cached_top_frame_bci(top_frame_bci);
AllocTracer::send_opto_fast_allocation_event(kh, obj, obj->size() * HeapWordSize, thread);
thread->jfr_thread_local()->clear_cached_top_frame_bci();
thread->set_vm_result(obj);
}
#endif // INCLUDE_JFR
......@@ -179,6 +179,8 @@ public:
static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread);
static void complete_monitor_unlocking_C(oopDesc* obj, BasicLock* lock);
// JFR support
static void jfr_fast_object_alloc_C(oopDesc* obj, jint bci, JavaThread* thread);
private:
// Implicit exception support
......@@ -339,6 +341,9 @@ private:
static const TypeFunc* zap_dead_locals_Type();
# endif
// JFR support
static const TypeFunc* jfr_fast_object_alloc_Type();
private:
static NamedCounter * volatile _named_counters;
......
......@@ -97,6 +97,8 @@
# include "gc_interface/collectedHeap.hpp"
# include "gc_interface/collectedHeap.inline.hpp"
# include "gc_interface/gcCause.hpp"
# include "gc_interface/allocTracer.hpp"
# include "gc_interface/allocTracer.inline.hpp"
# include "interpreter/abstractInterpreter.hpp"
# include "interpreter/bytecode.hpp"
# include "interpreter/bytecodeHistogram.hpp"
......
......@@ -367,6 +367,8 @@ class vframeStream : public vframeStreamCommon {
}
}
Thread *& thread_ref() { return (Thread *&)_thread; }
// top_frame may not be at safepoint, start with sender
vframeStream(JavaThread* thread, frame top_frame, bool stop_at_java_call_stub = false);
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册