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