src/share/vm/jfr/recorder/jfrRecorder.cpp

Fri, 12 Jun 2020 02:59:56 +0100

author
jbachorik
date
Fri, 12 Jun 2020 02:59:56 +0100
changeset 9925
30fb8c8cceb9
parent 9884
1258121876f8
child 9986
85e682d8ab91
permissions
-rw-r--r--

8233197: Invert JvmtiExport::post_vm_initialized() and Jfr:on_vm_start() start-up order for correct option parsing
8246703: [TESTBUG] Add test for JDK-8233197
Reviewed-by: aph, adinn, neugens

     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  */
    25 #include "precompiled.hpp"
    26 #include "jfr/dcmd/jfrDcmds.hpp"
    27 #include "jfr/instrumentation/jfrJvmtiAgent.hpp"
    28 #include "jfr/jni/jfrJavaSupport.hpp"
    29 #include "jfr/periodic/jfrOSInterface.hpp"
    30 #include "jfr/periodic/sampling/jfrThreadSampler.hpp"
    31 #include "jfr/recorder/jfrRecorder.hpp"
    32 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
    33 #include "jfr/recorder/repository/jfrRepository.hpp"
    34 #include "jfr/recorder/service/jfrOptionSet.hpp"
    35 #include "jfr/recorder/service/jfrPostBox.hpp"
    36 #include "jfr/recorder/service/jfrRecorderService.hpp"
    37 #include "jfr/recorder/service/jfrRecorderThread.hpp"
    38 #include "jfr/recorder/storage/jfrStorage.hpp"
    39 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
    40 #include "jfr/recorder/stringpool/jfrStringPool.hpp"
    41 #include "jfr/utilities/jfrTime.hpp"
    42 #include "jfr/writers/jfrJavaEventWriter.hpp"
    43 #include "memory/resourceArea.hpp"
    44 #include "runtime/handles.inline.hpp"
    45 #include "runtime/globals_extension.hpp"
    46 #include "utilities/growableArray.hpp"
    47 #ifdef ASSERT
    48 #include "prims/jvmtiEnvBase.hpp"
    49 #endif
    51 bool JfrRecorder::_shutting_down = false;
    53 bool JfrRecorder::is_disabled() {
    54   // True if -XX:-FlightRecorder has been explicitly set on the
    55   // command line
    56   return FLAG_IS_CMDLINE(FlightRecorder) ? !FlightRecorder : false;
    57 }
    59 static bool _enabled = false;
    61 static bool enable() {
    62   assert(!_enabled, "invariant");
    63   if (!FlightRecorder) {
    64     FLAG_SET_MGMT(bool, FlightRecorder, true);
    65   }
    66   _enabled = FlightRecorder;
    67   assert(_enabled, "invariant");
    68   return _enabled;
    69 }
    71 bool JfrRecorder::is_enabled() {
    72   return _enabled;
    73 }
    75 bool JfrRecorder::on_create_vm_1() {
    76   if (!is_disabled()) {
    77     if (FlightRecorder || StartFlightRecording != NULL) {
    78       enable();
    79     }
    80   }
    81   // fast time initialization
    82   return JfrTime::initialize();
    83 }
    85 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL;
    87 static void release_recordings() {
    88   if (dcmd_recordings_array != NULL) {
    89     const int length = dcmd_recordings_array->length();
    90     for (int i = 0; i < length; ++i) {
    91       delete dcmd_recordings_array->at(i);
    92     }
    93     delete dcmd_recordings_array;
    94     dcmd_recordings_array = NULL;
    95   }
    96 }
    98 static void teardown_startup_support() {
    99   release_recordings();
   100   JfrOptionSet::release_start_flight_recording_options();
   101 }
   103 // Parsing options here to detect errors as soon as possible
   104 static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
   105   assert(options != NULL, "invariant");
   106   assert(dcmd_recording != NULL, "invariant");
   107   CmdLine cmdline(options, strlen(options), true);
   108   dcmd_recording->parse(&cmdline, ',', THREAD);
   109   if (HAS_PENDING_EXCEPTION) {
   110     java_lang_Throwable::print(PENDING_EXCEPTION, tty);
   111     CLEAR_PENDING_EXCEPTION;
   112     return false;
   113   }
   114   return true;
   115 }
   117 static bool validate_recording_options(TRAPS) {
   118   const GrowableArray<const char*>* options = JfrOptionSet::start_flight_recording_options();
   119   if (options == NULL) {
   120     return true;
   121   }
   122   const int length = options->length();
   123   assert(length >= 1, "invariant");
   124   assert(dcmd_recordings_array == NULL, "invariant");
   125   dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, true, mtTracing);
   126   assert(dcmd_recordings_array != NULL, "invariant");
   127   for (int i = 0; i < length; ++i) {
   128     JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true);
   129     assert(dcmd_recording != NULL, "invariant");
   130     dcmd_recordings_array->append(dcmd_recording);
   131     if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) {
   132       return false;
   133     }
   134   }
   135   return true;
   136 }
   138 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
   139   assert(dcmd_recording != NULL, "invariant");
   140   if (LogJFR && Verbose) tty->print_cr("Starting a recording");
   141   dcmd_recording->execute(DCmd_Source_Internal, THREAD);
   142   if (HAS_PENDING_EXCEPTION) {
   143     if (LogJFR) tty->print_cr("Exception while starting a recording");
   144     CLEAR_PENDING_EXCEPTION;
   145     return false;
   146   }
   147   if (LogJFR && Verbose) tty->print_cr("Finished starting a recording");
   148   return true;
   149 }
   151 static bool launch_command_line_recordings(TRAPS) {
   152   bool result = true;
   153   if (dcmd_recordings_array != NULL) {
   154     const int length = dcmd_recordings_array->length();
   155     assert(length >= 1, "invariant");
   156     for (int i = 0; i < length; ++i) {
   157       if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) {
   158         result = false;
   159         break;
   160       }
   161     }
   162   }
   163   teardown_startup_support();
   164   return result;
   165 }
   167 static bool is_cds_dump_requested() {
   168   // we will not be able to launch recordings if a cds dump is being requested
   169   if (DumpSharedSpaces && (JfrOptionSet::start_flight_recording_options() != NULL)) {
   170     warning("JFR will be disabled during CDS dumping");
   171     teardown_startup_support();
   172     return true;
   173   }
   174   return false;
   175 }
   177 bool JfrRecorder::on_create_vm_2() {
   178   if (is_cds_dump_requested()) {
   179     return true;
   180   }
   181   Thread* const thread = Thread::current();
   182   if (!JfrJavaEventWriter::has_required_classes(thread)) {
   183     // assume it is compact profile of jfr.jar is missed for some reasons
   184     // skip further initialization.
   185     return true;
   186   }
   187   if (!JfrOptionSet::initialize(thread)) {
   188     return false;
   189   }
   190   if (!register_jfr_dcmds()) {
   191     return false;
   192   }
   194   if (!validate_recording_options(thread)) {
   195     return false;
   196   }
   197   if (!JfrOptionSet::configure(thread)) {
   198     return false;
   199   }
   201   if (!is_enabled()) {
   202     return true;
   203   }
   204   return true;
   205 }
   207 bool JfrRecorder::on_create_vm_3() {
   208   assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
   209   return launch_command_line_recordings(Thread::current());
   210  }
   212 static bool _created = false;
   214 //
   215 // Main entry point for starting Jfr functionality.
   216 // Non-protected initializations assume single-threaded setup.
   217 //
   218 bool JfrRecorder::create(bool simulate_failure) {
   219   assert(!is_disabled(), "invariant");
   220   assert(!is_created(), "invariant");
   221   if (!is_enabled()) {
   222     enable();
   223   }
   224   if (!create_components() || simulate_failure) {
   225     destroy_components();
   226     return false;
   227   }
   228   if (!create_recorder_thread()) {
   229     destroy_components();
   230     return false;
   231   }
   232   _created = true;
   233   return true;
   234 }
   236 bool JfrRecorder::is_created() {
   237   return _created;
   238 }
   240 bool JfrRecorder::create_components() {
   241   ResourceMark rm;
   242   HandleMark hm;
   244   if (!create_java_event_writer()) {
   245     return false;
   246   }
   247   if (!create_jvmti_agent()) {
   248     return false;
   249   }
   250   if (!create_post_box()) {
   251     return false;
   252   }
   253   if (!create_chunk_repository()) {
   254     return false;
   255   }
   256   if (!create_storage()) {
   257     return false;
   258   }
   259   if (!create_checkpoint_manager()) {
   260     return false;
   261   }
   262   if (!create_stacktrace_repository()) {
   263     return false;
   264   }
   265   if (!create_os_interface()) {
   266     return false;
   267   }
   268   if (!create_stringpool()) {
   269     return false;
   270   }
   271   if (!create_thread_sampling()) {
   272     return false;
   273   }
   274   return true;
   275 }
   277 // subsystems
   278 static JfrPostBox* _post_box = NULL;
   279 static JfrStorage* _storage = NULL;
   280 static JfrCheckpointManager* _checkpoint_manager = NULL;
   281 static JfrRepository* _repository = NULL;
   282 static JfrStackTraceRepository* _stack_trace_repository;
   283 static JfrStringPool* _stringpool = NULL;
   284 static JfrOSInterface* _os_interface = NULL;
   285 static JfrThreadSampling* _thread_sampling = NULL;
   287 bool JfrRecorder::create_java_event_writer() {
   288   return JfrJavaEventWriter::initialize();
   289 }
   291 bool JfrRecorder::create_jvmti_agent() {
   292   return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
   293 }
   295 bool JfrRecorder::create_post_box() {
   296   assert(_post_box == NULL, "invariant");
   297   _post_box = JfrPostBox::create();
   298   return _post_box != NULL;
   299 }
   301 bool JfrRecorder::create_chunk_repository() {
   302   assert(_repository == NULL, "invariant");
   303   assert(_post_box != NULL, "invariant");
   304   _repository = JfrRepository::create(*_post_box);
   305   return _repository != NULL && _repository->initialize();
   306 }
   308 bool JfrRecorder::create_os_interface() {
   309   assert(_os_interface == NULL, "invariant");
   310   _os_interface = JfrOSInterface::create();
   311   return _os_interface != NULL && _os_interface->initialize();
   312 }
   314 bool JfrRecorder::create_storage() {
   315   assert(_repository != NULL, "invariant");
   316   assert(_post_box != NULL, "invariant");
   317   _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
   318   return _storage != NULL && _storage->initialize();
   319 }
   321 bool JfrRecorder::create_checkpoint_manager() {
   322   assert(_checkpoint_manager == NULL, "invariant");
   323   assert(_repository != NULL, "invariant");
   324   _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
   325   return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
   326 }
   328 bool JfrRecorder::create_stacktrace_repository() {
   329   assert(_stack_trace_repository == NULL, "invariant");
   330   _stack_trace_repository = JfrStackTraceRepository::create();
   331   return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
   332 }
   334 bool JfrRecorder::create_stringpool() {
   335   assert(_stringpool == NULL, "invariant");
   336   assert(_repository != NULL, "invariant");
   337   _stringpool = JfrStringPool::create(_repository->chunkwriter());
   338   return _stringpool != NULL && _stringpool->initialize();
   339 }
   341 bool JfrRecorder::create_thread_sampling() {
   342   assert(_thread_sampling == NULL, "invariant");
   343   _thread_sampling = JfrThreadSampling::create();
   344   return _thread_sampling != NULL;
   345 }
   347 void JfrRecorder::destroy_components() {
   348   JfrJvmtiAgent::destroy();
   349   if (_post_box != NULL) {
   350     JfrPostBox::destroy();
   351     _post_box = NULL;
   352   }
   353   if (_repository != NULL) {
   354     JfrRepository::destroy();
   355     _repository = NULL;
   356   }
   357   if (_storage != NULL) {
   358     JfrStorage::destroy();
   359     _storage = NULL;
   360   }
   361   if (_checkpoint_manager != NULL) {
   362     JfrCheckpointManager::destroy();
   363     _checkpoint_manager = NULL;
   364   }
   365   if (_stack_trace_repository != NULL) {
   366     JfrStackTraceRepository::destroy();
   367     _stack_trace_repository = NULL;
   368   }
   369   if (_stringpool != NULL) {
   370     JfrStringPool::destroy();
   371     _stringpool = NULL;
   372   }
   373   if (_os_interface != NULL) {
   374     JfrOSInterface::destroy();
   375     _os_interface = NULL;
   376   }
   377   if (_thread_sampling != NULL) {
   378     JfrThreadSampling::destroy();
   379     _thread_sampling = NULL;
   380   }
   381 }
   383 bool JfrRecorder::create_recorder_thread() {
   384   return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current());
   385 }
   387 void JfrRecorder::destroy() {
   388   assert(is_created(), "invariant");
   389   _post_box->post(MSG_SHUTDOWN);
   390   JfrJvmtiAgent::destroy();
   391 }
   393 void JfrRecorder::on_recorder_thread_exit() {
   394   assert(!is_recording(), "invariant");
   395   // intent is to destroy the recorder instance and components,
   396   // but need sensitive coordination not yet in place
   397   //
   398   // destroy_components();
   399   //
   400   if (LogJFR) tty->print_cr("Recorder thread STOPPED");
   401 }
   403 void JfrRecorder::start_recording() {
   404   _post_box->post(MSG_START);
   405 }
   407 bool JfrRecorder::is_recording() {
   408   return JfrRecorderService::is_recording();
   409 }
   411 void JfrRecorder::stop_recording() {
   412   _post_box->post(MSG_STOP);
   413 }

mercurial