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