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