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 */ 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 "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" 38 39 struct ObsoleteOption { 40 const char* name; 41 const char* message; 42 }; 43 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 }; 55 56 jlong JfrOptionSet::max_chunk_size() { 57 return _max_chunk_size; 58 } 59 60 void JfrOptionSet::set_max_chunk_size(jlong value) { 61 _max_chunk_size = value; 62 } 63 64 jlong JfrOptionSet::global_buffer_size() { 65 return _global_buffer_size; 66 } 67 68 void JfrOptionSet::set_global_buffer_size(jlong value) { 69 _global_buffer_size = value; 70 } 71 72 jlong JfrOptionSet::thread_buffer_size() { 73 return _thread_buffer_size; 74 } 75 76 void JfrOptionSet::set_thread_buffer_size(jlong value) { 77 _thread_buffer_size = value; 78 } 79 80 jlong JfrOptionSet::memory_size() { 81 return _memory_size; 82 } 83 84 void JfrOptionSet::set_memory_size(jlong value) { 85 _memory_size = value; 86 } 87 88 jlong JfrOptionSet::num_global_buffers() { 89 return _num_global_buffers; 90 } 91 92 void JfrOptionSet::set_num_global_buffers(jlong value) { 93 _num_global_buffers = value; 94 } 95 96 jint JfrOptionSet::old_object_queue_size() { 97 return (jint)_old_object_queue_size; 98 } 99 100 void JfrOptionSet::set_old_object_queue_size(jlong value) { 101 _old_object_queue_size = value; 102 } 103 104 u4 JfrOptionSet::stackdepth() { 105 return _stack_depth; 106 } 107 108 static const u4 STACK_DEPTH_DEFAULT = 64; 109 static const u4 MIN_STACK_DEPTH = 1; 110 static const u4 MAX_STACK_DEPTH = 2048; 111 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 } 121 122 bool JfrOptionSet::sample_threads() { 123 return _sample_threads == JNI_TRUE; 124 } 125 126 void JfrOptionSet::set_sample_threads(jboolean sample) { 127 _sample_threads = sample; 128 } 129 130 bool JfrOptionSet::can_retransform() { 131 return _retransform == JNI_TRUE; 132 } 133 134 void JfrOptionSet::set_retransform(jboolean value) { 135 _retransform = value; 136 } 137 138 bool JfrOptionSet::sample_protection() { 139 return _sample_protection == JNI_TRUE; 140 } 141 142 #ifdef ASSERT 143 void JfrOptionSet::set_sample_protection(jboolean protection) { 144 _sample_protection = protection; 145 } 146 #endif 147 148 bool JfrOptionSet::compressed_integers() { 149 // Set this to false for debugging purposes. 150 return true; 151 } 152 153 bool JfrOptionSet::allow_retransforms() { 154 #if INCLUDE_JVMTI 155 return true; 156 #else 157 return false; 158 #endif 159 } 160 161 bool JfrOptionSet::allow_event_retransforms() { 162 return allow_retransforms() && (DumpSharedSpaces || can_retransform()); 163 } 164 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";) 177 178 // statics 179 static DCmdArgument<char*> _dcmd_repository( 180 "repository", 181 "Flight recorder disk repository location", 182 "STRING", 183 false, 184 default_repository); 185 186 static DCmdArgument<MemorySizeArgument> _dcmd_threadbuffersize( 187 "threadbuffersize", 188 "Thread buffer size", 189 "MEMORY SIZE", 190 false, 191 default_thread_buffer_size); 192 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); 199 200 static DCmdArgument<MemorySizeArgument> _dcmd_globalbuffersize( 201 "globalbuffersize", 202 "Global buffer size", 203 "MEMORY SIZE", 204 false, 205 default_global_buffer_size); 206 207 static DCmdArgument<jlong> _dcmd_numglobalbuffers( 208 "numglobalbuffers", 209 "Number of global buffers", 210 "JULONG", 211 false, 212 default_num_global_buffers); 213 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); 220 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); 227 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); 234 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 243 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); 250 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); 257 258 static DCmdParser _parser; 259 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 } 273 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 } 302 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 317 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 } 329 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 } 349 350 configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set()); 351 configure._stack_depth.set_value(_dcmd_stackdepth.value()); 352 353 configure._thread_buffer_size.set_is_set(_dcmd_threadbuffersize.is_set()); 354 configure._thread_buffer_size.set_value(_dcmd_threadbuffersize.value()._size); 355 356 configure._global_buffer_count.set_is_set(_dcmd_numglobalbuffers.is_set()); 357 configure._global_buffer_count.set_value(_dcmd_numglobalbuffers.value()); 358 359 configure._global_buffer_size.set_is_set(_dcmd_globalbuffersize.is_set()); 360 configure._global_buffer_size.set_value(_dcmd_globalbuffersize.value()._size); 361 362 configure._max_chunk_size.set_is_set(_dcmd_maxchunksize.is_set()); 363 configure._max_chunk_size.set_value(_dcmd_maxchunksize.value()._size); 364 365 configure._memory_size.set_is_set(_dcmd_memorysize.is_set()); 366 configure._memory_size.set_value(_dcmd_memorysize.value()._size); 367 368 configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set()); 369 configure._sample_threads.set_value(_dcmd_sample_threads.value()); 370 371 configure.execute(DCmd_Source_Internal, THREAD); 372 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 } 380 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 } 395 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 } 410 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 } 426 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 } 447 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 } 476 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 } 490 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 } 513 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 } 526 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 } 547 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()); 565 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; 570 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; 575 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; 580 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 } 591 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 } 607 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 } 617 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 } 642 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 } 666 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 } 681 682 static GrowableArray<const char*>* startup_recording_options_array = NULL; 683 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); 704 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 } 715 716 const GrowableArray<const char*>* JfrOptionSet::startup_recording_options() { 717 return startup_recording_options_array; 718 } 719 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 }