1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/jfr/recorder/jfrRecorder.cpp Mon Aug 12 18:30:40 2019 +0300 1.3 @@ -0,0 +1,409 @@ 1.4 +/* 1.5 + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "jfr/dcmd/jfrDcmds.hpp" 1.30 +#include "jfr/instrumentation/jfrJvmtiAgent.hpp" 1.31 +#include "jfr/jni/jfrJavaSupport.hpp" 1.32 +#include "jfr/periodic/jfrOSInterface.hpp" 1.33 +#include "jfr/periodic/sampling/jfrThreadSampler.hpp" 1.34 +#include "jfr/recorder/jfrRecorder.hpp" 1.35 +#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" 1.36 +#include "jfr/recorder/repository/jfrRepository.hpp" 1.37 +#include "jfr/recorder/service/jfrOptionSet.hpp" 1.38 +#include "jfr/recorder/service/jfrPostBox.hpp" 1.39 +#include "jfr/recorder/service/jfrRecorderService.hpp" 1.40 +#include "jfr/recorder/service/jfrRecorderThread.hpp" 1.41 +#include "jfr/recorder/storage/jfrStorage.hpp" 1.42 +#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" 1.43 +#include "jfr/recorder/stringpool/jfrStringPool.hpp" 1.44 +#include "jfr/utilities/jfrTime.hpp" 1.45 +#include "jfr/writers/jfrJavaEventWriter.hpp" 1.46 +#include "memory/resourceArea.hpp" 1.47 +#include "runtime/handles.inline.hpp" 1.48 +#include "runtime/globals.hpp" 1.49 +#include "utilities/growableArray.hpp" 1.50 + 1.51 +bool JfrRecorder::_shutting_down = false; 1.52 + 1.53 +static bool is_disabled_on_command_line() { 1.54 + static const size_t length = strlen("FlightRecorder"); 1.55 + static Flag* const flight_recorder_flag = Flag::find_flag("FlightRecorder", length); 1.56 + assert(flight_recorder_flag != NULL, "invariant"); 1.57 + return flight_recorder_flag->is_command_line() ? !FlightRecorder : false; 1.58 +} 1.59 + 1.60 +bool JfrRecorder::is_disabled() { 1.61 + return is_disabled_on_command_line(); 1.62 +} 1.63 + 1.64 +static bool set_flight_recorder_flag(bool flag_value) { 1.65 + CommandLineFlags::boolAtPut((char*)"FlightRecorder", &flag_value, Flag::MANAGEMENT); 1.66 + return FlightRecorder; 1.67 +} 1.68 + 1.69 +static bool _enabled = false; 1.70 + 1.71 +static bool enable() { 1.72 + assert(!_enabled, "invariant"); 1.73 + _enabled = set_flight_recorder_flag(true); 1.74 + return _enabled; 1.75 +} 1.76 + 1.77 +bool JfrRecorder::is_enabled() { 1.78 + return _enabled; 1.79 +} 1.80 + 1.81 +bool JfrRecorder::on_vm_init() { 1.82 + if (!is_disabled()) { 1.83 + if (FlightRecorder || StartFlightRecording != NULL) { 1.84 + enable(); 1.85 + } 1.86 + } 1.87 + // fast time initialization 1.88 + return JfrTime::initialize(); 1.89 +} 1.90 + 1.91 +static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL; 1.92 + 1.93 +static void release_recordings() { 1.94 + if (dcmd_recordings_array != NULL) { 1.95 + const int length = dcmd_recordings_array->length(); 1.96 + for (int i = 0; i < length; ++i) { 1.97 + delete dcmd_recordings_array->at(i); 1.98 + } 1.99 + delete dcmd_recordings_array; 1.100 + dcmd_recordings_array = NULL; 1.101 + } 1.102 +} 1.103 + 1.104 +static void teardown_startup_support() { 1.105 + release_recordings(); 1.106 + JfrOptionSet::release_startup_recording_options(); 1.107 +} 1.108 + 1.109 +// Parsing options here to detect errors as soon as possible 1.110 +static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) { 1.111 + assert(options != NULL, "invariant"); 1.112 + assert(dcmd_recording != NULL, "invariant"); 1.113 + CmdLine cmdline(options, strlen(options), true); 1.114 + dcmd_recording->parse(&cmdline, ',', THREAD); 1.115 + if (HAS_PENDING_EXCEPTION) { 1.116 + java_lang_Throwable::print(PENDING_EXCEPTION, tty); 1.117 + CLEAR_PENDING_EXCEPTION; 1.118 + return false; 1.119 + } 1.120 + return true; 1.121 +} 1.122 + 1.123 +static bool validate_recording_options(TRAPS) { 1.124 + const GrowableArray<const char*>* options = JfrOptionSet::startup_recording_options(); 1.125 + if (options == NULL) { 1.126 + return true; 1.127 + } 1.128 + const int length = options->length(); 1.129 + assert(length >= 1, "invariant"); 1.130 + assert(dcmd_recordings_array == NULL, "invariant"); 1.131 + dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, true, mtTracing); 1.132 + assert(dcmd_recordings_array != NULL, "invariant"); 1.133 + for (int i = 0; i < length; ++i) { 1.134 + JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true); 1.135 + assert(dcmd_recording != NULL, "invariant"); 1.136 + dcmd_recordings_array->append(dcmd_recording); 1.137 + if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) { 1.138 + return false; 1.139 + } 1.140 + } 1.141 + return true; 1.142 +} 1.143 + 1.144 +static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) { 1.145 + assert(dcmd_recording != NULL, "invariant"); 1.146 + if (LogJFR && Verbose) tty->print_cr("Starting a recording"); 1.147 + dcmd_recording->execute(DCmd_Source_Internal, THREAD); 1.148 + if (HAS_PENDING_EXCEPTION) { 1.149 + if (LogJFR) tty->print_cr("Exception while starting a recording"); 1.150 + CLEAR_PENDING_EXCEPTION; 1.151 + return false; 1.152 + } 1.153 + if (LogJFR && Verbose) tty->print_cr("Finished starting a recording"); 1.154 + return true; 1.155 +} 1.156 + 1.157 +static bool launch_recordings(TRAPS) { 1.158 + bool result = true; 1.159 + if (dcmd_recordings_array != NULL) { 1.160 + const int length = dcmd_recordings_array->length(); 1.161 + assert(length >= 1, "invariant"); 1.162 + for (int i = 0; i < length; ++i) { 1.163 + if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) { 1.164 + result = false; 1.165 + break; 1.166 + } 1.167 + } 1.168 + } 1.169 + teardown_startup_support(); 1.170 + return result; 1.171 +} 1.172 + 1.173 +static bool is_cds_dump_requested() { 1.174 + // we will not be able to launch recordings if a cds dump is being requested 1.175 + if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) { 1.176 + warning("JFR will be disabled during CDS dumping"); 1.177 + teardown_startup_support(); 1.178 + return true; 1.179 + } 1.180 + return false; 1.181 +} 1.182 + 1.183 +bool JfrRecorder::on_vm_start() { 1.184 + if (is_cds_dump_requested()) { 1.185 + return true; 1.186 + } 1.187 + Thread* const thread = Thread::current(); 1.188 + if (!JfrJavaEventWriter::has_required_classes(thread)) { 1.189 + // assume it is compact profile of jfr.jar is missed for some reasons 1.190 + // skip further initialization. 1.191 + return true; 1.192 + } 1.193 + if (!JfrOptionSet::initialize(thread)) { 1.194 + return false; 1.195 + } 1.196 + if (!register_jfr_dcmds()) { 1.197 + return false; 1.198 + } 1.199 + 1.200 + if (!validate_recording_options(thread)) { 1.201 + return false; 1.202 + } 1.203 + if (!JfrJavaEventWriter::initialize()) { 1.204 + return false; 1.205 + } 1.206 + if (!JfrOptionSet::configure(thread)) { 1.207 + return false; 1.208 + } 1.209 + 1.210 + if (!is_enabled()) { 1.211 + return true; 1.212 + } 1.213 + 1.214 + return launch_recordings(thread); 1.215 +} 1.216 + 1.217 +static bool _created = false; 1.218 + 1.219 +// 1.220 +// Main entry point for starting Jfr functionality. 1.221 +// Non-protected initializations assume single-threaded setup. 1.222 +// 1.223 +bool JfrRecorder::create(bool simulate_failure) { 1.224 + assert(!is_disabled(), "invariant"); 1.225 + assert(!is_created(), "invariant"); 1.226 + if (!is_enabled()) { 1.227 + enable(); 1.228 + } 1.229 + if (!create_components() || simulate_failure) { 1.230 + destroy_components(); 1.231 + return false; 1.232 + } 1.233 + if (!create_recorder_thread()) { 1.234 + destroy_components(); 1.235 + return false; 1.236 + } 1.237 + _created = true; 1.238 + return true; 1.239 +} 1.240 + 1.241 +bool JfrRecorder::is_created() { 1.242 + return _created; 1.243 +} 1.244 + 1.245 +bool JfrRecorder::create_components() { 1.246 + ResourceMark rm; 1.247 + HandleMark hm; 1.248 + 1.249 + if (!create_jvmti_agent()) { 1.250 + return false; 1.251 + } 1.252 + if (!create_post_box()) { 1.253 + return false; 1.254 + } 1.255 + if (!create_chunk_repository()) { 1.256 + return false; 1.257 + } 1.258 + if (!create_storage()) { 1.259 + return false; 1.260 + } 1.261 + if (!create_checkpoint_manager()) { 1.262 + return false; 1.263 + } 1.264 + if (!create_stacktrace_repository()) { 1.265 + return false; 1.266 + } 1.267 + if (!create_os_interface()) { 1.268 + return false; 1.269 + } 1.270 + if (!create_stringpool()) { 1.271 + return false; 1.272 + } 1.273 + if (!create_thread_sampling()) { 1.274 + return false; 1.275 + } 1.276 + return true; 1.277 +} 1.278 + 1.279 +// subsystems 1.280 +static JfrJvmtiAgent* _jvmti_agent = NULL; 1.281 +static JfrPostBox* _post_box = NULL; 1.282 +static JfrStorage* _storage = NULL; 1.283 +static JfrCheckpointManager* _checkpoint_manager = NULL; 1.284 +static JfrRepository* _repository = NULL; 1.285 +static JfrStackTraceRepository* _stack_trace_repository; 1.286 +static JfrStringPool* _stringpool = NULL; 1.287 +static JfrOSInterface* _os_interface = NULL; 1.288 +static JfrThreadSampling* _thread_sampling = NULL; 1.289 + 1.290 +bool JfrRecorder::create_jvmti_agent() { 1.291 + return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true; 1.292 +} 1.293 + 1.294 +bool JfrRecorder::create_post_box() { 1.295 + assert(_post_box == NULL, "invariant"); 1.296 + _post_box = JfrPostBox::create(); 1.297 + return _post_box != NULL; 1.298 +} 1.299 + 1.300 +bool JfrRecorder::create_chunk_repository() { 1.301 + assert(_repository == NULL, "invariant"); 1.302 + assert(_post_box != NULL, "invariant"); 1.303 + _repository = JfrRepository::create(*_post_box); 1.304 + return _repository != NULL && _repository->initialize(); 1.305 +} 1.306 + 1.307 +bool JfrRecorder::create_os_interface() { 1.308 + assert(_os_interface == NULL, "invariant"); 1.309 + _os_interface = JfrOSInterface::create(); 1.310 + return _os_interface != NULL && _os_interface->initialize(); 1.311 +} 1.312 + 1.313 +bool JfrRecorder::create_storage() { 1.314 + assert(_repository != NULL, "invariant"); 1.315 + assert(_post_box != NULL, "invariant"); 1.316 + _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box); 1.317 + return _storage != NULL && _storage->initialize(); 1.318 +} 1.319 + 1.320 +bool JfrRecorder::create_checkpoint_manager() { 1.321 + assert(_checkpoint_manager == NULL, "invariant"); 1.322 + assert(_repository != NULL, "invariant"); 1.323 + _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter()); 1.324 + return _checkpoint_manager != NULL && _checkpoint_manager->initialize(); 1.325 +} 1.326 + 1.327 +bool JfrRecorder::create_stacktrace_repository() { 1.328 + assert(_stack_trace_repository == NULL, "invariant"); 1.329 + _stack_trace_repository = JfrStackTraceRepository::create(); 1.330 + return _stack_trace_repository != NULL && _stack_trace_repository->initialize(); 1.331 +} 1.332 + 1.333 +bool JfrRecorder::create_stringpool() { 1.334 + assert(_stringpool == NULL, "invariant"); 1.335 + assert(_repository != NULL, "invariant"); 1.336 + _stringpool = JfrStringPool::create(_repository->chunkwriter()); 1.337 + return _stringpool != NULL && _stringpool->initialize(); 1.338 +} 1.339 + 1.340 +bool JfrRecorder::create_thread_sampling() { 1.341 + assert(_thread_sampling == NULL, "invariant"); 1.342 + _thread_sampling = JfrThreadSampling::create(); 1.343 + return _thread_sampling != NULL; 1.344 +} 1.345 + 1.346 +void JfrRecorder::destroy_components() { 1.347 + JfrJvmtiAgent::destroy(); 1.348 + if (_post_box != NULL) { 1.349 + JfrPostBox::destroy(); 1.350 + _post_box = NULL; 1.351 + } 1.352 + if (_repository != NULL) { 1.353 + JfrRepository::destroy(); 1.354 + _repository = NULL; 1.355 + } 1.356 + if (_storage != NULL) { 1.357 + JfrStorage::destroy(); 1.358 + _storage = NULL; 1.359 + } 1.360 + if (_checkpoint_manager != NULL) { 1.361 + JfrCheckpointManager::destroy(); 1.362 + _checkpoint_manager = NULL; 1.363 + } 1.364 + if (_stack_trace_repository != NULL) { 1.365 + JfrStackTraceRepository::destroy(); 1.366 + _stack_trace_repository = NULL; 1.367 + } 1.368 + if (_stringpool != NULL) { 1.369 + JfrStringPool::destroy(); 1.370 + _stringpool = NULL; 1.371 + } 1.372 + if (_os_interface != NULL) { 1.373 + JfrOSInterface::destroy(); 1.374 + _os_interface = NULL; 1.375 + } 1.376 + if (_thread_sampling != NULL) { 1.377 + JfrThreadSampling::destroy(); 1.378 + _thread_sampling = NULL; 1.379 + } 1.380 +} 1.381 + 1.382 +bool JfrRecorder::create_recorder_thread() { 1.383 + return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current()); 1.384 +} 1.385 + 1.386 +void JfrRecorder::destroy() { 1.387 + assert(is_created(), "invariant"); 1.388 + _post_box->post(MSG_SHUTDOWN); 1.389 + JfrJvmtiAgent::destroy(); 1.390 +} 1.391 + 1.392 +void JfrRecorder::on_recorder_thread_exit() { 1.393 + assert(!is_recording(), "invariant"); 1.394 + // intent is to destroy the recorder instance and components, 1.395 + // but need sensitive coordination not yet in place 1.396 + // 1.397 + // destroy_components(); 1.398 + // 1.399 + if (LogJFR) tty->print_cr("Recorder thread STOPPED"); 1.400 +} 1.401 + 1.402 +void JfrRecorder::start_recording() { 1.403 + _post_box->post(MSG_START); 1.404 +} 1.405 + 1.406 +bool JfrRecorder::is_recording() { 1.407 + return JfrRecorderService::is_recording(); 1.408 +} 1.409 + 1.410 +void JfrRecorder::stop_recording() { 1.411 + _post_box->post(MSG_STOP); 1.412 +}