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/access/jfrOptionSet.hpp" 33 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" 34 #include "jfr/recorder/repository/jfrRepository.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/jfrTraceTime.hpp" 42 #include "jfr/writers/jfrJavaEventWriter.hpp" 43 #include "jfr/utilities/jfrLog.hpp" 44 #include "memory/resourceArea.hpp" 45 #include "runtime/handles.inline.hpp" 46 #include "runtime/globals.hpp" 47 #include "utilities/defaultStream.hpp" 48 49 static bool is_disabled_on_command_line() { 50 static const size_t length = strlen("FlightRecorder"); 51 static Flag* const flight_recorder_flag = Flag::find_flag("FlightRecorder", length); 52 assert(flight_recorder_flag != NULL, "invariant"); 53 return flight_recorder_flag->is_command_line() ? !FlightRecorder : false; 54 } 55 56 bool JfrRecorder::is_disabled() { 57 return is_disabled_on_command_line(); 58 } 59 60 static bool set_flight_recorder_flag(bool flag_value) { 61 CommandLineFlags::boolAtPut((char*)"FlightRecorder", &flag_value, Flag::MANAGEMENT); 62 return FlightRecorder; 63 } 64 65 static bool _enabled = false; 66 67 static bool enable() { 68 assert(EnableJFR, "invariant"); 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 JfrTraceTime::initialize(); 86 } 87 88 static JfrStartFlightRecordingDCmd* _startup_recording = NULL; 89 90 // Parsing options here to detect errors as soon as possible 91 static bool parse_startup_recording(TRAPS) { 92 assert(StartFlightRecording != NULL, "invariant"); 93 CmdLine cmdline(StartFlightRecording, strlen(StartFlightRecording), true); 94 _startup_recording->parse(&cmdline, ',', THREAD); 95 if (HAS_PENDING_EXCEPTION) { 96 java_lang_Throwable::print(PENDING_EXCEPTION, tty); 97 CLEAR_PENDING_EXCEPTION; 98 return false; 99 } 100 return true; 101 } 102 103 static bool initialize_startup_recording(TRAPS) { 104 if (StartFlightRecording != NULL) { 105 _startup_recording = new (ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true); 106 return _startup_recording != NULL && parse_startup_recording(THREAD); 107 } 108 return true; 109 } 110 111 static bool startup_recording(TRAPS) { 112 if (_startup_recording == NULL) { 113 return true; 114 } 115 log_trace(jfr, system)("Starting up Jfr startup recording"); 116 _startup_recording->execute(DCmd_Source_Internal, Thread::current()); 117 delete _startup_recording; 118 _startup_recording = NULL; 119 if (HAS_PENDING_EXCEPTION) { 120 log_debug(jfr, system)("Exception while starting Jfr startup recording"); 121 CLEAR_PENDING_EXCEPTION; 122 return false; 123 } 124 log_trace(jfr, system)("Finished starting Jfr startup recording"); 125 return true; 126 } 127 128 static void log_jdk_jfr_module_resolution_error(TRAPS) { 129 } 130 131 bool JfrRecorder::on_vm_start() { 132 const bool in_graph = true; 133 Thread* const thread = Thread::current(); 134 if (!JfrOptionSet::initialize(thread)) { 135 return false; 136 } 137 if (!register_jfr_dcmds()) { 138 return false; 139 } 140 if (!initialize_startup_recording(thread)) { 141 return false; 142 } 143 if (in_graph) { 144 if (!JfrJavaEventWriter::initialize()) { 145 return false; 146 } 147 if (!JfrOptionSet::configure(thread)) { 148 return false; 149 } 150 } 151 if (!is_enabled()) { 152 return true; 153 } 154 if (!in_graph) { 155 log_jdk_jfr_module_resolution_error(thread); 156 return false; 157 } 158 return startup_recording(thread); 159 } 160 161 static bool _created = false; 162 163 // 164 // Main entry point for starting Jfr functionality. 165 // Non-protected initializations assume single-threaded setup. 166 // 167 bool JfrRecorder::create(bool simulate_failure) { 168 assert(!is_disabled(), "invariant"); 169 assert(!is_created(), "invariant"); 170 if (!EnableJFR) { 171 jio_fprintf(defaultStream::error_stream(), "Can't create JFR if EnableJFR is false."); 172 return false; 173 } 174 if (!is_enabled()) { 175 enable(); 176 } 177 if (!create_components() || simulate_failure) { 178 destroy_components(); 179 return false; 180 } 181 if (!create_recorder_thread()) { 182 destroy_components(); 183 return false; 184 } 185 _created = true; 186 return true; 187 } 188 189 bool JfrRecorder::is_created() { 190 return _created; 191 } 192 193 bool JfrRecorder::create_components() { 194 ResourceMark rm; 195 HandleMark hm; 196 197 if (!create_jvmti_agent()) { 198 return false; 199 } 200 if (!create_post_box()) { 201 return false; 202 } 203 if (!create_chunk_repository()) { 204 return false; 205 } 206 if (!create_storage()) { 207 return false; 208 } 209 if (!create_checkpoint_manager()) { 210 return false; 211 } 212 if (!create_stacktrace_repository()) { 213 return false; 214 } 215 if (!create_os_interface()) { 216 return false; 217 } 218 if (!create_stringpool()) { 219 return false; 220 } 221 if (!create_thread_sampling()) { 222 return false; 223 } 224 return true; 225 } 226 227 // subsystems 228 static JfrJvmtiAgent* _jvmti_agent = NULL; 229 static JfrPostBox* _post_box = NULL; 230 static JfrStorage* _storage = NULL; 231 static JfrCheckpointManager* _checkpoint_manager = NULL; 232 static JfrRepository* _repository = NULL; 233 static JfrStackTraceRepository* _stack_trace_repository; 234 static JfrStringPool* _stringpool = NULL; 235 static JfrOSInterface* _os_interface = NULL; 236 static JfrThreadSampling* _thread_sampling = NULL; 237 238 bool JfrRecorder::create_jvmti_agent() { 239 return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true; 240 } 241 242 bool JfrRecorder::create_post_box() { 243 assert(_post_box == NULL, "invariant"); 244 _post_box = JfrPostBox::create(); 245 return _post_box != NULL; 246 } 247 248 bool JfrRecorder::create_chunk_repository() { 249 assert(_repository == NULL, "invariant"); 250 assert(_post_box != NULL, "invariant"); 251 _repository = JfrRepository::create(*_post_box); 252 return _repository != NULL && _repository->initialize(); 253 } 254 255 bool JfrRecorder::create_os_interface() { 256 assert(_os_interface == NULL, "invariant"); 257 _os_interface = JfrOSInterface::create(); 258 return _os_interface != NULL && _os_interface->initialize(); 259 } 260 261 bool JfrRecorder::create_storage() { 262 assert(_repository != NULL, "invariant"); 263 assert(_post_box != NULL, "invariant"); 264 _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box); 265 return _storage != NULL && _storage->initialize(); 266 } 267 268 bool JfrRecorder::create_checkpoint_manager() { 269 assert(_checkpoint_manager == NULL, "invariant"); 270 assert(_repository != NULL, "invariant"); 271 _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter()); 272 return _checkpoint_manager != NULL && _checkpoint_manager->initialize(); 273 } 274 275 bool JfrRecorder::create_stacktrace_repository() { 276 assert(_stack_trace_repository == NULL, "invariant"); 277 _stack_trace_repository = JfrStackTraceRepository::create(); 278 return _stack_trace_repository != NULL && _stack_trace_repository->initialize(); 279 } 280 281 bool JfrRecorder::create_stringpool() { 282 assert(_stringpool == NULL, "invariant"); 283 assert(_repository != NULL, "invariant"); 284 _stringpool = JfrStringPool::create(_repository->chunkwriter()); 285 return _stringpool != NULL && _stringpool->initialize(); 286 } 287 288 bool JfrRecorder::create_thread_sampling() { 289 assert(_thread_sampling == NULL, "invariant"); 290 _thread_sampling = JfrThreadSampling::create(); 291 return _thread_sampling != NULL; 292 } 293 294 void JfrRecorder::destroy_components() { 295 JfrJvmtiAgent::destroy(); 296 if (_post_box != NULL) { 297 JfrPostBox::destroy(); 298 _post_box = NULL; 299 } 300 if (_repository != NULL) { 301 JfrRepository::destroy(); 302 _repository = NULL; 303 } 304 if (_storage != NULL) { 305 JfrStorage::destroy(); 306 _storage = NULL; 307 } 308 if (_checkpoint_manager != NULL) { 309 JfrCheckpointManager::destroy(); 310 _checkpoint_manager = NULL; 311 } 312 if (_stack_trace_repository != NULL) { 313 JfrStackTraceRepository::destroy(); 314 _stack_trace_repository = NULL; 315 } 316 if (_stringpool != NULL) { 317 JfrStringPool::destroy(); 318 _stringpool = NULL; 319 } 320 if (_os_interface != NULL) { 321 JfrOSInterface::destroy(); 322 _os_interface = NULL; 323 } 324 if (_thread_sampling != NULL) { 325 JfrThreadSampling::destroy(); 326 _thread_sampling = NULL; 327 } 328 } 329 330 bool JfrRecorder::create_recorder_thread() { 331 return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current()); 332 } 333 334 void JfrRecorder::destroy() { 335 assert(is_created(), "invariant"); 336 _post_box->post(MSG_SHUTDOWN); 337 JfrJvmtiAgent::destroy(); 338 } 339 340 void JfrRecorder::on_recorder_thread_exit() { 341 assert(!is_recording(), "invariant"); 342 // intent is to destroy the recorder instance and components, 343 // but need sensitive coordination not yet in place 344 // 345 // destroy_components(); 346 // 347 log_debug(jfr, system)("Recorder thread STOPPED"); 348 } 349 350 void JfrRecorder::start_recording() { 351 _post_box->post(MSG_START); 352 } 353 354 bool JfrRecorder::is_recording() { 355 return JfrRecorderService::is_recording(); 356 } 357 358 void JfrRecorder::stop_recording() { 359 _post_box->post(MSG_STOP); 360 }