1 /*
   2  * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 /*
  26  *      Implementation of class sun.misc.Perf
  27  */
  28 
  29 #include "incls/_precompiled.incl"
  30 #include "incls/_perf.cpp.incl"
  31 
  32 
  33 #define PERF_ENTRY(result_type, header) \
  34   JVM_ENTRY(result_type, header)
  35 
  36 #define PERF_END JVM_END
  37 
  38 #define PerfWrapper(arg) /* Unimplemented at this time */
  39 
  40 static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) {
  41 
  42   char* utfstr = NULL;
  43 
  44   if (str == NULL) {
  45     THROW_0(vmSymbols::java_lang_NullPointerException());
  46     //throw_new(env,"NullPointerException");
  47   }
  48 
  49   int len = env->GetStringUTFLength(str);
  50   int unicode_len = env->GetStringLength(str);
  51 
  52   utfstr = NEW_RESOURCE_ARRAY(char, len + 1);
  53 
  54   env->GetStringUTFRegion(str, 0, unicode_len, utfstr);
  55 
  56   return utfstr;
  57 }
  58 
  59 PERF_ENTRY(jobject, Perf_Attach(JNIEnv *env, jobject unused, jstring user, int vmid, int mode))
  60 
  61   PerfWrapper("Perf_Attach");
  62 
  63   char* address = 0;
  64   size_t capacity = 0;
  65   const char* user_utf = NULL;
  66 
  67   ResourceMark rm;
  68 
  69   {
  70     ThreadToNativeFromVM ttnfv(thread);
  71 
  72     user_utf = user == NULL ? NULL : jstr_to_utf(env, user, CHECK_NULL);
  73   }
  74 
  75   if (mode != PerfMemory::PERF_MODE_RO &&
  76       mode != PerfMemory::PERF_MODE_RW) {
  77     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
  78   }
  79 
  80   // attach to the PerfData memory region for the specified VM
  81   PerfMemory::attach(user_utf, vmid, (PerfMemory::PerfMemoryMode) mode,
  82                      &address, &capacity, CHECK_NULL);
  83 
  84   {
  85     ThreadToNativeFromVM ttnfv(thread);
  86     return env->NewDirectByteBuffer(address, (jlong)capacity);
  87   }
  88 
  89 PERF_END
  90 
  91 PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer))
  92 
  93   PerfWrapper("Perf_Detach");
  94 
  95   void* address = 0;
  96   jlong capacity = 0;
  97 
  98   // get buffer address and capacity
  99   {
 100    ThreadToNativeFromVM ttnfv(thread);
 101    address = env->GetDirectBufferAddress(buffer);
 102    capacity = env->GetDirectBufferCapacity(buffer);
 103   }
 104 
 105   PerfMemory::detach((char*)address, capacity, CHECK);
 106 
 107 PERF_END
 108 
 109 PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name,
 110            int variability, int units, jlong value))
 111 
 112   PerfWrapper("Perf_CreateLong");
 113 
 114   char* name_utf = NULL;
 115 
 116   if (units <= 0 || units > PerfData::U_Last) {
 117     debug_only(warning("unexpected units argument, units = %d", units));
 118     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
 119   }
 120 
 121   ResourceMark rm;
 122 
 123   {
 124     ThreadToNativeFromVM ttnfv(thread);
 125 
 126     name_utf = jstr_to_utf(env, name, CHECK_NULL);
 127   }
 128 
 129   PerfLong* pl = NULL;
 130 
 131   // check that the PerfData name doesn't already exist
 132   if (PerfDataManager::exists(name_utf)) {
 133     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists");
 134   }
 135 
 136   switch(variability) {
 137   case 1:  /* V_Constant */
 138     pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf,
 139                                                (PerfData::Units)units, value,
 140                                                CHECK_NULL);
 141     break;
 142 
 143   case 2:  /* V_Variable */
 144     pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
 145                                                (PerfData::Units)units, value,
 146                                                CHECK_NULL);
 147     break;
 148 
 149   case 3:  /* V_Monotonic Counter */
 150     pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
 151                                               (PerfData::Units)units, value,
 152                                               CHECK_NULL);
 153     break;
 154 
 155   default: /* Illegal Argument */
 156     debug_only(warning("unexpected variability value: %d", variability));
 157     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
 158     break;
 159   }
 160 
 161   long* lp = (long*)pl->get_address();
 162 
 163   {
 164     ThreadToNativeFromVM ttnfv(thread);
 165     return env->NewDirectByteBuffer(lp, sizeof(jlong));
 166   }
 167 
 168 PERF_END
 169 
 170 PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf,
 171                                          jstring name, jint variability,
 172                                          jint units, jbyteArray value,
 173                                          jint maxlength))
 174 
 175   PerfWrapper("Perf_CreateByteArray");
 176 
 177   // check for valid byte array objects
 178   if (name == NULL || value == NULL) {
 179     THROW_0(vmSymbols::java_lang_NullPointerException());
 180   }
 181 
 182   // check for valid variability classification
 183   if (variability != PerfData::V_Constant &&
 184       variability != PerfData::V_Variable) {
 185     debug_only(warning("unexpected variability value: %d", variability));
 186     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
 187   }
 188 
 189   // check for valid units
 190   if (units != PerfData::U_String) {
 191     // only String based ByteArray objects are currently supported
 192     debug_only(warning("unexpected units value: %d", variability));
 193     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
 194   }
 195 
 196   int value_length;
 197   char* name_utf = NULL;
 198   jbyte* value_local = NULL;
 199 
 200   ResourceMark rm;
 201 
 202   {
 203     ThreadToNativeFromVM ttnfv(thread);
 204 
 205     name_utf = jstr_to_utf(env, name, CHECK_NULL);
 206 
 207     value_length = env->GetArrayLength(value);
 208 
 209     value_local = NEW_RESOURCE_ARRAY(jbyte, value_length + 1);
 210 
 211     env->GetByteArrayRegion(value, 0, value_length, value_local);
 212   }
 213 
 214   // check that the counter name doesn't already exist
 215   if (PerfDataManager::exists((char*)name_utf)) {
 216     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists");
 217   }
 218 
 219   PerfByteArray* pbv = NULL;
 220 
 221   if (units == PerfData::U_String) {
 222 
 223     if (variability == PerfData::V_Constant) {
 224       // create the string constant
 225       pbv = PerfDataManager::create_string_constant(NULL_NS, (char*)name_utf,
 226                                                     (char*)value_local,
 227                                                     CHECK_NULL);
 228 
 229       assert(maxlength == value_length, "string constant length should be == maxlength");
 230       maxlength = value_length;
 231     }
 232     else {
 233 
 234       // create the string variable
 235       pbv = PerfDataManager::create_string_variable(NULL_NS, (char*)name_utf,
 236                                                     maxlength,
 237                                                     (char*)value_local,
 238                                                     CHECK_NULL);
 239 
 240      assert(maxlength >= value_length,"string variable length should be <= maxlength");
 241     }
 242   }
 243 
 244   char* cp = (char*)pbv->get_address();
 245 
 246   {
 247     ThreadToNativeFromVM ttnfv(thread);
 248     return env->NewDirectByteBuffer(cp, maxlength+1);
 249   }
 250 
 251 PERF_END
 252 
 253 PERF_ENTRY(jlong, Perf_HighResCounter(JNIEnv *env, jobject perf))
 254 
 255   PerfWrapper("Perf_HighResCounter");
 256 
 257   // this should be a method in java.lang.System. This value could
 258   // be acquired through access to a PerfData performance counter, but
 259   // doing so would require that the PerfData monitoring overhead be
 260   // incurred by all Java applications, which is unacceptable.
 261 
 262   return os::elapsed_counter();
 263 
 264 PERF_END
 265 
 266 PERF_ENTRY(jlong, Perf_HighResFrequency(JNIEnv *env, jobject perf))
 267 
 268   PerfWrapper("Perf_HighResFrequency");
 269 
 270   // this should be a method in java.lang.System. This value could
 271   // be acquired through access to a PerfData performance counter, but
 272   // doing so would require that the PerfData monitoring overhead be
 273   // incurred by all Java applications, which is unacceptable.
 274 
 275   return os::elapsed_frequency();
 276 
 277 PERF_END
 278 
 279 /// JVM_RegisterPerfMethods
 280 
 281 #define CC (char*)  /*cast a literal from (const char*)*/
 282 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
 283 #define BB "Ljava/nio/ByteBuffer;"
 284 #define JLS "Ljava/lang/String;"
 285 #define CL_ARGS     CC"("JLS"IIJ)"BB
 286 #define CBA_ARGS    CC"("JLS"II[BI)"BB
 287 
 288 static JNINativeMethod perfmethods[] = {
 289 
 290   {CC"attach",              CC"("JLS"II)"BB,  FN_PTR(Perf_Attach)},
 291   {CC"detach",              CC"("BB")V",      FN_PTR(Perf_Detach)},
 292   {CC"createLong",          CL_ARGS,          FN_PTR(Perf_CreateLong)},
 293   {CC"createByteArray",     CBA_ARGS,         FN_PTR(Perf_CreateByteArray)},
 294   {CC"highResCounter",      CC"()J",          FN_PTR(Perf_HighResCounter)},
 295   {CC"highResFrequency",    CC"()J",          FN_PTR(Perf_HighResFrequency)}
 296 };
 297 
 298 #undef CBA_ARGS
 299 #undef CL_ARGS
 300 #undef JLS
 301 #undef BB
 302 #undef FN_PTR
 303 #undef CC
 304 
 305 // This one function is exported, used by NativeLookup.
 306 JVM_ENTRY(void, JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass))
 307   PerfWrapper("JVM_RegisterPerfMethods");
 308   {
 309     ThreadToNativeFromVM ttnfv(thread);
 310     int ok = env->RegisterNatives(perfclass, perfmethods, sizeof(perfmethods)/sizeof(JNINativeMethod));
 311     guarantee(ok == 0, "register perf natives");
 312   }
 313 JVM_END