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 }