/*
* Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
*
* This file is part of the Lock Contention Tracing Subsystem for the HotSpot
* Virtual Machine, which is developed at Christian Doppler Laboratory on
* Monitoring and Evolution of Very-Large-Scale Software Systems. Please
* contact us at if you need additional information
* or have any questions.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work. If not, see .
*
*/
#include "evtrace/traceJavaBridge.hpp"
#include "evtrace/traceBuffer.hpp"
#include "evtrace/traceBufferQueue.hpp"
#include "evtrace/traceEvents.hpp"
#include "evtrace/traceWriter.hpp"
#include "evtrace/traceReaderThread.hpp"
#include "prims/jni.h"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#define TEVT_ENTRY(result_type, header) \
JVM_ENTRY(result_type, header)
#define TEVT_END JVM_END
TEVT_ENTRY(jobject, TEvT_DequeueBuffer(JNIEnv *env, jobject self, jlong queue_handle, const jboolean should_block))
TraceBufferQueue *queue = (TraceBufferQueue *) queue_handle;
TraceBuffer *buffer;
if (thread->is_TraceReader_thread()) {
// we do this to avoid interrupting the thread at a bad time
((TraceReaderThread *) thread)->set_is_polling_queue(true);
}
jlong delay = 4;
for (;;) {
buffer = queue->try_dequeue();
if (buffer != NULL || !should_block || !TraceManager::is_initialized()) {
break;
}
os::sleep(thread, delay, true);
if (delay <= 64) {
delay = 2 * delay;
}
}
if (thread->is_TraceReader_thread()) {
((TraceReaderThread *) thread)->set_is_polling_queue(false);
}
jobject bufobj = NULL;
if (buffer != NULL) {
ThreadToNativeFromVM ttn(thread);
jlong handle = (jlong) ((uintptr_t) buffer); // sign extension paranoia
size_t length = buffer->filled_size();
jobject bytebuf = env->NewDirectByteBuffer(buffer->data, length);
jclass clazz = env->FindClass("sun/evtracing/TraceBuffer");
jmethodID method = env->GetMethodID(clazz, "", "(JLjava/nio/ByteBuffer;J)V");
assert(method != NULL, "must be successful");
bufobj = env->NewObject(clazz, method, handle, bytebuf, buffer->owner_id);
assert(bufobj != NULL, "must succeed");
}
return bufobj;
TEVT_END
TEVT_ENTRY(void, TEvT_EnqueueBuffer(JNIEnv *env, jobject self, jlong queue_handle, jlong buffer_handle))
TraceBufferQueue *queue = (TraceBufferQueue *) queue_handle;
queue->enqueue((TraceBuffer *) buffer_handle);
TEVT_END
TEVT_ENTRY(void, TEvT_ResetAndEnqueueBuffer(JNIEnv *env, jobject self, jlong queue_handle, jlong buffer_handle))
TraceBuffer *buffer = (TraceBuffer *) buffer_handle;
buffer->reset();
TraceBufferQueue *queue = (TraceBufferQueue *) queue_handle;
queue->enqueue((TraceBuffer *) buffer_handle);
TEVT_END
TEVT_ENTRY(void, TEvT_FreeBuffer(JNIEnv *env, jobject self, jlong buffer_handle))
TraceBuffer *buffer = (TraceBuffer *) buffer_handle;
TraceManager::free_buffer(buffer);
TEVT_END
TEVT_ENTRY(jlong, TEvT_QueueCount(JNIEnv *env, jobject self, jlong queue_handle))
TraceBufferQueue *queue = (TraceBufferQueue *) queue_handle;
return (jlong) queue->count();TEVT_END
TEVT_ENTRY(void, TEvT_WriteGroupEvent(JNIEnv *env, jobject self, jlong park_global_seq_begin_ref, jobject source))
TraceEvents::write_group(thread, park_global_seq_begin_ref, instanceOop(JNIHandles::resolve_non_null(source)));
TEVT_END
TEVT_ENTRY(jstring, TEvT_GetConfiguration(JNIEnv *env, jobject self))
jstring config = NULL;
if (EventTracingConfiguration != NULL && EventTracingConfiguration[0] != '\0') {
ThreadToNativeFromVM ttn(thread);
config = env->NewStringUTF(EventTracingConfiguration);
}
return config;
TEVT_END
TEVT_ENTRY(void, TEvT_PutNativeStatistics(JNIEnv *env, jobject self, jobject map))
JavaTraceStatistics jts(env, thread, instanceHandle(instanceOop(JNIHandles::resolve_non_null(map))), CHECK);
TraceManager::write_stats(&jts);
TEVT_END
JavaTraceStatistics::JavaTraceStatistics(JNIEnv* env, JavaThread* thread, instanceHandle map, TRAPS)
: _env(env),
THREAD(THREAD),
_hashmap_obj(map)
{
}
void JavaTraceStatistics::add_entry(const char* name, jdouble value) {
assert(name != NULL, "must not be NULL");
// assume utf8 string to save native transition required by java_lang_String::create_from_platform_dependent_str
Handle name_str = java_lang_String::create_from_str(name, CHECK);
oop value_oop = java_lang_boxing_object::create(T_DOUBLE, (jvalue*) &value, CHECK);
Handle value_handle(THREAD, value_oop);
JavaValue result(T_OBJECT);
JavaCalls::call_virtual(&result,
_hashmap_obj,
_hashmap_obj->klass(),
vmSymbols::put_name(),
vmSymbols::object_object_object_signature(),
name_str,
value_handle,
CHECK);
}
TEVT_ENTRY(void, TEvT_ResetNativeStatistics(JNIEnv *env, jobject self))
TraceManager::reset_stats();
TEVT_END
TEVT_ENTRY(void, TEvT_ResetNativeMetadata(JNIEnv *env, jobject self))
TraceManager::reset_metadata();
TEVT_END
TEVT_ENTRY(void, TEvT_ReclaimBuffers(JNIEnv *env, jobject self, jboolean wait_until_processed))
TraceManager::reclaim_buffers_in_safepoint(wait_until_processed);
TEVT_END
#define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
static JNINativeMethod tevtmethods[] = {
{CC"dequeueBuffer", CC"(JZ)Lsun/evtracing/TraceBuffer;", FN_PTR(TEvT_DequeueBuffer)},
{CC"enqueueBuffer", CC"(JJ)V", FN_PTR(TEvT_EnqueueBuffer)},
{CC"resetAndEnqueueBuffer", CC"(JJ)V", FN_PTR(TEvT_ResetAndEnqueueBuffer)},
{CC"freeBuffer", CC"(J)V", FN_PTR(TEvT_FreeBuffer)},
{CC"queueCount", CC"(J)J", FN_PTR(TEvT_QueueCount) },
{CC"writeGroupEvent", CC"(JLjava/lang/Object;)V", FN_PTR(TEvT_WriteGroupEvent)},
{CC"getConfiguration", CC"()Ljava/lang/String;", FN_PTR(TEvT_GetConfiguration)},
{CC"putNativeStatistics", CC"(Ljava/util/Map;)V", FN_PTR(TEvT_PutNativeStatistics)},
{CC"resetNativeStatistics", CC"()V", FN_PTR(TEvT_ResetNativeStatistics)},
{CC"resetNativeMetadata", CC"()V", FN_PTR(TEvT_ResetNativeMetadata)},
{CC"reclaimBuffers", CC"(Z)V", FN_PTR(TEvT_ReclaimBuffers)},
};
JVM_ENTRY(jboolean, JVM_RegisterEventTracingMethods(JNIEnv* env, jclass tevtclass))
if (EnableEventTracing) {
ThreadToNativeFromVM ttnfv(thread);
int ok = env->RegisterNatives(tevtclass, tevtmethods, sizeof(tevtmethods) / sizeof(JNINativeMethod));
guarantee(ok == 0, "register event tracing natives");
}
return EnableEventTracing;
JVM_END