aoqi@0: /* aoqi@0: * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "classfile/vmSymbols.hpp" aoqi@0: #include "memory/allocation.inline.hpp" aoqi@0: #include "memory/resourceArea.hpp" aoqi@0: #include "oops/oop.inline.hpp" aoqi@0: #include "prims/jni.h" aoqi@0: #include "prims/jvm.h" aoqi@0: #include "runtime/interfaceSupport.hpp" aoqi@0: #include "runtime/perfData.hpp" aoqi@0: #include "runtime/perfMemory.hpp" aoqi@0: aoqi@0: /* aoqi@0: * Implementation of class sun.misc.Perf aoqi@0: */ aoqi@0: aoqi@0: aoqi@0: #define PERF_ENTRY(result_type, header) \ aoqi@0: JVM_ENTRY(result_type, header) aoqi@0: aoqi@0: #define PERF_END JVM_END aoqi@0: aoqi@0: #define PerfWrapper(arg) /* Unimplemented at this time */ aoqi@0: aoqi@0: static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) { aoqi@0: aoqi@0: char* utfstr = NULL; aoqi@0: aoqi@0: if (str == NULL) { aoqi@0: THROW_0(vmSymbols::java_lang_NullPointerException()); aoqi@0: //throw_new(env,"NullPointerException"); aoqi@0: } aoqi@0: aoqi@0: int len = env->GetStringUTFLength(str); aoqi@0: int unicode_len = env->GetStringLength(str); aoqi@0: aoqi@0: utfstr = NEW_RESOURCE_ARRAY(char, len + 1); aoqi@0: aoqi@0: env->GetStringUTFRegion(str, 0, unicode_len, utfstr); aoqi@0: aoqi@0: return utfstr; aoqi@0: } aoqi@0: aoqi@0: PERF_ENTRY(jobject, Perf_Attach(JNIEnv *env, jobject unused, jstring user, int vmid, int mode)) aoqi@0: aoqi@0: PerfWrapper("Perf_Attach"); aoqi@0: aoqi@0: char* address = 0; aoqi@0: size_t capacity = 0; aoqi@0: const char* user_utf = NULL; aoqi@0: aoqi@0: ResourceMark rm; aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: aoqi@0: user_utf = user == NULL ? NULL : jstr_to_utf(env, user, CHECK_NULL); aoqi@0: } aoqi@0: aoqi@0: if (mode != PerfMemory::PERF_MODE_RO && aoqi@0: mode != PerfMemory::PERF_MODE_RW) { aoqi@0: THROW_0(vmSymbols::java_lang_IllegalArgumentException()); aoqi@0: } aoqi@0: aoqi@0: // attach to the PerfData memory region for the specified VM aoqi@0: PerfMemory::attach(user_utf, vmid, (PerfMemory::PerfMemoryMode) mode, aoqi@0: &address, &capacity, CHECK_NULL); aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: return env->NewDirectByteBuffer(address, (jlong)capacity); aoqi@0: } aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer)) aoqi@0: aoqi@0: PerfWrapper("Perf_Detach"); aoqi@0: aoqi@0: void* address = 0; aoqi@0: jlong capacity = 0; aoqi@0: aoqi@0: // get buffer address and capacity aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: address = env->GetDirectBufferAddress(buffer); aoqi@0: capacity = env->GetDirectBufferCapacity(buffer); aoqi@0: } aoqi@0: aoqi@0: PerfMemory::detach((char*)address, capacity, CHECK); aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, aoqi@0: int variability, int units, jlong value)) aoqi@0: aoqi@0: PerfWrapper("Perf_CreateLong"); aoqi@0: aoqi@0: char* name_utf = NULL; aoqi@0: aoqi@0: if (units <= 0 || units > PerfData::U_Last) { aoqi@0: debug_only(warning("unexpected units argument, units = %d", units)); aoqi@0: THROW_0(vmSymbols::java_lang_IllegalArgumentException()); aoqi@0: } aoqi@0: aoqi@0: ResourceMark rm; aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: aoqi@0: name_utf = jstr_to_utf(env, name, CHECK_NULL); aoqi@0: } aoqi@0: aoqi@0: PerfLong* pl = NULL; aoqi@0: aoqi@0: // check that the PerfData name doesn't already exist aoqi@0: if (PerfDataManager::exists(name_utf)) { aoqi@0: THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists"); aoqi@0: } aoqi@0: aoqi@0: switch(variability) { aoqi@0: case PerfData::V_Constant: aoqi@0: pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf, aoqi@0: (PerfData::Units)units, value, aoqi@0: CHECK_NULL); aoqi@0: break; aoqi@0: aoqi@0: case PerfData::V_Monotonic: aoqi@0: pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf, aoqi@0: (PerfData::Units)units, value, aoqi@0: CHECK_NULL); aoqi@0: break; aoqi@0: aoqi@0: case PerfData::V_Variable: aoqi@0: pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf, aoqi@0: (PerfData::Units)units, value, aoqi@0: CHECK_NULL); aoqi@0: break; aoqi@0: aoqi@0: default: /* Illegal Argument */ aoqi@0: debug_only(warning("unexpected variability value: %d", variability)); aoqi@0: THROW_0(vmSymbols::java_lang_IllegalArgumentException()); aoqi@0: break; aoqi@0: } aoqi@0: aoqi@0: long* lp = (long*)pl->get_address(); aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: return env->NewDirectByteBuffer(lp, sizeof(jlong)); aoqi@0: } aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf, aoqi@0: jstring name, jint variability, aoqi@0: jint units, jbyteArray value, aoqi@0: jint maxlength)) aoqi@0: aoqi@0: PerfWrapper("Perf_CreateByteArray"); aoqi@0: aoqi@0: // check for valid byte array objects aoqi@0: if (name == NULL || value == NULL) { aoqi@0: THROW_0(vmSymbols::java_lang_NullPointerException()); aoqi@0: } aoqi@0: aoqi@0: // check for valid variability classification aoqi@0: if (variability != PerfData::V_Constant && aoqi@0: variability != PerfData::V_Variable) { aoqi@0: debug_only(warning("unexpected variability value: %d", variability)); aoqi@0: THROW_0(vmSymbols::java_lang_IllegalArgumentException()); aoqi@0: } aoqi@0: aoqi@0: // check for valid units aoqi@0: if (units != PerfData::U_String) { aoqi@0: // only String based ByteArray objects are currently supported aoqi@0: debug_only(warning("unexpected units value: %d", variability)); aoqi@0: THROW_0(vmSymbols::java_lang_IllegalArgumentException()); aoqi@0: } aoqi@0: aoqi@0: int value_length; aoqi@0: char* name_utf = NULL; aoqi@0: jbyte* value_local = NULL; aoqi@0: aoqi@0: ResourceMark rm; aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: aoqi@0: name_utf = jstr_to_utf(env, name, CHECK_NULL); aoqi@0: aoqi@0: value_length = env->GetArrayLength(value); aoqi@0: aoqi@0: value_local = NEW_RESOURCE_ARRAY(jbyte, value_length + 1); aoqi@0: aoqi@0: env->GetByteArrayRegion(value, 0, value_length, value_local); aoqi@0: } aoqi@0: aoqi@0: // check that the counter name doesn't already exist aoqi@0: if (PerfDataManager::exists((char*)name_utf)) { aoqi@0: THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists"); aoqi@0: } aoqi@0: aoqi@0: PerfByteArray* pbv = NULL; aoqi@0: aoqi@0: if (units == PerfData::U_String) { aoqi@0: aoqi@0: if (variability == PerfData::V_Constant) { aoqi@0: // create the string constant aoqi@0: pbv = PerfDataManager::create_string_constant(NULL_NS, (char*)name_utf, aoqi@0: (char*)value_local, aoqi@0: CHECK_NULL); aoqi@0: aoqi@0: assert(maxlength == value_length, "string constant length should be == maxlength"); aoqi@0: maxlength = value_length; aoqi@0: } aoqi@0: else { aoqi@0: aoqi@0: // create the string variable aoqi@0: pbv = PerfDataManager::create_string_variable(NULL_NS, (char*)name_utf, aoqi@0: maxlength, aoqi@0: (char*)value_local, aoqi@0: CHECK_NULL); aoqi@0: aoqi@0: assert(maxlength >= value_length,"string variable length should be <= maxlength"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: char* cp = (char*)pbv->get_address(); aoqi@0: aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: return env->NewDirectByteBuffer(cp, maxlength+1); aoqi@0: } aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: PERF_ENTRY(jlong, Perf_HighResCounter(JNIEnv *env, jobject perf)) aoqi@0: aoqi@0: PerfWrapper("Perf_HighResCounter"); aoqi@0: aoqi@0: // this should be a method in java.lang.System. This value could aoqi@0: // be acquired through access to a PerfData performance counter, but aoqi@0: // doing so would require that the PerfData monitoring overhead be aoqi@0: // incurred by all Java applications, which is unacceptable. aoqi@0: aoqi@0: return os::elapsed_counter(); aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: PERF_ENTRY(jlong, Perf_HighResFrequency(JNIEnv *env, jobject perf)) aoqi@0: aoqi@0: PerfWrapper("Perf_HighResFrequency"); aoqi@0: aoqi@0: // this should be a method in java.lang.System. This value could aoqi@0: // be acquired through access to a PerfData performance counter, but aoqi@0: // doing so would require that the PerfData monitoring overhead be aoqi@0: // incurred by all Java applications, which is unacceptable. aoqi@0: aoqi@0: return os::elapsed_frequency(); aoqi@0: aoqi@0: PERF_END aoqi@0: aoqi@0: /// JVM_RegisterPerfMethods aoqi@0: aoqi@0: #define CC (char*) /*cast a literal from (const char*)*/ aoqi@0: #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) aoqi@0: #define BB "Ljava/nio/ByteBuffer;" aoqi@0: #define JLS "Ljava/lang/String;" aoqi@0: #define CL_ARGS CC"("JLS"IIJ)"BB aoqi@0: #define CBA_ARGS CC"("JLS"II[BI)"BB aoqi@0: aoqi@0: static JNINativeMethod perfmethods[] = { aoqi@0: aoqi@0: {CC"attach", CC"("JLS"II)"BB, FN_PTR(Perf_Attach)}, aoqi@0: {CC"detach", CC"("BB")V", FN_PTR(Perf_Detach)}, aoqi@0: {CC"createLong", CL_ARGS, FN_PTR(Perf_CreateLong)}, aoqi@0: {CC"createByteArray", CBA_ARGS, FN_PTR(Perf_CreateByteArray)}, aoqi@0: {CC"highResCounter", CC"()J", FN_PTR(Perf_HighResCounter)}, aoqi@0: {CC"highResFrequency", CC"()J", FN_PTR(Perf_HighResFrequency)} aoqi@0: }; aoqi@0: aoqi@0: #undef CBA_ARGS aoqi@0: #undef CL_ARGS aoqi@0: #undef JLS aoqi@0: #undef BB aoqi@0: #undef FN_PTR aoqi@0: #undef CC aoqi@0: aoqi@0: // This one function is exported, used by NativeLookup. aoqi@0: JVM_ENTRY(void, JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass)) aoqi@0: PerfWrapper("JVM_RegisterPerfMethods"); aoqi@0: { aoqi@0: ThreadToNativeFromVM ttnfv(thread); aoqi@0: int ok = env->RegisterNatives(perfclass, perfmethods, sizeof(perfmethods)/sizeof(JNINativeMethod)); aoqi@0: guarantee(ok == 0, "register perf natives"); aoqi@0: } aoqi@0: JVM_END