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