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 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); 185 Thread* const thread = Thread::current(); 186 if (!JfrOptionSet::initialize(thread)) { 187 return false; 188 } 189 if (!register_jfr_dcmds()) { 190 return false; 191 } 192 if (!validate_recording_options(thread)) { 193 return false; 194 } 195 if (in_graph) { 196 if (!JfrJavaEventWriter::initialize()) { 197 return false; 198 } 199 if (!JfrOptionSet::configure(thread)) { 200 return false; 201 } 202 } 203 if (!is_enabled()) { 204 return true; 205 } 206 if (!in_graph) { 207 log_jdk_jfr_module_resolution_error(thread); 208 return false; 209 } 210 return startup_recordings(thread); 211 } 212 213 static bool _created = false; 214 215 // 216 // Main entry point for starting Jfr functionality. 217 // Non-protected initializations assume single-threaded setup. 218 // 219 bool JfrRecorder::create(bool simulate_failure) { 220 assert(!is_disabled(), "invariant"); 221 assert(!is_created(), "invariant"); 222 if (!is_enabled()) { 223 enable(); 224 } 225 if (!create_components() || simulate_failure) { 226 destroy_components(); 227 return false; 228 } 229 if (!create_recorder_thread()) { 230 destroy_components(); 231 return false; 232 } 233 _created = true; 234 return true; 235 } 236 237 bool JfrRecorder::is_created() { 238 return _created; 239 } 240 241 bool JfrRecorder::create_components() { 242 ResourceMark rm; 243 HandleMark hm; 244 245 if (!create_jvmti_agent()) { 246 return false; 247 } 248 if (!create_post_box()) { 249 return false; 250 } 251 if (!create_chunk_repository()) { 252 return false; 253 } 254 if (!create_storage()) { 255 return false; 256 } 257 if (!create_checkpoint_manager()) { 258 return false; 259 } 260 if (!create_stacktrace_repository()) { 261 return false; 262 } 263 if (!create_os_interface()) { 264 return false; 265 } 266 if (!create_stringpool()) { 267 return false; 268 } 269 if (!create_thread_sampling()) { 270 return false; 271 } 272 return true; 273 } 274 275 // subsystems 276 static JfrJvmtiAgent* _jvmti_agent = NULL; 277 static JfrPostBox* _post_box = NULL; 278 static JfrStorage* _storage = NULL; 279 static JfrCheckpointManager* _checkpoint_manager = NULL; 280 static JfrRepository* _repository = NULL; 281 static JfrStackTraceRepository* _stack_trace_repository; 282 static JfrStringPool* _stringpool = NULL; 283 static JfrOSInterface* _os_interface = NULL; 284 static JfrThreadSampling* _thread_sampling = NULL; 285 286 bool JfrRecorder::create_jvmti_agent() { 287 return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true; 288 } 289 290 bool JfrRecorder::create_post_box() { 291 assert(_post_box == NULL, "invariant"); 292 _post_box = JfrPostBox::create(); 293 return _post_box != NULL; 294 } 295 296 bool JfrRecorder::create_chunk_repository() { 297 assert(_repository == NULL, "invariant"); 298 assert(_post_box != NULL, "invariant"); 299 _repository = JfrRepository::create(*_post_box); 300 return _repository != NULL && _repository->initialize(); 301 } 302 303 bool JfrRecorder::create_os_interface() { 304 assert(_os_interface == NULL, "invariant"); 305 _os_interface = JfrOSInterface::create(); 306 return _os_interface != NULL && _os_interface->initialize(); 307 } 308 309 bool JfrRecorder::create_storage() { 310 assert(_repository != NULL, "invariant"); 311 assert(_post_box != NULL, "invariant"); 312 _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box); 313 return _storage != NULL && _storage->initialize(); 314 } 315 316 bool JfrRecorder::create_checkpoint_manager() { 317 assert(_checkpoint_manager == NULL, "invariant"); 318 assert(_repository != NULL, "invariant"); 319 _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter()); 320 return _checkpoint_manager != NULL && _checkpoint_manager->initialize(); 321 } 322 323 bool JfrRecorder::create_stacktrace_repository() { 324 assert(_stack_trace_repository == NULL, "invariant"); 325 _stack_trace_repository = JfrStackTraceRepository::create(); 326 return _stack_trace_repository != NULL && _stack_trace_repository->initialize(); 327 } 328 329 bool JfrRecorder::create_stringpool() { 330 assert(_stringpool == NULL, "invariant"); 331 assert(_repository != NULL, "invariant"); 332 _stringpool = JfrStringPool::create(_repository->chunkwriter()); 333 return _stringpool != NULL && _stringpool->initialize(); 334 } 335 336 bool JfrRecorder::create_thread_sampling() { 337 assert(_thread_sampling == NULL, "invariant"); 338 _thread_sampling = JfrThreadSampling::create(); 339 return _thread_sampling != NULL; 340 } 341 342 void JfrRecorder::destroy_components() { 343 JfrJvmtiAgent::destroy(); 344 if (_post_box != NULL) { 345 JfrPostBox::destroy(); 346 _post_box = NULL; 347 } 348 if (_repository != NULL) { 349 JfrRepository::destroy(); 350 _repository = NULL; 351 } 352 if (_storage != NULL) { 353 JfrStorage::destroy(); 354 _storage = NULL; 355 } 356 if (_checkpoint_manager != NULL) { 357 JfrCheckpointManager::destroy(); 358 _checkpoint_manager = NULL; 359 } 360 if (_stack_trace_repository != NULL) { 361 JfrStackTraceRepository::destroy(); 362 _stack_trace_repository = NULL; 363 } 364 if (_stringpool != NULL) { 365 JfrStringPool::destroy(); 366 _stringpool = NULL; 367 } 368 if (_os_interface != NULL) { 369 JfrOSInterface::destroy(); 370 _os_interface = NULL; 371 } 372 if (_thread_sampling != NULL) { 373 JfrThreadSampling::destroy(); 374 _thread_sampling = NULL; 375 } 376 } 377 378 bool JfrRecorder::create_recorder_thread() { 379 return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current()); 380 } 381 382 void JfrRecorder::destroy() { 383 assert(is_created(), "invariant"); 384 _post_box->post(MSG_SHUTDOWN); 385 JfrJvmtiAgent::destroy(); 386 } 387 388 void JfrRecorder::on_recorder_thread_exit() { 389 assert(!is_recording(), "invariant"); 390 // intent is to destroy the recorder instance and components, 391 // but need sensitive coordination not yet in place 392 // 393 // destroy_components(); 394 // 395 log_debug(jfr, system)("Recorder thread STOPPED"); 396 } 397 398 void JfrRecorder::start_recording() { 399 _post_box->post(MSG_START); 400 } 401 402 bool JfrRecorder::is_recording() { 403 return JfrRecorderService::is_recording(); 404 } 405 406 void JfrRecorder::stop_recording() { 407 _post_box->post(MSG_STOP); 408 }