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