1 /*
2  * Copyright (c) 2001, 2013, 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 #include "precompiled.hpp"
26 #include "classfile/vmSymbols.hpp"
27 #include "memory/allocation.inline.hpp"
28 #include "memory/resourceArea.hpp"
29 #include "oops/oop.inline.hpp"
30 #include "prims/jni.h"
31 #include "prims/jvm.h"
32 #include "runtime/interfaceSupport.hpp"
33 #include "runtime/perfData.hpp"
34 #include "runtime/perfMemory.hpp"
35 
36 /*
37  *      Implementation of class sun.misc.Perf
38  */
39 
40 
41 #define PERF_ENTRY(result_type, header) \
42   JVM_ENTRY(result_type, header)
43 
44 #define PERF_END JVM_END
45 
46 #define PerfWrapper(arg) /* Unimplemented at this time */
47 
jstr_to_utf(JNIEnv * env,jstring str,TRAPS)48 static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) {
49 
50   char* utfstr = NULL;
51 
52   if (str == NULL) {
53     THROW_0(vmSymbols::java_lang_NullPointerException());
54     //throw_new(env,"NullPointerException");
55   }
56 
57   int len = env->GetStringUTFLength(str);
58   int unicode_len = env->GetStringLength(str);
59 
60   utfstr = NEW_RESOURCE_ARRAY(char, len + 1);
61 
62   env->GetStringUTFRegion(str, 0, unicode_len, utfstr);
63 
64   return utfstr;
65 }
66 
67 PERF_ENTRY(jobject, Perf_Attach(JNIEnv *env, jobject unused, jstring user, int vmid, int mode))
68 
69   PerfWrapper("Perf_Attach");
70 
71   char* address = 0;
72   size_t capacity = 0;
73   const char* user_utf = NULL;
74 
75   ResourceMark rm;
76 
77   {
78     ThreadToNativeFromVM ttnfv(thread);
79 
80     user_utf = user == NULL ? NULL : jstr_to_utf(env, user, CHECK_NULL);
81   }
82 
83   if (mode != PerfMemory::PERF_MODE_RO &&
84       mode != PerfMemory::PERF_MODE_RW) {
85     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
86   }
87 
88   // attach to the PerfData memory region for the specified VM
89   PerfMemory::attach(user_utf, vmid, (PerfMemory::PerfMemoryMode) mode,
90                      &address, &capacity, CHECK_NULL);
91 
92   {
93     ThreadToNativeFromVM ttnfv(thread);
94     return env->NewDirectByteBuffer(address, (jlong)capacity);
95   }
96 
97 PERF_END
98 
99 PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer))
100 
101   PerfWrapper("Perf_Detach");
102 
103   void* address = 0;
104   jlong capacity = 0;
105 
106   // get buffer address and capacity
107   {
108    ThreadToNativeFromVM ttnfv(thread);
109    address = env->GetDirectBufferAddress(buffer);
110    capacity = env->GetDirectBufferCapacity(buffer);
111   }
112 
113   PerfMemory::detach((char*)address, capacity, CHECK);
114 
115 PERF_END
116 
117 PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name,
118            int variability, int units, jlong value))
119 
120   PerfWrapper("Perf_CreateLong");
121 
122   char* name_utf = NULL;
123 
124   if (units <= 0 || units > PerfData::U_Last) {
125     debug_only(warning("unexpected units argument, units = %d", units));
126     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
127   }
128 
129   ResourceMark rm;
130 
131   {
132     ThreadToNativeFromVM ttnfv(thread);
133 
134     name_utf = jstr_to_utf(env, name, CHECK_NULL);
135   }
136 
137   PerfLong* pl = NULL;
138 
139   // check that the PerfData name doesn't already exist
140   if (PerfDataManager::exists(name_utf)) {
141     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists");
142   }
143 
144   switch(variability) {
145   case PerfData::V_Constant:
146     pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf,
147                                                (PerfData::Units)units, value,
148                                                CHECK_NULL);
149     break;
150 
151   case PerfData::V_Monotonic:
152     pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
153                                                (PerfData::Units)units, value,
154                                                CHECK_NULL);
155     break;
156 
157   case PerfData::V_Variable:
158     pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
159                                               (PerfData::Units)units, value,
160                                               CHECK_NULL);
161     break;
162 
163   default: /* Illegal Argument */
164     debug_only(warning("unexpected variability value: %d", variability));
165     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
166     break;
167   }
168 
169   long* lp = (long*)pl->get_address();
170 
171   {
172     ThreadToNativeFromVM ttnfv(thread);
173     return env->NewDirectByteBuffer(lp, sizeof(jlong));
174   }
175 
176 PERF_END
177 
178 PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf,
179                                          jstring name, jint variability,
180                                          jint units, jbyteArray value,
181                                          jint maxlength))
182 
183   PerfWrapper("Perf_CreateByteArray");
184 
185   // check for valid byte array objects
186   if (name == NULL || value == NULL) {
187     THROW_0(vmSymbols::java_lang_NullPointerException());
188   }
189 
190   // check for valid variability classification
191   if (variability != PerfData::V_Constant &&
192       variability != PerfData::V_Variable) {
193     debug_only(warning("unexpected variability value: %d", variability));
194     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
195   }
196 
197   // check for valid units
198   if (units != PerfData::U_String) {
199     // only String based ByteArray objects are currently supported
200     debug_only(warning("unexpected units value: %d", variability));
201     THROW_0(vmSymbols::java_lang_IllegalArgumentException());
202   }
203 
204   int value_length;
205   char* name_utf = NULL;
206   jbyte* value_local = NULL;
207 
208   ResourceMark rm;
209 
210   {
211     ThreadToNativeFromVM ttnfv(thread);
212 
213     name_utf = jstr_to_utf(env, name, CHECK_NULL);
214 
215     value_length = env->GetArrayLength(value);
216 
217     value_local = NEW_RESOURCE_ARRAY(jbyte, value_length + 1);
218 
219     env->GetByteArrayRegion(value, 0, value_length, value_local);
220   }
221 
222   // check that the counter name doesn't already exist
223   if (PerfDataManager::exists((char*)name_utf)) {
224     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists");
225   }
226 
227   PerfByteArray* pbv = NULL;
228 
229   if (units == PerfData::U_String) {
230 
231     if (variability == PerfData::V_Constant) {
232       // create the string constant
233       pbv = PerfDataManager::create_string_constant(NULL_NS, (char*)name_utf,
234                                                     (char*)value_local,
235                                                     CHECK_NULL);
236 
237       assert(maxlength == value_length, "string constant length should be == maxlength");
238       maxlength = value_length;
239     }
240     else {
241 
242       // create the string variable
243       pbv = PerfDataManager::create_string_variable(NULL_NS, (char*)name_utf,
244                                                     maxlength,
245                                                     (char*)value_local,
246                                                     CHECK_NULL);
247 
248      assert(maxlength >= value_length,"string variable length should be <= maxlength");
249     }
250   }
251 
252   char* cp = (char*)pbv->get_address();
253 
254   {
255     ThreadToNativeFromVM ttnfv(thread);
256     return env->NewDirectByteBuffer(cp, maxlength+1);
257   }
258 
259 PERF_END
260 
261 PERF_ENTRY(jlong, Perf_HighResCounter(JNIEnv *env, jobject perf))
262 
263   PerfWrapper("Perf_HighResCounter");
264 
265   // this should be a method in java.lang.System. This value could
266   // be acquired through access to a PerfData performance counter, but
267   // doing so would require that the PerfData monitoring overhead be
268   // incurred by all Java applications, which is unacceptable.
269 
270   return os::elapsed_counter();
271 
272 PERF_END
273 
274 PERF_ENTRY(jlong, Perf_HighResFrequency(JNIEnv *env, jobject perf))
275 
276   PerfWrapper("Perf_HighResFrequency");
277 
278   // this should be a method in java.lang.System. This value could
279   // be acquired through access to a PerfData performance counter, but
280   // doing so would require that the PerfData monitoring overhead be
281   // incurred by all Java applications, which is unacceptable.
282 
283   return os::elapsed_frequency();
284 
285 PERF_END
286 
287 /// JVM_RegisterPerfMethods
288 
289 #define CC (char*)  /*cast a literal from (const char*)*/
290 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
291 #define BB "Ljava/nio/ByteBuffer;"
292 #define JLS "Ljava/lang/String;"
293 #define CL_ARGS     CC "(" JLS "IIJ)" BB
294 #define CBA_ARGS    CC "(" JLS "II[BI)" BB
295 
296 static JNINativeMethod perfmethods[] = {
297 
298   {CC "attach",              CC "(" JLS "II)" BB, FN_PTR(Perf_Attach)},
299   {CC "detach",              CC "(" BB ")V",      FN_PTR(Perf_Detach)},
300   {CC "createLong",          CL_ARGS,             FN_PTR(Perf_CreateLong)},
301   {CC "createByteArray",     CBA_ARGS,            FN_PTR(Perf_CreateByteArray)},
302   {CC "highResCounter",      CC "()J",            FN_PTR(Perf_HighResCounter)},
303   {CC "highResFrequency",    CC "()J",            FN_PTR(Perf_HighResFrequency)}
304 };
305 
306 #undef CBA_ARGS
307 #undef CL_ARGS
308 #undef JLS
309 #undef BB
310 #undef FN_PTR
311 #undef CC
312 
313 // This one function is exported, used by NativeLookup.
314 JVM_ENTRY(void, JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass))
315   PerfWrapper("JVM_RegisterPerfMethods");
316   {
317     ThreadToNativeFromVM ttnfv(thread);
318     int ok = env->RegisterNatives(perfclass, perfmethods, sizeof(perfmethods)/sizeof(JNINativeMethod));
319     guarantee(ok == 0, "register perf natives");
320   }
321 JVM_END
322