1 | /* |
2 | * Copyright (c) 2012, 2019, 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/javaClasses.hpp" |
27 | #include "classfile/vmSymbols.hpp" |
28 | #include "jfr/jfr.hpp" |
29 | #include "jfr/dcmd/jfrDcmds.hpp" |
30 | #include "jfr/jni/jfrJavaSupport.hpp" |
31 | #include "jfr/recorder/jfrRecorder.hpp" |
32 | #include "jfr/recorder/service/jfrOptionSet.hpp" |
33 | #include "memory/resourceArea.hpp" |
34 | #include "oops/oop.inline.hpp" |
35 | #include "oops/symbol.hpp" |
36 | #include "runtime/handles.inline.hpp" |
37 | #include "services/diagnosticArgument.hpp" |
38 | #include "services/diagnosticFramework.hpp" |
39 | #include "utilities/globalDefinitions.hpp" |
40 | |
41 | #ifdef _WINDOWS |
42 | #define JFR_FILENAME_EXAMPLE "C:\\Users\\user\\My Recording.jfr" |
43 | #endif |
44 | |
45 | #ifdef __APPLE__ |
46 | #define JFR_FILENAME_EXAMPLE "/Users/user/My Recording.jfr" |
47 | #endif |
48 | |
49 | #ifndef JFR_FILENAME_EXAMPLE |
50 | #define JFR_FILENAME_EXAMPLE "/home/user/My Recording.jfr" |
51 | #endif |
52 | |
53 | // JNIHandle management |
54 | |
55 | // ------------------------------------------------------------------ |
56 | // push_jni_handle_block |
57 | // |
58 | // Push on a new block of JNI handles. |
59 | static void push_jni_handle_block(Thread* const thread) { |
60 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread)); |
61 | |
62 | // Allocate a new block for JNI handles. |
63 | // Inlined code from jni_PushLocalFrame() |
64 | JNIHandleBlock* prev_handles = thread->active_handles(); |
65 | JNIHandleBlock* entry_handles = JNIHandleBlock::allocate_block(thread); |
66 | assert(entry_handles != NULL && prev_handles != NULL, "should not be NULL" ); |
67 | entry_handles->set_pop_frame_link(prev_handles); // make sure prev handles get gc'd. |
68 | thread->set_active_handles(entry_handles); |
69 | } |
70 | |
71 | // ------------------------------------------------------------------ |
72 | // pop_jni_handle_block |
73 | // |
74 | // Pop off the current block of JNI handles. |
75 | static void pop_jni_handle_block(Thread* const thread) { |
76 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread)); |
77 | |
78 | // Release our JNI handle block |
79 | JNIHandleBlock* entry_handles = thread->active_handles(); |
80 | JNIHandleBlock* prev_handles = entry_handles->pop_frame_link(); |
81 | // restore |
82 | thread->set_active_handles(prev_handles); |
83 | entry_handles->set_pop_frame_link(NULL); |
84 | JNIHandleBlock::release_block(entry_handles, thread); // may block |
85 | } |
86 | |
87 | class JNIHandleBlockManager : public StackObj { |
88 | private: |
89 | Thread* const _thread; |
90 | public: |
91 | JNIHandleBlockManager(Thread* thread) : _thread(thread) { |
92 | push_jni_handle_block(_thread); |
93 | } |
94 | |
95 | ~JNIHandleBlockManager() { |
96 | pop_jni_handle_block(_thread); |
97 | } |
98 | }; |
99 | |
100 | static bool is_module_available(outputStream* output, TRAPS) { |
101 | return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD); |
102 | } |
103 | |
104 | static bool is_disabled(outputStream* output) { |
105 | if (Jfr::is_disabled()) { |
106 | if (output != NULL) { |
107 | output->print_cr("Flight Recorder is disabled.\n" ); |
108 | } |
109 | return true; |
110 | } |
111 | return false; |
112 | } |
113 | |
114 | static bool is_recorder_instance_created(outputStream* output) { |
115 | if (!JfrRecorder::is_created()) { |
116 | if (output != NULL) { |
117 | output->print_cr("No available recordings.\n" ); |
118 | output->print_cr("Use JFR.start to start a recording.\n" ); |
119 | } |
120 | return false; |
121 | } |
122 | return true; |
123 | } |
124 | |
125 | static bool invalid_state(outputStream* out, TRAPS) { |
126 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
127 | return is_disabled(out) || !is_module_available(out, THREAD); |
128 | } |
129 | |
130 | static void print_pending_exception(outputStream* output, oop throwable) { |
131 | assert(throwable != NULL, "invariant" ); |
132 | |
133 | oop msg = java_lang_Throwable::message(throwable); |
134 | |
135 | if (msg != NULL) { |
136 | char* text = java_lang_String::as_utf8_string(msg); |
137 | output->print_raw_cr(text); |
138 | } |
139 | } |
140 | |
141 | static void print_message(outputStream* output, const char* message) { |
142 | if (message != NULL) { |
143 | output->print_raw(message); |
144 | } |
145 | } |
146 | |
147 | static void handle_dcmd_result(outputStream* output, |
148 | const oop result, |
149 | const DCmdSource source, |
150 | TRAPS) { |
151 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
152 | assert(output != NULL, "invariant" ); |
153 | if (HAS_PENDING_EXCEPTION) { |
154 | print_pending_exception(output, PENDING_EXCEPTION); |
155 | // Don't clear excption on startup, JVM should fail initialization. |
156 | if (DCmd_Source_Internal != source) { |
157 | CLEAR_PENDING_EXCEPTION; |
158 | } |
159 | return; |
160 | } |
161 | |
162 | assert(!HAS_PENDING_EXCEPTION, "invariant" ); |
163 | |
164 | if (result != NULL) { |
165 | const char* result_chars = java_lang_String::as_utf8_string(result); |
166 | print_message(output, result_chars); |
167 | } |
168 | } |
169 | |
170 | static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) { |
171 | assert(args != NULL, "invariant" ); |
172 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
173 | assert(args->klass() != NULL, "invariant" ); |
174 | args->set_name("<init>" ); |
175 | args->set_signature("()V" ); |
176 | JfrJavaSupport::new_object(args, CHECK_NULL); |
177 | return (oop)args->result()->get_jobject(); |
178 | } |
179 | |
180 | JfrDumpFlightRecordingDCmd::JfrDumpFlightRecordingDCmd(outputStream* output, |
181 | bool heap) : DCmdWithParser(output, heap), |
182 | _name("name" , "Recording name, e.g. \\\"My Recording\\\"" , "STRING" , false, NULL), |
183 | _filename("filename" , "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"" , "STRING" , false), |
184 | _maxage("maxage" , "Maximum duration to dump, in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit" , "NANOTIME" , false, "0" ), |
185 | _maxsize("maxsize" , "Maximum amount of bytes to dump, in (M)B or (G)B, e.g. 500M, or 0 for no limit" , "MEMORY SIZE" , false, "0" ), |
186 | _begin("begin" , "Point in time to dump data from, e.g. 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d" , "STRING" , false), |
187 | _end("end" , "Point in time to dump data to, e.g. 09:00, 21:35:00, 2018-06-03T18:12:56.827Z, 2018-06-03T20:13:46.832, -10m, -3h, or -1d" , "STRING" , false), |
188 | _path_to_gc_roots("path-to-gc-roots" , "Collect path to GC roots" , "BOOLEAN" , false, "false" ) { |
189 | _dcmdparser.add_dcmd_option(&_name); |
190 | _dcmdparser.add_dcmd_option(&_filename); |
191 | _dcmdparser.add_dcmd_option(&_maxage); |
192 | _dcmdparser.add_dcmd_option(&_maxsize); |
193 | _dcmdparser.add_dcmd_option(&_begin); |
194 | _dcmdparser.add_dcmd_option(&_end); |
195 | _dcmdparser.add_dcmd_option(&_path_to_gc_roots); |
196 | }; |
197 | |
198 | int JfrDumpFlightRecordingDCmd::num_arguments() { |
199 | ResourceMark rm; |
200 | JfrDumpFlightRecordingDCmd* dcmd = new JfrDumpFlightRecordingDCmd(NULL, false); |
201 | if (dcmd != NULL) { |
202 | DCmdMark mark(dcmd); |
203 | return dcmd->_dcmdparser.num_arguments(); |
204 | } |
205 | return 0; |
206 | } |
207 | |
208 | void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { |
209 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
210 | |
211 | if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) { |
212 | return; |
213 | } |
214 | |
215 | ResourceMark rm(THREAD); |
216 | HandleMark hm(THREAD); |
217 | JNIHandleBlockManager jni_handle_management(THREAD); |
218 | |
219 | JavaValue result(T_OBJECT); |
220 | JfrJavaArguments constructor_args(&result); |
221 | constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdDump" , CHECK); |
222 | const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); |
223 | Handle h_dcmd_instance(THREAD, dcmd); |
224 | assert(h_dcmd_instance.not_null(), "invariant" ); |
225 | |
226 | jstring name = NULL; |
227 | if (_name.is_set() && _name.value() != NULL) { |
228 | name = JfrJavaSupport::new_string(_name.value(), CHECK); |
229 | } |
230 | |
231 | jstring filepath = NULL; |
232 | if (_filename.is_set() && _filename.value() != NULL) { |
233 | filepath = JfrJavaSupport::new_string(_filename.value(), CHECK); |
234 | } |
235 | |
236 | jobject maxage = NULL; |
237 | if (_maxage.is_set()) { |
238 | maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK); |
239 | } |
240 | |
241 | jobject maxsize = NULL; |
242 | if (_maxsize.is_set()) { |
243 | maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK); |
244 | } |
245 | |
246 | jstring begin = NULL; |
247 | if (_begin.is_set() && _begin.value() != NULL) { |
248 | begin = JfrJavaSupport::new_string(_begin.value(), CHECK); |
249 | } |
250 | |
251 | jstring end = NULL; |
252 | if (_end.is_set() && _end.value() != NULL) { |
253 | end = JfrJavaSupport::new_string(_end.value(), CHECK); |
254 | } |
255 | |
256 | jobject path_to_gc_roots = NULL; |
257 | if (_path_to_gc_roots.is_set()) { |
258 | path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK); |
259 | } |
260 | |
261 | static const char klass[] = "jdk/jfr/internal/dcmd/DCmdDump" ; |
262 | static const char method[] = "execute" ; |
263 | static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;" ; |
264 | |
265 | JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); |
266 | execute_args.set_receiver(h_dcmd_instance); |
267 | |
268 | // arguments |
269 | execute_args.push_jobject(name); |
270 | execute_args.push_jobject(filepath); |
271 | execute_args.push_jobject(maxage); |
272 | execute_args.push_jobject(maxsize); |
273 | execute_args.push_jobject(begin); |
274 | execute_args.push_jobject(end); |
275 | execute_args.push_jobject(path_to_gc_roots); |
276 | |
277 | JfrJavaSupport::call_virtual(&execute_args, THREAD); |
278 | handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD); |
279 | } |
280 | |
281 | JfrCheckFlightRecordingDCmd::JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), |
282 | _name("name" ,"Recording name, e.g. \\\"My Recording\\\" or omit to see all recordings" ,"STRING" ,false, NULL), |
283 | _verbose("verbose" ,"Print event settings for the recording(s)" ,"BOOLEAN" , |
284 | false, "false" ) { |
285 | _dcmdparser.add_dcmd_option(&_name); |
286 | _dcmdparser.add_dcmd_option(&_verbose); |
287 | }; |
288 | |
289 | int JfrCheckFlightRecordingDCmd::num_arguments() { |
290 | ResourceMark rm; |
291 | JfrCheckFlightRecordingDCmd* dcmd = new JfrCheckFlightRecordingDCmd(NULL, false); |
292 | if (dcmd != NULL) { |
293 | DCmdMark mark(dcmd); |
294 | return dcmd->_dcmdparser.num_arguments(); |
295 | } |
296 | return 0; |
297 | } |
298 | |
299 | void JfrCheckFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { |
300 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
301 | |
302 | if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) { |
303 | return; |
304 | } |
305 | |
306 | ResourceMark rm(THREAD); |
307 | HandleMark hm(THREAD); |
308 | JNIHandleBlockManager jni_handle_management(THREAD); |
309 | |
310 | JavaValue result(T_OBJECT); |
311 | JfrJavaArguments constructor_args(&result); |
312 | constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdCheck" , CHECK); |
313 | const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); |
314 | Handle h_dcmd_instance(THREAD, dcmd); |
315 | assert(h_dcmd_instance.not_null(), "invariant" ); |
316 | |
317 | jstring name = NULL; |
318 | if (_name.is_set() && _name.value() != NULL) { |
319 | name = JfrJavaSupport::new_string(_name.value(), CHECK); |
320 | } |
321 | |
322 | jobject verbose = NULL; |
323 | if (_verbose.is_set()) { |
324 | verbose = JfrJavaSupport::new_java_lang_Boolean(_verbose.value(), CHECK); |
325 | } |
326 | |
327 | static const char klass[] = "jdk/jfr/internal/dcmd/DCmdCheck" ; |
328 | static const char method[] = "execute" ; |
329 | static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;" ; |
330 | |
331 | JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); |
332 | execute_args.set_receiver(h_dcmd_instance); |
333 | |
334 | // arguments |
335 | execute_args.push_jobject(name); |
336 | execute_args.push_jobject(verbose); |
337 | |
338 | JfrJavaSupport::call_virtual(&execute_args, THREAD); |
339 | handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD); |
340 | } |
341 | |
342 | JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output, |
343 | bool heap) : DCmdWithParser(output, heap), |
344 | _name("name" , "Name that can be used to identify recording, e.g. \\\"My Recording\\\"" , "STRING" , false, NULL), |
345 | _settings("settings" , "Settings file(s), e.g. profile or default. See JRE_HOME/lib/jfr" , "STRING SET" , false), |
346 | _delay("delay" , "Delay recording start with (s)econds, (m)inutes), (h)ours), or (d)ays, e.g. 5h." , "NANOTIME" , false, "0" ), |
347 | _duration("duration" , "Duration of recording in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 300s." , "NANOTIME" , false, "0" ), |
348 | _disk("disk" , "Recording should be persisted to disk" , "BOOLEAN" , false), |
349 | _filename("filename" , "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"" , "STRING" , false), |
350 | _maxage("maxage" , "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit" , "NANOTIME" , false, "0" ), |
351 | _maxsize("maxsize" , "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit" , "MEMORY SIZE" , false, "0" ), |
352 | _dump_on_exit("dumponexit" , "Dump running recording when JVM shuts down" , "BOOLEAN" , false), |
353 | _path_to_gc_roots("path-to-gc-roots" , "Collect path to GC roots" , "BOOLEAN" , false, "false" ) { |
354 | _dcmdparser.add_dcmd_option(&_name); |
355 | _dcmdparser.add_dcmd_option(&_settings); |
356 | _dcmdparser.add_dcmd_option(&_delay); |
357 | _dcmdparser.add_dcmd_option(&_duration); |
358 | _dcmdparser.add_dcmd_option(&_disk); |
359 | _dcmdparser.add_dcmd_option(&_filename); |
360 | _dcmdparser.add_dcmd_option(&_maxage); |
361 | _dcmdparser.add_dcmd_option(&_maxsize); |
362 | _dcmdparser.add_dcmd_option(&_dump_on_exit); |
363 | _dcmdparser.add_dcmd_option(&_path_to_gc_roots); |
364 | }; |
365 | |
366 | int JfrStartFlightRecordingDCmd::num_arguments() { |
367 | ResourceMark rm; |
368 | JfrStartFlightRecordingDCmd* dcmd = new JfrStartFlightRecordingDCmd(NULL, false); |
369 | if (dcmd != NULL) { |
370 | DCmdMark mark(dcmd); |
371 | return dcmd->_dcmdparser.num_arguments(); |
372 | } |
373 | return 0; |
374 | } |
375 | |
376 | void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { |
377 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
378 | |
379 | if (invalid_state(output(), THREAD)) { |
380 | return; |
381 | } |
382 | |
383 | ResourceMark rm(THREAD); |
384 | HandleMark hm(THREAD); |
385 | JNIHandleBlockManager jni_handle_management(THREAD); |
386 | |
387 | JavaValue result(T_OBJECT); |
388 | JfrJavaArguments constructor_args(&result); |
389 | constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStart" , THREAD); |
390 | const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); |
391 | Handle h_dcmd_instance(THREAD, dcmd); |
392 | assert(h_dcmd_instance.not_null(), "invariant" ); |
393 | |
394 | jstring name = NULL; |
395 | if (_name.is_set() && _name.value() != NULL) { |
396 | name = JfrJavaSupport::new_string(_name.value(), CHECK); |
397 | } |
398 | |
399 | jstring filename = NULL; |
400 | if (_filename.is_set() && _filename.value() != NULL) { |
401 | filename = JfrJavaSupport::new_string(_filename.value(), CHECK); |
402 | } |
403 | |
404 | jobject maxage = NULL; |
405 | if (_maxage.is_set()) { |
406 | maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK); |
407 | } |
408 | |
409 | jobject maxsize = NULL; |
410 | if (_maxsize.is_set()) { |
411 | maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK); |
412 | } |
413 | |
414 | jobject duration = NULL; |
415 | if (_duration.is_set()) { |
416 | duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK); |
417 | } |
418 | |
419 | jobject delay = NULL; |
420 | if (_delay.is_set()) { |
421 | delay = JfrJavaSupport::new_java_lang_Long(_delay.value()._nanotime, CHECK); |
422 | } |
423 | |
424 | jobject disk = NULL; |
425 | if (_disk.is_set()) { |
426 | disk = JfrJavaSupport::new_java_lang_Boolean(_disk.value(), CHECK); |
427 | } |
428 | |
429 | jobject dump_on_exit = NULL; |
430 | if (_dump_on_exit.is_set()) { |
431 | dump_on_exit = JfrJavaSupport::new_java_lang_Boolean(_dump_on_exit.value(), CHECK); |
432 | } |
433 | |
434 | jobject path_to_gc_roots = NULL; |
435 | if (_path_to_gc_roots.is_set()) { |
436 | path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK); |
437 | } |
438 | |
439 | jobjectArray settings = NULL; |
440 | if (_settings.is_set()) { |
441 | int length = _settings.value()->array()->length(); |
442 | if (length == 1) { |
443 | const char* c_str = _settings.value()->array()->at(0); |
444 | if (strcmp(c_str, "none" ) == 0) { |
445 | length = 0; |
446 | } |
447 | } |
448 | settings = JfrJavaSupport::new_string_array(length, CHECK); |
449 | assert(settings != NULL, "invariant" ); |
450 | for (int i = 0; i < length; ++i) { |
451 | jobject element = JfrJavaSupport::new_string(_settings.value()->array()->at(i), CHECK); |
452 | assert(element != NULL, "invariant" ); |
453 | JfrJavaSupport::set_array_element(settings, element, i, CHECK); |
454 | } |
455 | } else { |
456 | settings = JfrJavaSupport::new_string_array(1, CHECK); |
457 | assert(settings != NULL, "invariant" ); |
458 | jobject element = JfrJavaSupport::new_string("default" , CHECK); |
459 | assert(element != NULL, "invariant" ); |
460 | JfrJavaSupport::set_array_element(settings, element, 0, CHECK); |
461 | } |
462 | |
463 | static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStart" ; |
464 | static const char method[] = "execute" ; |
465 | static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;" |
466 | "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;" |
467 | "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;" ; |
468 | |
469 | JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); |
470 | execute_args.set_receiver(h_dcmd_instance); |
471 | |
472 | // arguments |
473 | execute_args.push_jobject(name); |
474 | execute_args.push_jobject(settings); |
475 | execute_args.push_jobject(delay); |
476 | execute_args.push_jobject(duration); |
477 | execute_args.push_jobject(disk); |
478 | execute_args.push_jobject(filename); |
479 | execute_args.push_jobject(maxage); |
480 | execute_args.push_jobject(maxsize); |
481 | execute_args.push_jobject(dump_on_exit); |
482 | execute_args.push_jobject(path_to_gc_roots); |
483 | |
484 | JfrJavaSupport::call_virtual(&execute_args, THREAD); |
485 | handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD); |
486 | } |
487 | |
488 | JfrStopFlightRecordingDCmd::JfrStopFlightRecordingDCmd(outputStream* output, |
489 | bool heap) : DCmdWithParser(output, heap), |
490 | _name("name" , "Recording text,.e.g \\\"My Recording\\\"" , "STRING" , true, NULL), |
491 | _filename("filename" , "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"" , "STRING" , false, NULL) { |
492 | _dcmdparser.add_dcmd_option(&_name); |
493 | _dcmdparser.add_dcmd_option(&_filename); |
494 | }; |
495 | |
496 | int JfrStopFlightRecordingDCmd::num_arguments() { |
497 | ResourceMark rm; |
498 | JfrStopFlightRecordingDCmd* dcmd = new JfrStopFlightRecordingDCmd(NULL, false); |
499 | if (dcmd != NULL) { |
500 | DCmdMark mark(dcmd); |
501 | return dcmd->_dcmdparser.num_arguments(); |
502 | } |
503 | return 0; |
504 | } |
505 | |
506 | void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { |
507 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
508 | |
509 | if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) { |
510 | return; |
511 | } |
512 | |
513 | ResourceMark rm(THREAD); |
514 | HandleMark hm(THREAD); |
515 | JNIHandleBlockManager jni_handle_management(THREAD); |
516 | |
517 | JavaValue result(T_OBJECT); |
518 | JfrJavaArguments constructor_args(&result); |
519 | constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStop" , CHECK); |
520 | const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); |
521 | Handle h_dcmd_instance(THREAD, dcmd); |
522 | assert(h_dcmd_instance.not_null(), "invariant" ); |
523 | |
524 | jstring name = NULL; |
525 | if (_name.is_set() && _name.value() != NULL) { |
526 | name = JfrJavaSupport::new_string(_name.value(), CHECK); |
527 | } |
528 | |
529 | jstring filepath = NULL; |
530 | if (_filename.is_set() && _filename.value() != NULL) { |
531 | filepath = JfrJavaSupport::new_string(_filename.value(), CHECK); |
532 | } |
533 | |
534 | static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop" ; |
535 | static const char method[] = "execute" ; |
536 | static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" ; |
537 | |
538 | JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); |
539 | execute_args.set_receiver(h_dcmd_instance); |
540 | |
541 | // arguments |
542 | execute_args.push_jobject(name); |
543 | execute_args.push_jobject(filepath); |
544 | |
545 | JfrJavaSupport::call_virtual(&execute_args, THREAD); |
546 | handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD); |
547 | } |
548 | |
549 | JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output, |
550 | bool heap) : DCmdWithParser(output, heap), |
551 | _repository_path("repositorypath" , "Path to repository,.e.g \\\"My Repository\\\"" , "STRING" , false, NULL), |
552 | _dump_path("dumppath" , "Path to dump,.e.g \\\"My Dump path\\\"" , "STRING" , false, NULL), |
553 | _stack_depth("stackdepth" , "Stack Depth" , "JULONG" , false, "64" ), |
554 | _global_buffer_count("globalbuffercount" , "Number of global buffers," , "JULONG" , false, "20" ), |
555 | _global_buffer_size("globalbuffersize" , "Size of a global buffers," , "MEMORY SIZE" , false, "512k" ), |
556 | _thread_buffer_size("thread_buffer_size" , "Size of a thread buffer" , "MEMORY SIZE" , false, "8k" ), |
557 | _memory_size("memorysize" , "Overall memory size, " , "MEMORY SIZE" , false, "10m" ), |
558 | _max_chunk_size("maxchunksize" , "Size of an individual disk chunk" , "MEMORY SIZE" , false, "12m" ), |
559 | _sample_threads("samplethreads" , "Activate Thread sampling" , "BOOLEAN" , false, "true" ) { |
560 | _dcmdparser.add_dcmd_option(&_repository_path); |
561 | _dcmdparser.add_dcmd_option(&_dump_path); |
562 | _dcmdparser.add_dcmd_option(&_stack_depth); |
563 | _dcmdparser.add_dcmd_option(&_global_buffer_count); |
564 | _dcmdparser.add_dcmd_option(&_global_buffer_size); |
565 | _dcmdparser.add_dcmd_option(&_thread_buffer_size); |
566 | _dcmdparser.add_dcmd_option(&_memory_size); |
567 | _dcmdparser.add_dcmd_option(&_max_chunk_size); |
568 | _dcmdparser.add_dcmd_option(&_sample_threads); |
569 | }; |
570 | |
571 | int JfrConfigureFlightRecorderDCmd::num_arguments() { |
572 | ResourceMark rm; |
573 | JfrConfigureFlightRecorderDCmd* dcmd = new JfrConfigureFlightRecorderDCmd(NULL, false); |
574 | if (dcmd != NULL) { |
575 | DCmdMark mark(dcmd); |
576 | return dcmd->_dcmdparser.num_arguments(); |
577 | } |
578 | return 0; |
579 | } |
580 | |
581 | void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) { |
582 | DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
583 | |
584 | if (invalid_state(output(), THREAD)) { |
585 | return; |
586 | } |
587 | |
588 | ResourceMark rm(THREAD); |
589 | HandleMark hm(THREAD); |
590 | JNIHandleBlockManager jni_handle_management(THREAD); |
591 | |
592 | JavaValue result(T_OBJECT); |
593 | JfrJavaArguments constructor_args(&result); |
594 | constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdConfigure" , CHECK); |
595 | const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK); |
596 | Handle h_dcmd_instance(THREAD, dcmd); |
597 | assert(h_dcmd_instance.not_null(), "invariant" ); |
598 | |
599 | jstring repository_path = NULL; |
600 | if (_repository_path.is_set() && _repository_path.value() != NULL) { |
601 | repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK); |
602 | } |
603 | |
604 | jstring dump_path = NULL; |
605 | if (_dump_path.is_set() && _dump_path.value() != NULL) { |
606 | dump_path = JfrJavaSupport::new_string(_dump_path.value(), CHECK); |
607 | } |
608 | |
609 | jobject stack_depth = NULL; |
610 | if (_stack_depth.is_set()) { |
611 | stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK); |
612 | } |
613 | |
614 | jobject global_buffer_count = NULL; |
615 | if (_global_buffer_count.is_set()) { |
616 | global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK); |
617 | } |
618 | |
619 | jobject global_buffer_size = NULL; |
620 | if (_global_buffer_size.is_set()) { |
621 | global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value()._size, CHECK); |
622 | } |
623 | |
624 | jobject thread_buffer_size = NULL; |
625 | if (_thread_buffer_size.is_set()) { |
626 | thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value()._size, CHECK); |
627 | } |
628 | |
629 | jobject max_chunk_size = NULL; |
630 | if (_max_chunk_size.is_set()) { |
631 | max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value()._size, CHECK); |
632 | } |
633 | |
634 | jobject memory_size = NULL; |
635 | if (_memory_size.is_set()) { |
636 | memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value()._size, CHECK); |
637 | } |
638 | |
639 | jobject sample_threads = NULL; |
640 | if (_sample_threads.is_set()) { |
641 | sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK); |
642 | } |
643 | |
644 | static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure" ; |
645 | static const char method[] = "execute" ; |
646 | static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;" |
647 | "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;" |
648 | "Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;" ; |
649 | |
650 | JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); |
651 | execute_args.set_receiver(h_dcmd_instance); |
652 | |
653 | // params |
654 | execute_args.push_jobject(repository_path); |
655 | execute_args.push_jobject(dump_path); |
656 | execute_args.push_jobject(stack_depth); |
657 | execute_args.push_jobject(global_buffer_count); |
658 | execute_args.push_jobject(global_buffer_size); |
659 | execute_args.push_jobject(thread_buffer_size); |
660 | execute_args.push_jobject(memory_size); |
661 | execute_args.push_jobject(max_chunk_size); |
662 | execute_args.push_jobject(sample_threads); |
663 | |
664 | JfrJavaSupport::call_virtual(&execute_args, THREAD); |
665 | handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD); |
666 | } |
667 | |
668 | bool register_jfr_dcmds() { |
669 | uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; |
670 | DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrCheckFlightRecordingDCmd>(full_export, true, false)); |
671 | DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrDumpFlightRecordingDCmd>(full_export, true, false)); |
672 | DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStartFlightRecordingDCmd>(full_export, true, false)); |
673 | DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStopFlightRecordingDCmd>(full_export, true, false)); |
674 | DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrConfigureFlightRecorderDCmd>(full_export, true, false)); |
675 | return true; |
676 | } |
677 | |
678 | |