1/*
2 * Copyright (c) 2001, 2016, 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 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