src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp
changeset 50113 caf115bb98ad
child 50664 857ce291c70c
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     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/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         log_error(arguments) ("-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       log_error(arguments) ("%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     log_error(arguments) (
       
   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   log_error(arguments) (
       
   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     log_error(arguments) (
       
   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   log_error(arguments) (
       
   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   log_trace(arguments) (
       
   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   log_trace(arguments) (
       
   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   log_trace(arguments) (
       
   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     log_error(arguments) (
       
   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     log_error(arguments) (
       
   465       "These values are causing an ambiguity when trying to determine how much memory to use");
       
   466     log_error(arguments) ("\"%s\" * \"%s\" do not equal \"%s\"",
       
   467       global_buffer_size.name(),
       
   468       num_global_buffers.name(),
       
   469       memory_size.name());
       
   470     log_error(arguments) (
       
   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     log_error(arguments) (
       
   481       "Value specified for option \"%s\" is " JLONG_FORMAT,
       
   482       buffer_count_argument.name(), buffer_count_argument.value());
       
   483     log_error(arguments) (
       
   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     log_error(arguments) (
       
   501       "Value specified for option \"%s\" is " JLONG_FORMAT,
       
   502       num_global_buffers.name(), num_global_buffers.value());
       
   503     log_error(arguments) ("\"%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     log_error(arguments) (
       
   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   log_trace(arguments) ("Number of global buffers (original) " JLONG_FORMAT " (user defined: %s)",
       
   557     _dcmd_numglobalbuffers.value(),
       
   558     _dcmd_numglobalbuffers.is_set() ? "true" : "false");
       
   559   log_trace(arguments) ( "Number of global buffers (adjusted) " JULONG_FORMAT " (modified: %s)",
       
   560     options.buffer_count,
       
   561     _dcmd_numglobalbuffers.value() != (jlong)options.buffer_count ? "true" : "false");
       
   562   log_trace(arguments) ("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 /*
       
   668 
       
   669 to support starting multiple startup recordings
       
   670 
       
   671 static const char* start_flight_recording_option_original = NULL;
       
   672 static const char* flight_recorder_option_original = NULL;
       
   673 
       
   674 static void copy_option_string(const JavaVMOption* option, const char** addr) {
       
   675   assert(option != NULL, "invariant");
       
   676   assert(option->optionString != NULL, "invariant");
       
   677   const size_t length = strlen(option->optionString);
       
   678   *addr = JfrCHeapObj::new_array<char>(length + 1);
       
   679   assert(*addr != NULL, "invarinat");
       
   680   strncpy((char*)*addr, option->optionString, length + 1);
       
   681   assert(strncmp(*addr, option->optionString, length + 1) == 0, "invariant");
       
   682 }
       
   683 
       
   684 copy_option_string(*option, &start_flight_recording_option_original);
       
   685 copy_option_string(*option, &flight_recorder_option_original);
       
   686 */
       
   687 
       
   688 bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* tail) {
       
   689   assert(option != NULL, "invariant");
       
   690   assert(tail != NULL, "invariant");
       
   691   assert((*option)->optionString != NULL, "invariant");
       
   692   assert(strncmp((*option)->optionString, "-XX:StartFlightRecording", 24) == 0, "invariant");
       
   693   if (*tail == '\0') {
       
   694     // Add dummy dumponexit=false so -XX:StartFlightRecording can be used without a parameter.
       
   695     // The existing option->optionString points to stack memory so no need to deallocate.
       
   696     const_cast<JavaVMOption*>(*option)->optionString = (char*)"-XX:StartFlightRecording=dumponexit=false";
       
   697   } else {
       
   698     *tail = '='; // ":" -> "="
       
   699   }
       
   700   return false;
       
   701 }
       
   702 
       
   703 bool JfrOptionSet::parse_flight_recorder_option(const JavaVMOption** option, char* tail) {
       
   704   assert(option != NULL, "invariant");
       
   705   assert(tail != NULL, "invariant");
       
   706   assert((*option)->optionString != NULL, "invariant");
       
   707   assert(strncmp((*option)->optionString, "-XX:FlightRecorderOptions", 25) == 0, "invariant");
       
   708   if (tail != NULL) {
       
   709     *tail = '='; // ":" -> "="
       
   710   }
       
   711   return false;
       
   712 }
       
   713