Fri, 23 Nov 2018 16:36:07 +0900
8213015: Inconsistent settings between JFR.configure and -XX:FlightRecorderOptions
Reviewed-by: mgronlun, egahlin
1 /*
2 * Copyright (c) 2012, 2018, 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 */
25 #include "precompiled.hpp"
26 #include "jfr/dcmd/jfrDcmds.hpp"
27 #include "jfr/recorder/service/jfrMemorySizer.hpp"
28 #include "jfr/recorder/service/jfrOptionSet.hpp"
29 #include "jfr/utilities/jfrAllocation.hpp"
30 #include "memory/allocation.inline.hpp"
31 #include "memory/resourceArea.hpp"
32 #include "runtime/java.hpp"
33 #include "runtime/thread.inline.hpp"
34 #include "services/diagnosticArgument.hpp"
35 #include "services/diagnosticFramework.hpp"
36 #include "utilities/growableArray.hpp"
37 #include "utilities/ostream.hpp"
39 struct ObsoleteOption {
40 const char* name;
41 const char* message;
42 };
44 static const ObsoleteOption OBSOLETE_OPTIONS[] = {
45 {"checkpointbuffersize", ""},
46 {"maxsize", "Use -XX:StartFlightRecording=maxsize=... instead."},
47 {"maxage", "Use -XX:StartFlightRecording=maxage=... instead."},
48 {"settings", "Use -XX:StartFlightRecording=settings=... instead."},
49 {"defaultrecording", "Use -XX:StartFlightRecording=disk=false to create an in-memory recording."},
50 {"disk", "Use -XX:StartFlightRecording=disk=... instead."},
51 {"dumponexit", "Use -XX:StartFlightRecording=dumponexit=... instead."},
52 {"dumponexitpath", "Use -XX:StartFlightRecording=filename=... instead."},
53 {"loglevel", "Use -Xlog:jfr=... instead."}
54 };
56 jlong JfrOptionSet::max_chunk_size() {
57 return _max_chunk_size;
58 }
60 void JfrOptionSet::set_max_chunk_size(jlong value) {
61 _max_chunk_size = value;
62 }
64 jlong JfrOptionSet::global_buffer_size() {
65 return _global_buffer_size;
66 }
68 void JfrOptionSet::set_global_buffer_size(jlong value) {
69 _global_buffer_size = value;
70 }
72 jlong JfrOptionSet::thread_buffer_size() {
73 return _thread_buffer_size;
74 }
76 void JfrOptionSet::set_thread_buffer_size(jlong value) {
77 _thread_buffer_size = value;
78 }
80 jlong JfrOptionSet::memory_size() {
81 return _memory_size;
82 }
84 void JfrOptionSet::set_memory_size(jlong value) {
85 _memory_size = value;
86 }
88 jlong JfrOptionSet::num_global_buffers() {
89 return _num_global_buffers;
90 }
92 void JfrOptionSet::set_num_global_buffers(jlong value) {
93 _num_global_buffers = value;
94 }
96 jint JfrOptionSet::old_object_queue_size() {
97 return (jint)_old_object_queue_size;
98 }
100 void JfrOptionSet::set_old_object_queue_size(jlong value) {
101 _old_object_queue_size = value;
102 }
104 u4 JfrOptionSet::stackdepth() {
105 return _stack_depth;
106 }
108 static const u4 STACK_DEPTH_DEFAULT = 64;
109 static const u4 MIN_STACK_DEPTH = 1;
110 static const u4 MAX_STACK_DEPTH = 2048;
112 void JfrOptionSet::set_stackdepth(u4 depth) {
113 if (depth < MIN_STACK_DEPTH) {
114 _stack_depth = MIN_STACK_DEPTH;
115 } else if (depth > MAX_STACK_DEPTH) {
116 _stack_depth = MAX_STACK_DEPTH;
117 } else {
118 _stack_depth = depth;
119 }
120 }
122 bool JfrOptionSet::sample_threads() {
123 return _sample_threads == JNI_TRUE;
124 }
126 void JfrOptionSet::set_sample_threads(jboolean sample) {
127 _sample_threads = sample;
128 }
130 bool JfrOptionSet::can_retransform() {
131 return _retransform == JNI_TRUE;
132 }
134 void JfrOptionSet::set_retransform(jboolean value) {
135 _retransform = value;
136 }
138 bool JfrOptionSet::sample_protection() {
139 return _sample_protection == JNI_TRUE;
140 }
142 #ifdef ASSERT
143 void JfrOptionSet::set_sample_protection(jboolean protection) {
144 _sample_protection = protection;
145 }
146 #endif
148 bool JfrOptionSet::compressed_integers() {
149 // Set this to false for debugging purposes.
150 return true;
151 }
153 bool JfrOptionSet::allow_retransforms() {
154 #if INCLUDE_JVMTI
155 return true;
156 #else
157 return false;
158 #endif
159 }
161 bool JfrOptionSet::allow_event_retransforms() {
162 return allow_retransforms() && (DumpSharedSpaces || can_retransform());
163 }
165 // default options for the dcmd parser
166 const char* const default_repository = NULL;
167 const char* const default_global_buffer_size = "512k";
168 const char* const default_num_global_buffers = "20";
169 const char* const default_memory_size = "10m";
170 const char* const default_thread_buffer_size = "8k";
171 const char* const default_max_chunk_size = "12m";
172 const char* const default_sample_threads = "true";
173 const char* const default_stack_depth = "64";
174 const char* const default_retransform = "true";
175 const char* const default_old_object_queue_size = "256";
176 DEBUG_ONLY(const char* const default_sample_protection = "false";)
178 // statics
179 static DCmdArgument<char*> _dcmd_repository(
180 "repository",
181 "Flight recorder disk repository location",
182 "STRING",
183 false,
184 default_repository);
186 static DCmdArgument<MemorySizeArgument> _dcmd_threadbuffersize(
187 "threadbuffersize",
188 "Thread buffer size",
189 "MEMORY SIZE",
190 false,
191 default_thread_buffer_size);
193 static DCmdArgument<MemorySizeArgument> _dcmd_memorysize(
194 "memorysize",
195 "Size of memory to be used by Flight Recorder",
196 "MEMORY SIZE",
197 false,
198 default_memory_size);
200 static DCmdArgument<MemorySizeArgument> _dcmd_globalbuffersize(
201 "globalbuffersize",
202 "Global buffer size",
203 "MEMORY SIZE",
204 false,
205 default_global_buffer_size);
207 static DCmdArgument<jlong> _dcmd_numglobalbuffers(
208 "numglobalbuffers",
209 "Number of global buffers",
210 "JULONG",
211 false,
212 default_num_global_buffers);
214 static DCmdArgument<MemorySizeArgument> _dcmd_maxchunksize(
215 "maxchunksize",
216 "Maximum size of a single repository disk chunk",
217 "MEMORY SIZE",
218 false,
219 default_max_chunk_size);
221 static DCmdArgument<jlong> _dcmd_old_object_queue_size (
222 "old-object-queue-size",
223 "Maximum number of old objects to track",
224 "JINT",
225 false,
226 default_old_object_queue_size);
228 static DCmdArgument<bool> _dcmd_sample_threads(
229 "samplethreads",
230 "Thread sampling enable / disable (only sampling when event enabled and sampling enabled)",
231 "BOOLEAN",
232 false,
233 default_sample_threads);
235 #ifdef ASSERT
236 static DCmdArgument<bool> _dcmd_sample_protection(
237 "sampleprotection",
238 "Safeguard for stackwalking while sampling threads (false by default)",
239 "BOOLEAN",
240 false,
241 default_sample_protection);
242 #endif
244 static DCmdArgument<jlong> _dcmd_stackdepth(
245 "stackdepth",
246 "Stack depth for stacktraces (minimum 1, maximum 2048)",
247 "JULONG",
248 false,
249 default_stack_depth);
251 static DCmdArgument<bool> _dcmd_retransform(
252 "retransform",
253 "If event classes should be instrumented using JVMTI (by default true)",
254 "BOOLEAN",
255 true,
256 default_retransform);
258 static DCmdParser _parser;
260 static void register_parser_options() {
261 _parser.add_dcmd_option(&_dcmd_repository);
262 _parser.add_dcmd_option(&_dcmd_threadbuffersize);
263 _parser.add_dcmd_option(&_dcmd_memorysize);
264 _parser.add_dcmd_option(&_dcmd_globalbuffersize);
265 _parser.add_dcmd_option(&_dcmd_numglobalbuffers);
266 _parser.add_dcmd_option(&_dcmd_maxchunksize);
267 _parser.add_dcmd_option(&_dcmd_stackdepth);
268 _parser.add_dcmd_option(&_dcmd_sample_threads);
269 _parser.add_dcmd_option(&_dcmd_retransform);
270 _parser.add_dcmd_option(&_dcmd_old_object_queue_size);
271 DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
272 }
274 static bool parse_flight_recorder_options_internal(TRAPS) {
275 if (FlightRecorderOptions == NULL) {
276 return true;
277 }
278 const size_t length = strlen((const char*)FlightRecorderOptions);
279 CmdLine cmdline((const char*)FlightRecorderOptions, length, true);
280 _parser.parse(&cmdline, ',', THREAD);
281 if (HAS_PENDING_EXCEPTION) {
282 for (int index = 0; index < 9; index++) {
283 ObsoleteOption option = OBSOLETE_OPTIONS[index];
284 const char* p = strstr((const char*)FlightRecorderOptions, option.name);
285 const size_t option_length = strlen(option.name);
286 if (p != NULL && p[option_length] == '=') {
287 tty->print_cr("-XX:FlightRecorderOptions=%s=... has been removed. %s", option.name, option.message);
288 return false;
289 }
290 }
291 ResourceMark rm(THREAD);
292 oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
293 if (message != NULL) {
294 const char* msg = java_lang_String::as_utf8_string(message);
295 tty->print_cr("%s", msg);
296 }
297 CLEAR_PENDING_EXCEPTION;
298 return false;
299 }
300 return true;
301 }
303 jlong JfrOptionSet::_max_chunk_size = 0;
304 jlong JfrOptionSet::_global_buffer_size = 0;
305 jlong JfrOptionSet::_thread_buffer_size = 0;
306 jlong JfrOptionSet::_memory_size = 0;
307 jlong JfrOptionSet::_num_global_buffers = 0;
308 jlong JfrOptionSet::_old_object_queue_size = 0;
309 u4 JfrOptionSet::_stack_depth = STACK_DEPTH_DEFAULT;
310 jboolean JfrOptionSet::_sample_threads = JNI_TRUE;
311 jboolean JfrOptionSet::_retransform = JNI_TRUE;
312 #ifdef ASSERT
313 jboolean JfrOptionSet::_sample_protection = JNI_FALSE;
314 #else
315 jboolean JfrOptionSet::_sample_protection = JNI_TRUE;
316 #endif
318 bool JfrOptionSet::initialize(Thread* thread) {
319 register_parser_options();
320 if (!parse_flight_recorder_options_internal(thread)) {
321 return false;
322 }
323 if (_dcmd_retransform.is_set()) {
324 set_retransform(_dcmd_retransform.value());
325 }
326 set_old_object_queue_size(_dcmd_old_object_queue_size.value());
327 return adjust_memory_options();
328 }
330 bool JfrOptionSet::configure(TRAPS) {
331 if (FlightRecorderOptions == NULL) {
332 return true;
333 }
334 ResourceMark rm(THREAD);
335 bufferedStream st;
336 // delegate to DCmd execution
337 JfrConfigureFlightRecorderDCmd configure(&st, false);
338 configure._repository_path.set_is_set(_dcmd_repository.is_set());
339 char* repo = _dcmd_repository.value();
340 if (repo != NULL) {
341 const size_t len = strlen(repo);
342 char* repo_copy = JfrCHeapObj::new_array<char>(len + 1);
343 if (NULL == repo_copy) {
344 return false;
345 }
346 strncpy(repo_copy, repo, len + 1);
347 configure._repository_path.set_value(repo_copy);
348 }
350 configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set());
351 configure._stack_depth.set_value(_dcmd_stackdepth.value());
353 configure._thread_buffer_size.set_is_set(_dcmd_threadbuffersize.is_set());
354 configure._thread_buffer_size.set_value(_dcmd_threadbuffersize.value());
356 configure._global_buffer_count.set_is_set(_dcmd_numglobalbuffers.is_set());
357 configure._global_buffer_count.set_value(_dcmd_numglobalbuffers.value());
359 configure._global_buffer_size.set_is_set(_dcmd_globalbuffersize.is_set());
360 configure._global_buffer_size.set_value(_dcmd_globalbuffersize.value());
362 configure._max_chunk_size.set_is_set(_dcmd_maxchunksize.is_set());
363 configure._max_chunk_size.set_value(_dcmd_maxchunksize.value());
365 configure._memory_size.set_is_set(_dcmd_memorysize.is_set());
366 configure._memory_size.set_value(_dcmd_memorysize.value());
368 configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
369 configure._sample_threads.set_value(_dcmd_sample_threads.value());
371 configure.execute(DCmd_Source_Internal, THREAD);
373 if (HAS_PENDING_EXCEPTION) {
374 java_lang_Throwable::print(PENDING_EXCEPTION, tty);
375 CLEAR_PENDING_EXCEPTION;
376 return false;
377 }
378 return true;
379 }
381 template <typename Argument>
382 static julong divide_with_user_unit(Argument& memory_argument, julong value) {
383 if (memory_argument.value()._size != memory_argument.value()._val) {
384 switch (memory_argument.value()._multiplier) {
385 case 'k': case 'K':
386 return value / K;
387 case 'm': case 'M':
388 return value / M;
389 case 'g': case 'G':
390 return value / G;
391 }
392 }
393 return value;
394 }
396 template <typename Argument>
397 static void log_lower_than_min_value(Argument& memory_argument, julong min_value) {
398 if (memory_argument.value()._size != memory_argument.value()._val) {
399 // has multiplier
400 tty->print_cr(
401 "This value is lower than the minimum size required " JULONG_FORMAT "%c",
402 divide_with_user_unit(memory_argument, min_value),
403 memory_argument.value()._multiplier);
404 return;
405 }
406 tty->print_cr(
407 "This value is lower than the minimum size required " JULONG_FORMAT,
408 divide_with_user_unit(memory_argument, min_value));
409 }
411 template <typename Argument>
412 static void log_set_value(Argument& memory_argument) {
413 if (memory_argument.value()._size != memory_argument.value()._val) {
414 // has multiplier
415 tty->print_cr(
416 "Value specified for option \"%s\" is " JULONG_FORMAT "%c",
417 memory_argument.name(),
418 memory_argument.value()._val,
419 memory_argument.value()._multiplier);
420 return;
421 }
422 tty->print_cr(
423 "Value specified for option \"%s\" is " JULONG_FORMAT,
424 memory_argument.name(), memory_argument.value()._val);
425 }
427 template <typename MemoryArg>
428 static void log_adjustments(MemoryArg& original_memory_size, julong new_memory_size, const char* msg) {
429 if (LogJFR && Verbose) tty->print_cr(
430 "%s size (original) " JULONG_FORMAT " B (user defined: %s)",
431 msg,
432 original_memory_size.value()._size,
433 original_memory_size.is_set() ? "true" : "false");
434 if (LogJFR && Verbose) tty->print_cr(
435 "%s size (adjusted) " JULONG_FORMAT " B (modified: %s)",
436 msg,
437 new_memory_size,
438 original_memory_size.value()._size != new_memory_size ? "true" : "false");
439 if (LogJFR && Verbose) tty->print_cr(
440 "%s size (adjustment) %s" JULONG_FORMAT " B",
441 msg,
442 new_memory_size < original_memory_size.value()._size ? "-" : "+",
443 new_memory_size < original_memory_size.value()._size ?
444 original_memory_size.value()._size - new_memory_size :
445 new_memory_size - original_memory_size.value()._size);
446 }
448 // All "triangular" options are explicitly set
449 // check that they are congruent and not causing
450 // an ambiguous situtation
451 template <typename MemoryArg, typename NumberArg>
452 static bool check_for_ambiguity(MemoryArg& memory_size, MemoryArg& global_buffer_size, NumberArg& num_global_buffers) {
453 assert(memory_size.is_set(), "invariant");
454 assert(global_buffer_size.is_set(), "invariant");
455 assert(num_global_buffers.is_set(), "invariant");
456 const julong calc_size = global_buffer_size.value()._size * (julong)num_global_buffers.value();
457 if (calc_size != memory_size.value()._size) {
458 // ambiguous
459 log_set_value(global_buffer_size);
460 tty->print_cr(
461 "Value specified for option \"%s\" is " JLONG_FORMAT,
462 num_global_buffers.name(), num_global_buffers.value());
463 log_set_value(memory_size);
464 tty->print_cr(
465 "These values are causing an ambiguity when trying to determine how much memory to use");
466 tty->print_cr("\"%s\" * \"%s\" do not equal \"%s\"",
467 global_buffer_size.name(),
468 num_global_buffers.name(),
469 memory_size.name());
470 tty->print_cr(
471 "Try to remove one of the involved options or make sure they are unambigous");
472 return false;
473 }
474 return true;
475 }
477 template <typename Argument>
478 static bool ensure_minimum_count(Argument& buffer_count_argument, jlong min_count) {
479 if (buffer_count_argument.value() < min_count) {
480 tty->print_cr(
481 "Value specified for option \"%s\" is " JLONG_FORMAT,
482 buffer_count_argument.name(), buffer_count_argument.value());
483 tty->print_cr(
484 "This value is lower than the minimum required number " JLONG_FORMAT,
485 min_count);
486 return false;
487 }
488 return true;
489 }
491 // global buffer size and num global buffers specified
492 // ensure that particular combination to be ihigher than minimum memory size
493 template <typename MemoryArg, typename NumberArg>
494 static bool ensure_calculated_gteq(MemoryArg& global_buffer_size, NumberArg& num_global_buffers, julong min_value) {
495 assert(global_buffer_size.is_set(), "invariant");
496 assert(num_global_buffers.is_set(), "invariant");
497 const julong calc_size = global_buffer_size.value()._size * (julong)num_global_buffers.value();
498 if (calc_size < min_value) {
499 log_set_value(global_buffer_size);
500 tty->print_cr(
501 "Value specified for option \"%s\" is " JLONG_FORMAT,
502 num_global_buffers.name(), num_global_buffers.value());
503 tty->print_cr("\"%s\" * \"%s\" (" JULONG_FORMAT
504 ") is lower than minimum memory size required " JULONG_FORMAT,
505 global_buffer_size.name(),
506 num_global_buffers.name(),
507 calc_size,
508 min_value);
509 return false;
510 }
511 return true;
512 }
514 template <typename Argument>
515 static bool ensure_first_gteq_second(Argument& first_argument, Argument& second_argument) {
516 if (second_argument.value()._size > first_argument.value()._size) {
517 log_set_value(first_argument);
518 log_set_value(second_argument);
519 tty->print_cr(
520 "The value for option \"%s\" should not be larger than the value specified for option \"%s\"",
521 second_argument.name(), first_argument.name());
522 return false;
523 }
524 return true;
525 }
527 static bool valid_memory_relations(const JfrMemoryOptions& options) {
528 if (options.global_buffer_size_configured) {
529 if (options.memory_size_configured) {
530 if (!ensure_first_gteq_second(_dcmd_memorysize, _dcmd_globalbuffersize)) {
531 return false;
532 }
533 }
534 if (options.thread_buffer_size_configured) {
535 if (!ensure_first_gteq_second(_dcmd_globalbuffersize, _dcmd_threadbuffersize)) {
536 return false;
537 }
538 }
539 if (options.buffer_count_configured) {
540 if (!ensure_calculated_gteq(_dcmd_globalbuffersize, _dcmd_numglobalbuffers, MIN_MEMORY_SIZE)) {
541 return false;
542 }
543 }
544 }
545 return true;
546 }
548 static void post_process_adjusted_memory_options(const JfrMemoryOptions& options) {
549 assert(options.memory_size >= MIN_MEMORY_SIZE, "invariant");
550 assert(options.global_buffer_size >= MIN_GLOBAL_BUFFER_SIZE, "invariant");
551 assert(options.buffer_count >= MIN_BUFFER_COUNT, "invariant");
552 assert(options.thread_buffer_size >= MIN_THREAD_BUFFER_SIZE, "invariant");
553 log_adjustments(_dcmd_memorysize, options.memory_size, "Memory");
554 log_adjustments(_dcmd_globalbuffersize, options.global_buffer_size, "Global buffer");
555 log_adjustments(_dcmd_threadbuffersize, options.thread_buffer_size, "Thread local buffer");
556 if (LogJFR && Verbose) tty->print_cr("Number of global buffers (original) " JLONG_FORMAT " (user defined: %s)",
557 _dcmd_numglobalbuffers.value(),
558 _dcmd_numglobalbuffers.is_set() ? "true" : "false");
559 if (LogJFR && Verbose) tty->print_cr( "Number of global buffers (adjusted) " JULONG_FORMAT " (modified: %s)",
560 options.buffer_count,
561 _dcmd_numglobalbuffers.value() != (jlong)options.buffer_count ? "true" : "false");
562 if (LogJFR && Verbose) tty->print_cr("Number of global buffers (adjustment) %s" JLONG_FORMAT,
563 (jlong)options.buffer_count < _dcmd_numglobalbuffers.value() ? "" : "+",
564 (jlong)options.buffer_count - _dcmd_numglobalbuffers.value());
566 MemorySizeArgument adjusted_memory_size;
567 adjusted_memory_size._val = divide_with_user_unit(_dcmd_memorysize, options.memory_size);
568 adjusted_memory_size._multiplier = _dcmd_memorysize.value()._multiplier;
569 adjusted_memory_size._size = options.memory_size;
571 MemorySizeArgument adjusted_global_buffer_size;
572 adjusted_global_buffer_size._val = divide_with_user_unit(_dcmd_globalbuffersize, options.global_buffer_size);
573 adjusted_global_buffer_size._multiplier = _dcmd_globalbuffersize.value()._multiplier;
574 adjusted_global_buffer_size._size = options.global_buffer_size;
576 MemorySizeArgument adjusted_thread_buffer_size;
577 adjusted_thread_buffer_size._val = divide_with_user_unit(_dcmd_threadbuffersize, options.thread_buffer_size);
578 adjusted_thread_buffer_size._multiplier = _dcmd_threadbuffersize.value()._multiplier;
579 adjusted_thread_buffer_size._size = options.thread_buffer_size;
581 // store back to dcmd
582 _dcmd_memorysize.set_value(adjusted_memory_size);
583 _dcmd_memorysize.set_is_set(true);
584 _dcmd_globalbuffersize.set_value(adjusted_global_buffer_size);
585 _dcmd_globalbuffersize.set_is_set(true);
586 _dcmd_numglobalbuffers.set_value((jlong)options.buffer_count);
587 _dcmd_numglobalbuffers.set_is_set(true);
588 _dcmd_threadbuffersize.set_value(adjusted_thread_buffer_size);
589 _dcmd_threadbuffersize.set_is_set(true);
590 }
592 static void initialize_memory_options_from_dcmd(JfrMemoryOptions& options) {
593 options.memory_size = _dcmd_memorysize.value()._size;
594 options.global_buffer_size = MAX2<julong>(_dcmd_globalbuffersize.value()._size, (julong)os::vm_page_size());
595 options.buffer_count = (julong)_dcmd_numglobalbuffers.value();
596 options.thread_buffer_size = MAX2<julong>(_dcmd_threadbuffersize.value()._size, (julong)os::vm_page_size());
597 // determine which options have been explicitly set
598 options.memory_size_configured = _dcmd_memorysize.is_set();
599 options.global_buffer_size_configured = _dcmd_globalbuffersize.is_set();
600 options.buffer_count_configured = _dcmd_numglobalbuffers.is_set();
601 options.thread_buffer_size_configured = _dcmd_threadbuffersize.is_set();
602 assert(options.memory_size >= MIN_MEMORY_SIZE, "invariant");
603 assert(options.global_buffer_size >= MIN_GLOBAL_BUFFER_SIZE, "invariant");
604 assert(options.buffer_count >= MIN_BUFFER_COUNT, "invariant");
605 assert(options.thread_buffer_size >= MIN_THREAD_BUFFER_SIZE, "invariant");
606 }
608 template <typename Argument>
609 static bool ensure_gteq(Argument& memory_argument, const jlong value) {
610 if ((jlong)memory_argument.value()._size < value) {
611 log_set_value(memory_argument);
612 log_lower_than_min_value(memory_argument, value);
613 return false;
614 }
615 return true;
616 }
618 static bool ensure_valid_minimum_sizes() {
619 // ensure valid minimum memory sizes
620 if (_dcmd_memorysize.is_set()) {
621 if (!ensure_gteq(_dcmd_memorysize, MIN_MEMORY_SIZE)) {
622 return false;
623 }
624 }
625 if (_dcmd_globalbuffersize.is_set()) {
626 if (!ensure_gteq(_dcmd_globalbuffersize, MIN_GLOBAL_BUFFER_SIZE)) {
627 return false;
628 }
629 }
630 if (_dcmd_numglobalbuffers.is_set()) {
631 if (!ensure_minimum_count(_dcmd_numglobalbuffers, MIN_BUFFER_COUNT)) {
632 return false;
633 }
634 }
635 if (_dcmd_threadbuffersize.is_set()) {
636 if (!ensure_gteq(_dcmd_threadbuffersize, MIN_THREAD_BUFFER_SIZE)) {
637 return false;
638 }
639 }
640 return true;
641 }
643 /**
644 * Starting with the initial set of memory values from the user,
645 * sanitize, enforce min/max rules and adjust to a set of consistent options.
646 *
647 * Adjusted memory sizes will be page aligned.
648 */
649 bool JfrOptionSet::adjust_memory_options() {
650 if (!ensure_valid_minimum_sizes()) {
651 return false;
652 }
653 JfrMemoryOptions options;
654 initialize_memory_options_from_dcmd(options);
655 if (!valid_memory_relations(options)) {
656 return false;
657 }
658 if (!JfrMemorySizer::adjust_options(&options)) {
659 if (!check_for_ambiguity(_dcmd_memorysize, _dcmd_globalbuffersize, _dcmd_numglobalbuffers)) {
660 return false;
661 }
662 }
663 post_process_adjusted_memory_options(options);
664 return true;
665 }
667 bool JfrOptionSet::parse_flight_recorder_option(const JavaVMOption** option, char* delimiter) {
668 assert(option != NULL, "invariant");
669 assert(delimiter != NULL, "invariant");
670 assert((*option)->optionString != NULL, "invariant");
671 assert(strncmp((*option)->optionString, "-XX:FlightRecorderOptions", 25) == 0, "invariant");
672 if (*delimiter == '\0') {
673 // -XX:FlightRecorderOptions without any delimiter and values
674 } else {
675 // -XX:FlightRecorderOptions[=|:]
676 // set delimiter to '='
677 *delimiter = '=';
678 }
679 return false;
680 }
682 static GrowableArray<const char*>* startup_recording_options_array = NULL;
684 bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter) {
685 assert(option != NULL, "invariant");
686 assert(delimiter != NULL, "invariant");
687 assert((*option)->optionString != NULL, "invariant");
688 assert(strncmp((*option)->optionString, "-XX:StartFlightRecording", 24) == 0, "invariant");
689 const char* value = NULL;
690 if (*delimiter == '\0') {
691 // -XX:StartFlightRecording without any delimiter and values
692 // Add dummy value "dumponexit=false" so -XX:StartFlightRecording can be used without explicit values.
693 // The existing option->optionString points to stack memory so no need to deallocate.
694 const_cast<JavaVMOption*>(*option)->optionString = (char*)"-XX:StartFlightRecording=dumponexit=false";
695 value = (*option)->optionString + 25;
696 } else {
697 // -XX:StartFlightRecording[=|:]
698 // set delimiter to '='
699 *delimiter = '=';
700 value = delimiter + 1;
701 }
702 assert(value != NULL, "invariant");
703 const size_t value_length = strlen(value);
705 if (startup_recording_options_array == NULL) {
706 startup_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray<const char*>(8, true, mtTracing);
707 }
708 assert(startup_recording_options_array != NULL, "invariant");
709 char* const startup_value = NEW_C_HEAP_ARRAY(char, value_length + 1, mtTracing);
710 strncpy(startup_value, value, value_length + 1);
711 assert(strncmp(startup_value, value, value_length) == 0, "invariant");
712 startup_recording_options_array->append(startup_value);
713 return false;
714 }
716 const GrowableArray<const char*>* JfrOptionSet::startup_recording_options() {
717 return startup_recording_options_array;
718 }
720 void JfrOptionSet::release_startup_recording_options() {
721 if (startup_recording_options_array != NULL) {
722 const int length = startup_recording_options_array->length();
723 for (int i = 0; i < length; ++i) {
724 FREE_C_HEAP_ARRAY(char, startup_recording_options_array->at(i), mtTracing);
725 }
726 delete startup_recording_options_array;
727 startup_recording_options_array = NULL;
728 }
729 }