1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "jfr/dcmd/jfrDcmds.hpp"
  27 #include "jfr/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 "logging/log.hpp"
  44 #include "logging/logStream.hpp"
  45 #include "memory/resourceArea.inline.hpp"
  46 #include "runtime/handles.inline.hpp"
  47 #include "runtime/globals_extension.hpp"
  48 #include "utilities/growableArray.hpp"
  49 #ifdef ASSERT
  50 #include "prims/jvmtiEnvBase.hpp"
  51 #endif
  52 
  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 }
  58 
  59 static bool _enabled = false;
  60 
  61 static bool enable() {
  62   assert(!_enabled, "invariant");
  63   if (!FlightRecorder) {
  64     FLAG_SET_MGMT(FlightRecorder, true);
  65   }
  66   _enabled = FlightRecorder;
  67   assert(_enabled, "invariant");
  68   return _enabled;
  69 }
  70 
  71 bool JfrRecorder::is_enabled() {
  72   return _enabled;
  73 }
  74 
  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 }
  84 
  85 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL;
  86 
  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 }
  97 
  98 static void teardown_startup_support() {
  99   release_recordings();
 100   JfrOptionSet::release_start_flight_recording_options();
 101 }
 102 
 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 }
 116 
 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 }
 137 
 138 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
 139   assert(dcmd_recording != NULL, "invariant");
 140   log_trace(jfr, system)("Starting a recording");
 141   dcmd_recording->execute(DCmd_Source_Internal, THREAD);
 142   if (HAS_PENDING_EXCEPTION) {
 143     log_debug(jfr, system)("Exception while starting a recording");
 144     CLEAR_PENDING_EXCEPTION;
 145     return false;
 146   }
 147   log_trace(jfr, system)("Finished starting a recording");
 148   return true;
 149 }
 150 
 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 }
 166 
 167 static void log_jdk_jfr_module_resolution_error(TRAPS) {
 168   LogTarget(Error, jfr, system) lt_error;
 169   LogTargetHandle handle(lt_error);
 170   LogStream stream(handle);
 171   JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD);
 172 }
 173 
 174 static bool is_cds_dump_requested() {
 175   // we will not be able to launch recordings if a cds dump is being requested
 176   if (Arguments::is_dumping_archive() && (JfrOptionSet::start_flight_recording_options() != NULL)) {
 177     warning("JFR will be disabled during CDS dumping");
 178     teardown_startup_support();
 179     return true;
 180   }
 181   return false;
 182 }
 183 
 184 bool JfrRecorder::on_create_vm_2() {
 185   if (is_cds_dump_requested()) {
 186     return true;
 187   }
 188   Thread* const thread = Thread::current();
 189   if (!JfrOptionSet::initialize(thread)) {
 190     return false;
 191   }
 192   if (!register_jfr_dcmds()) {
 193     return false;
 194   }
 195   const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available();
 196   if (in_graph) {
 197     if (!validate_recording_options(thread)) {
 198       return false;
 199     }
 200     if (!JfrOptionSet::configure(thread)) {
 201       return false;
 202     }
 203   }
 204   if (!is_enabled()) {
 205     return true;
 206   }
 207   if (!in_graph) {
 208     log_jdk_jfr_module_resolution_error(thread);
 209     return false;
 210   }
 211   return true;
 212 }
 213 
 214 bool JfrRecorder::on_create_vm_3() {
 215   assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
 216   return launch_command_line_recordings(Thread::current());
 217 }
 218 
 219 static bool _created = false;
 220 
 221 //
 222 // Main entry point for starting Jfr functionality.
 223 // Non-protected initializations assume single-threaded setup.
 224 //
 225 bool JfrRecorder::create(bool simulate_failure) {
 226   assert(!is_disabled(), "invariant");
 227   assert(!is_created(), "invariant");
 228   if (!is_enabled()) {
 229     enable();
 230   }
 231   if (!create_components() || simulate_failure) {
 232     destroy_components();
 233     return false;
 234   }
 235   if (!create_recorder_thread()) {
 236     destroy_components();
 237     return false;
 238   }
 239   _created = true;
 240   return true;
 241 }
 242 
 243 bool JfrRecorder::is_created() {
 244   return _created;
 245 }
 246 
 247 bool JfrRecorder::create_components() {
 248   ResourceMark rm;
 249   HandleMark hm;
 250 
 251   if (!create_java_event_writer()) {
 252     return false;
 253   }
 254   if (!create_jvmti_agent()) {
 255     return false;
 256   }
 257   if (!create_post_box()) {
 258     return false;
 259   }
 260   if (!create_chunk_repository()) {
 261     return false;
 262   }
 263   if (!create_storage()) {
 264     return false;
 265   }
 266   if (!create_checkpoint_manager()) {
 267     return false;
 268   }
 269   if (!create_stacktrace_repository()) {
 270     return false;
 271   }
 272   if (!create_os_interface()) {
 273     return false;
 274   }
 275   if (!create_stringpool()) {
 276     return false;
 277   }
 278   if (!create_thread_sampling()) {
 279     return false;
 280   }
 281   return true;
 282 }
 283 
 284 // subsystems
 285 static JfrPostBox* _post_box = NULL;
 286 static JfrStorage* _storage = NULL;
 287 static JfrCheckpointManager* _checkpoint_manager = NULL;
 288 static JfrRepository* _repository = NULL;
 289 static JfrStackTraceRepository* _stack_trace_repository;
 290 static JfrStringPool* _stringpool = NULL;
 291 static JfrOSInterface* _os_interface = NULL;
 292 static JfrThreadSampling* _thread_sampling = NULL;
 293 
 294 bool JfrRecorder::create_java_event_writer() {
 295   return JfrJavaEventWriter::initialize();
 296 }
 297 
 298 bool JfrRecorder::create_jvmti_agent() {
 299   return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
 300 }
 301 
 302 bool JfrRecorder::create_post_box() {
 303   assert(_post_box == NULL, "invariant");
 304   _post_box = JfrPostBox::create();
 305   return _post_box != NULL;
 306 }
 307 
 308 bool JfrRecorder::create_chunk_repository() {
 309   assert(_repository == NULL, "invariant");
 310   assert(_post_box != NULL, "invariant");
 311   _repository = JfrRepository::create(*_post_box);
 312   return _repository != NULL && _repository->initialize();
 313 }
 314 
 315 bool JfrRecorder::create_os_interface() {
 316   assert(_os_interface == NULL, "invariant");
 317   _os_interface = JfrOSInterface::create();
 318   return _os_interface != NULL && _os_interface->initialize();
 319 }
 320 
 321 bool JfrRecorder::create_storage() {
 322   assert(_repository != NULL, "invariant");
 323   assert(_post_box != NULL, "invariant");
 324   _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
 325   return _storage != NULL && _storage->initialize();
 326 }
 327 
 328 bool JfrRecorder::create_checkpoint_manager() {
 329   assert(_checkpoint_manager == NULL, "invariant");
 330   assert(_repository != NULL, "invariant");
 331   _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
 332   return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
 333 }
 334 
 335 bool JfrRecorder::create_stacktrace_repository() {
 336   assert(_stack_trace_repository == NULL, "invariant");
 337   _stack_trace_repository = JfrStackTraceRepository::create();
 338   return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
 339 }
 340 
 341 bool JfrRecorder::create_stringpool() {
 342   assert(_stringpool == NULL, "invariant");
 343   assert(_repository != NULL, "invariant");
 344   _stringpool = JfrStringPool::create(_repository->chunkwriter());
 345   return _stringpool != NULL && _stringpool->initialize();
 346 }
 347 
 348 bool JfrRecorder::create_thread_sampling() {
 349   assert(_thread_sampling == NULL, "invariant");
 350   _thread_sampling = JfrThreadSampling::create();
 351   return _thread_sampling != NULL;
 352 }
 353 
 354 void JfrRecorder::destroy_components() {
 355   JfrJvmtiAgent::destroy();
 356   if (_post_box != NULL) {
 357     JfrPostBox::destroy();
 358     _post_box = NULL;
 359   }
 360   if (_repository != NULL) {
 361     JfrRepository::destroy();
 362     _repository = NULL;
 363   }
 364   if (_storage != NULL) {
 365     JfrStorage::destroy();
 366     _storage = NULL;
 367   }
 368   if (_checkpoint_manager != NULL) {
 369     JfrCheckpointManager::destroy();
 370     _checkpoint_manager = NULL;
 371   }
 372   if (_stack_trace_repository != NULL) {
 373     JfrStackTraceRepository::destroy();
 374     _stack_trace_repository = NULL;
 375   }
 376   if (_stringpool != NULL) {
 377     JfrStringPool::destroy();
 378     _stringpool = NULL;
 379   }
 380   if (_os_interface != NULL) {
 381     JfrOSInterface::destroy();
 382     _os_interface = NULL;
 383   }
 384   if (_thread_sampling != NULL) {
 385     JfrThreadSampling::destroy();
 386     _thread_sampling = NULL;
 387   }
 388 }
 389 
 390 bool JfrRecorder::create_recorder_thread() {
 391   return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current());
 392 }
 393 
 394 void JfrRecorder::destroy() {
 395   assert(is_created(), "invariant");
 396   _post_box->post(MSG_SHUTDOWN);
 397   JfrJvmtiAgent::destroy();
 398 }
 399 
 400 void JfrRecorder::on_recorder_thread_exit() {
 401   assert(!is_recording(), "invariant");
 402   // intent is to destroy the recorder instance and components,
 403   // but need sensitive coordination not yet in place
 404   //
 405   // destroy_components();
 406   //
 407   log_debug(jfr, system)("Recorder thread STOPPED");
 408 }
 409 
 410 void JfrRecorder::start_recording() {
 411   _post_box->post(MSG_START);
 412 }
 413 
 414 bool JfrRecorder::is_recording() {
 415   return JfrRecorderService::is_recording();
 416 }
 417 
 418 void JfrRecorder::stop_recording() {
 419   _post_box->post(MSG_STOP);
 420 }