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 "logging/log.hpp" 44 #include "logging/logStream.hpp" 45 #include "memory/resourceArea.inline.hpp" 46 #include "runtime/handles.inline.hpp" 47 #include "runtime/flags/jvmFlag.hpp" 48 #include "runtime/globals.hpp" 49 50 static bool is_disabled_on_command_line() { 51 static const size_t length = strlen("FlightRecorder"); 52 static JVMFlag* const flight_recorder_flag = JVMFlag::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 JVMFlag::boolAtPut((char*)"FlightRecorder", &flag_value, JVMFlag::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 JfrStartFlightRecordingDCmd* _startup_recording = NULL; 89 90 static void release_startup_recording() { 91 if (_startup_recording != NULL) { 92 delete _startup_recording; 93 _startup_recording = NULL; 94 } 95 } 96 97 static void teardown_startup_support() { 98 release_startup_recording(); 99 JfrOptionSet::release_startup_recordings(); 100 } 101 102 103 // Parsing options here to detect errors as soon as possible 104 static bool parse_recording_options(const char* options, TRAPS) { 105 assert(options != NULL, "invariant"); 106 if (_startup_recording != NULL) { 107 delete _startup_recording; 108 } 109 CmdLine cmdline(options, strlen(options), true); 110 _startup_recording = new (ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true); 111 assert(_startup_recording != NULL, "invariant"); 112 _startup_recording->parse(&cmdline, ',', THREAD); 113 if (HAS_PENDING_EXCEPTION) { 114 java_lang_Throwable::print(PENDING_EXCEPTION, tty); 115 CLEAR_PENDING_EXCEPTION; 116 return false; 117 } 118 return true; 119 } 120 121 static bool validate_recording_options(TRAPS) { 122 const GrowableArray<const char*>* startup_options = JfrOptionSet::startup_recordings(); 123 if (startup_options == NULL) { 124 return true; 125 } 126 const int length = startup_options->length(); 127 assert(length >= 1, "invariant"); 128 for (int i = 0; i < length; ++i) { 129 if (!parse_recording_options(startup_options->at(i), THREAD)) { 130 return false; 131 } 132 } 133 return true; 134 } 135 136 static bool launch_recording(TRAPS) { 137 assert(_startup_recording != NULL, "invariant"); 138 log_trace(jfr, system)("Starting a recording"); 139 _startup_recording->execute(DCmd_Source_Internal, Thread::current()); 140 if (HAS_PENDING_EXCEPTION) { 141 log_debug(jfr, system)("Exception while starting a recording"); 142 CLEAR_PENDING_EXCEPTION; 143 return false; 144 } 145 log_trace(jfr, system)("Finished starting a recording"); 146 return true; 147 } 148 149 static bool launch_recordings(const GrowableArray<const char*>* startup_options, TRAPS) { 150 assert(startup_options != NULL, "invariant"); 151 const int length = startup_options->length(); 152 assert(length >= 1, "invariant"); 153 if (length == 1) { 154 // already parsed and ready, launch it 155 return launch_recording(THREAD); 156 } 157 for (int i = 0; i < length; ++i) { 158 parse_recording_options(startup_options->at(i), THREAD); 159 if (!launch_recording(THREAD)) { 160 return false; 161 } 162 } 163 return true; 164 } 165 166 static bool startup_recordings(TRAPS) { 167 const GrowableArray<const char*>* startup_options = JfrOptionSet::startup_recordings(); 168 if (startup_options == NULL) { 169 return true; 170 } 171 const bool ret = launch_recordings(startup_options, THREAD); 172 teardown_startup_support(); 173 return ret; 174 } 175 176 static void log_jdk_jfr_module_resolution_error(TRAPS) { 177 LogTarget(Error, jfr, system) lt_error; 178 LogTargetHandle handle(lt_error); 179 LogStream stream(handle); 180 JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD); 181 } 182 183 bool JfrRecorder::on_vm_start() { 184 if (DumpSharedSpaces && (JfrOptionSet::startup_recordings() != NULL)) { 185 warning("JFR will be disabled during CDS dumping"); 186 teardown_startup_support(); 187 return true; 188 } 189 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); 190 Thread* const thread = Thread::current(); 191 if (!JfrOptionSet::initialize(thread)) { 192 return false; 193 } 194 if (!register_jfr_dcmds()) { 195 return false; 196 } 197 if (!validate_recording_options(thread)) { 198 return false; 199 } 200 if (in_graph) { 201 if (!JfrJavaEventWriter::initialize()) { 202 return false; 203 } 204 if (!JfrOptionSet::configure(thread)) { 205 return false; 206 } 207 } 208 if (!is_enabled()) { 209 return true; 210 } 211 if (!in_graph) { 212 log_jdk_jfr_module_resolution_error(thread); 213 return false; 214 } 215 return startup_recordings(thread); 216 } 217 218 static bool _created = false; 219 220 // 221 // Main entry point for starting Jfr functionality. 222 // Non-protected initializations assume single-threaded setup. 223 // 224 bool JfrRecorder::create(bool simulate_failure) { 225 assert(!is_disabled(), "invariant"); 226 assert(!is_created(), "invariant"); 227 if (!is_enabled()) { 228 enable(); 229 } 230 if (!create_components() || simulate_failure) { 231 destroy_components(); 232 return false; 233 } 234 if (!create_recorder_thread()) { 235 destroy_components(); 236 return false; 237 } 238 _created = true; 239 return true; 240 } 241 242 bool JfrRecorder::is_created() { 243 return _created; 244 } 245 246 bool JfrRecorder::create_components() { 247 ResourceMark rm; 248 HandleMark hm; 249 250 if (!create_jvmti_agent()) { 251 return false; 252 } 253 if (!create_post_box()) { 254 return false; 255 } 256 if (!create_chunk_repository()) { 257 return false; 258 } 259 if (!create_storage()) { 260 return false; 261 } 262 if (!create_checkpoint_manager()) { 263 return false; 264 } 265 if (!create_stacktrace_repository()) { 266 return false; 267 } 268 if (!create_os_interface()) { 269 return false; 270 } 271 if (!create_stringpool()) { 272 return false; 273 } 274 if (!create_thread_sampling()) { 275 return false; 276 } 277 return true; 278 } 279 280 // subsystems 281 static JfrJvmtiAgent* _jvmti_agent = NULL; 282 static JfrPostBox* _post_box = NULL; 283 static JfrStorage* _storage = NULL; 284 static JfrCheckpointManager* _checkpoint_manager = NULL; 285 static JfrRepository* _repository = NULL; 286 static JfrStackTraceRepository* _stack_trace_repository; 287 static JfrStringPool* _stringpool = NULL; 288 static JfrOSInterface* _os_interface = NULL; 289 static JfrThreadSampling* _thread_sampling = NULL; 290 291 bool JfrRecorder::create_jvmti_agent() { 292 return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true; 293 } 294 295 bool JfrRecorder::create_post_box() { 296 assert(_post_box == NULL, "invariant"); 297 _post_box = JfrPostBox::create(); 298 return _post_box != NULL; 299 } 300 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 } 307 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 } 313 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 } 320 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 } 327 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 } 333 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 } 340 341 bool JfrRecorder::create_thread_sampling() { 342 assert(_thread_sampling == NULL, "invariant"); 343 _thread_sampling = JfrThreadSampling::create(); 344 return _thread_sampling != NULL; 345 } 346 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 } 382 383 bool JfrRecorder::create_recorder_thread() { 384 return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current()); 385 } 386 387 void JfrRecorder::destroy() { 388 assert(is_created(), "invariant"); 389 _post_box->post(MSG_SHUTDOWN); 390 JfrJvmtiAgent::destroy(); 391 } 392 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 log_debug(jfr, system)("Recorder thread STOPPED"); 401 } 402 403 void JfrRecorder::start_recording() { 404 _post_box->post(MSG_START); 405 } 406 407 bool JfrRecorder::is_recording() { 408 return JfrRecorderService::is_recording(); 409 } 410 411 void JfrRecorder::stop_recording() { 412 _post_box->post(MSG_STOP); 413 }