/* * 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