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