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 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(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 log_trace(jfr, system)("Starting a recording"); 136 dcmd_recording->execute(DCmd_Source_Internal, THREAD); 137 if (HAS_PENDING_EXCEPTION) { 138 log_debug(jfr, system)("Exception while starting a recording"); 139 CLEAR_PENDING_EXCEPTION; 140 return false; 141 } 142 log_trace(jfr, system)("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 void log_jdk_jfr_module_resolution_error(TRAPS) { 163 LogTarget(Error, jfr, system) lt_error; 164 LogTargetHandle handle(lt_error); 165 LogStream stream(handle); 166 JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD); 167 } 168 169 static bool is_cds_dump_requested() { 170 // we will not be able to launch recordings if a cds dump is being requested 171 if (Arguments::is_dumping_archive() && (JfrOptionSet::startup_recording_options() != NULL)) { 172 warning("JFR will be disabled during CDS dumping"); 173 teardown_startup_support(); 174 return true; 175 } 176 return false; 177 } 178 179 bool JfrRecorder::on_vm_start() { 180 if (is_cds_dump_requested()) { 181 return true; 182 } 183 Thread* const thread = Thread::current(); 184 if (!JfrOptionSet::initialize(thread)) { 185 return false; 186 } 187 if (!register_jfr_dcmds()) { 188 return false; 189 } 190 191 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); 192 193 if (in_graph) { 194 if (!validate_recording_options(thread)) { 195 return false; 196 } 197 if (!JfrOptionSet::configure(thread)) { 198 return false; 199 } 200 } 201 202 if (!is_enabled()) { 203 return true; 204 } 205 206 if (!in_graph) { 207 log_jdk_jfr_module_resolution_error(thread); 208 return false; 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_java_event_writer()) { 247 return false; 248 } 249 if (!create_jvmti_agent()) { 250 return false; 251 } 252 if (!create_post_box()) { 253 return false; 254 } 255 if (!create_chunk_repository()) { 256 return false; 257 } 258 if (!create_storage()) { 259 return false; 260 } 261 if (!create_checkpoint_manager()) { 262 return false; 263 } 264 if (!create_stacktrace_repository()) { 265 return false; 266 } 267 if (!create_os_interface()) { 268 return false; 269 } 270 if (!create_stringpool()) { 271 return false; 272 } 273 if (!create_thread_sampling()) { 274 return false; 275 } 276 return true; 277 } 278 279 // subsystems 280 static JfrJvmtiAgent* _jvmti_agent = NULL; 281 static JfrPostBox* _post_box = NULL; 282 static JfrStorage* _storage = NULL; 283 static JfrCheckpointManager* _checkpoint_manager = NULL; 284 static JfrRepository* _repository = NULL; 285 static JfrStackTraceRepository* _stack_trace_repository; 286 static JfrStringPool* _stringpool = NULL; 287 static JfrOSInterface* _os_interface = NULL; 288 static JfrThreadSampling* _thread_sampling = NULL; 289 290 bool JfrRecorder::create_java_event_writer() { 291 return JfrJavaEventWriter::initialize(); 292 } 293 294 bool JfrRecorder::create_jvmti_agent() { 295 return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true; 296 } 297 298 bool JfrRecorder::create_post_box() { 299 assert(_post_box == NULL, "invariant"); 300 _post_box = JfrPostBox::create(); 301 return _post_box != NULL; 302 } 303 304 bool JfrRecorder::create_chunk_repository() { 305 assert(_repository == NULL, "invariant"); 306 assert(_post_box != NULL, "invariant"); 307 _repository = JfrRepository::create(*_post_box); 308 return _repository != NULL && _repository->initialize(); 309 } 310 311 bool JfrRecorder::create_os_interface() { 312 assert(_os_interface == NULL, "invariant"); 313 _os_interface = JfrOSInterface::create(); 314 return _os_interface != NULL && _os_interface->initialize(); 315 } 316 317 bool JfrRecorder::create_storage() { 318 assert(_repository != NULL, "invariant"); 319 assert(_post_box != NULL, "invariant"); 320 _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box); 321 return _storage != NULL && _storage->initialize(); 322 } 323 324 bool JfrRecorder::create_checkpoint_manager() { 325 assert(_checkpoint_manager == NULL, "invariant"); 326 assert(_repository != NULL, "invariant"); 327 _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter()); 328 return _checkpoint_manager != NULL && _checkpoint_manager->initialize(); 329 } 330 331 bool JfrRecorder::create_stacktrace_repository() { 332 assert(_stack_trace_repository == NULL, "invariant"); 333 _stack_trace_repository = JfrStackTraceRepository::create(); 334 return _stack_trace_repository != NULL && _stack_trace_repository->initialize(); 335 } 336 337 bool JfrRecorder::create_stringpool() { 338 assert(_stringpool == NULL, "invariant"); 339 assert(_repository != NULL, "invariant"); 340 _stringpool = JfrStringPool::create(_repository->chunkwriter()); 341 return _stringpool != NULL && _stringpool->initialize(); 342 } 343 344 bool JfrRecorder::create_thread_sampling() { 345 assert(_thread_sampling == NULL, "invariant"); 346 _thread_sampling = JfrThreadSampling::create(); 347 return _thread_sampling != NULL; 348 } 349 350 void JfrRecorder::destroy_components() { 351 JfrJvmtiAgent::destroy(); 352 if (_post_box != NULL) { 353 JfrPostBox::destroy(); 354 _post_box = NULL; 355 } 356 if (_repository != NULL) { 357 JfrRepository::destroy(); 358 _repository = NULL; 359 } 360 if (_storage != NULL) { 361 JfrStorage::destroy(); 362 _storage = NULL; 363 } 364 if (_checkpoint_manager != NULL) { 365 JfrCheckpointManager::destroy(); 366 _checkpoint_manager = NULL; 367 } 368 if (_stack_trace_repository != NULL) { 369 JfrStackTraceRepository::destroy(); 370 _stack_trace_repository = NULL; 371 } 372 if (_stringpool != NULL) { 373 JfrStringPool::destroy(); 374 _stringpool = NULL; 375 } 376 if (_os_interface != NULL) { 377 JfrOSInterface::destroy(); 378 _os_interface = NULL; 379 } 380 if (_thread_sampling != NULL) { 381 JfrThreadSampling::destroy(); 382 _thread_sampling = NULL; 383 } 384 } 385 386 bool JfrRecorder::create_recorder_thread() { 387 return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current()); 388 } 389 390 void JfrRecorder::destroy() { 391 assert(is_created(), "invariant"); 392 _post_box->post(MSG_SHUTDOWN); 393 JfrJvmtiAgent::destroy(); 394 } 395 396 void JfrRecorder::on_recorder_thread_exit() { 397 assert(!is_recording(), "invariant"); 398 // intent is to destroy the recorder instance and components, 399 // but need sensitive coordination not yet in place 400 // 401 // destroy_components(); 402 // 403 log_debug(jfr, system)("Recorder thread STOPPED"); 404 } 405 406 void JfrRecorder::start_recording() { 407 _post_box->post(MSG_START); 408 } 409 410 bool JfrRecorder::is_recording() { 411 return JfrRecorderService::is_recording(); 412 } 413 414 void JfrRecorder::stop_recording() { 415 _post_box->post(MSG_STOP); 416 }