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 #include "utilities/growableArray.hpp"
50 #ifdef ASSERT
51 #include "prims/jvmtiEnvBase.hpp"
52 #endif
53
is_disabled_on_command_line()54 static bool is_disabled_on_command_line() {
55 static const size_t length = strlen("FlightRecorder");
56 static JVMFlag* const flight_recorder_flag = JVMFlag::find_flag("FlightRecorder", length);
57 assert(flight_recorder_flag != NULL, "invariant");
58 return flight_recorder_flag->is_command_line() ? !FlightRecorder : false;
59 }
60
is_disabled()61 bool JfrRecorder::is_disabled() {
62 return is_disabled_on_command_line();
63 }
64
set_flight_recorder_flag(bool flag_value)65 static bool set_flight_recorder_flag(bool flag_value) {
66 JVMFlag::boolAtPut((char*)"FlightRecorder", &flag_value, JVMFlag::MANAGEMENT);
67 return FlightRecorder;
68 }
69
70 static bool _enabled = false;
71
enable()72 static bool enable() {
73 assert(!_enabled, "invariant");
74 if (!FlightRecorder) {
75 _enabled = set_flight_recorder_flag(true);
76 }
77 return _enabled;
78 }
79
is_enabled()80 bool JfrRecorder::is_enabled() {
81 return _enabled;
82 }
83
on_create_vm_1()84 bool JfrRecorder::on_create_vm_1() {
85 if (!is_disabled()) {
86 if (FlightRecorder || StartFlightRecording != NULL) {
87 enable();
88 }
89 }
90 // fast time initialization
91 return JfrTime::initialize();
92 }
93
94 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL;
95
release_recordings()96 static void release_recordings() {
97 if (dcmd_recordings_array != NULL) {
98 const int length = dcmd_recordings_array->length();
99 for (int i = 0; i < length; ++i) {
100 delete dcmd_recordings_array->at(i);
101 }
102 delete dcmd_recordings_array;
103 dcmd_recordings_array = NULL;
104 }
105 }
106
teardown_startup_support()107 static void teardown_startup_support() {
108 release_recordings();
109 JfrOptionSet::release_start_flight_recording_options();
110 }
111
112 // Parsing options here to detect errors as soon as possible
parse_recording_options(const char * options,JfrStartFlightRecordingDCmd * dcmd_recording,TRAPS)113 static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
114 assert(options != NULL, "invariant");
115 assert(dcmd_recording != NULL, "invariant");
116 CmdLine cmdline(options, strlen(options), true);
117 dcmd_recording->parse(&cmdline, ',', THREAD);
118 if (HAS_PENDING_EXCEPTION) {
119 java_lang_Throwable::print(PENDING_EXCEPTION, tty);
120 CLEAR_PENDING_EXCEPTION;
121 return false;
122 }
123 return true;
124 }
125
validate_recording_options(TRAPS)126 static bool validate_recording_options(TRAPS) {
127 const GrowableArray<const char*>* options = JfrOptionSet::start_flight_recording_options();
128 if (options == NULL) {
129 return true;
130 }
131 const int length = options->length();
132 assert(length >= 1, "invariant");
133 assert(dcmd_recordings_array == NULL, "invariant");
134 dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, true, mtTracing);
135 assert(dcmd_recordings_array != NULL, "invariant");
136 for (int i = 0; i < length; ++i) {
137 JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true);
138 assert(dcmd_recording != NULL, "invariant");
139 dcmd_recordings_array->append(dcmd_recording);
140 if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) {
141 return false;
142 }
143 }
144 return true;
145 }
146
launch_recording(JfrStartFlightRecordingDCmd * dcmd_recording,TRAPS)147 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
148 assert(dcmd_recording != NULL, "invariant");
149 log_trace(jfr, system)("Starting a recording");
150 dcmd_recording->execute(DCmd_Source_Internal, THREAD);
151 if (HAS_PENDING_EXCEPTION) {
152 log_debug(jfr, system)("Exception while starting a recording");
153 CLEAR_PENDING_EXCEPTION;
154 return false;
155 }
156 log_trace(jfr, system)("Finished starting a recording");
157 return true;
158 }
159
launch_command_line_recordings(TRAPS)160 static bool launch_command_line_recordings(TRAPS) {
161 bool result = true;
162 if (dcmd_recordings_array != NULL) {
163 const int length = dcmd_recordings_array->length();
164 assert(length >= 1, "invariant");
165 for (int i = 0; i < length; ++i) {
166 if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) {
167 result = false;
168 break;
169 }
170 }
171 }
172 teardown_startup_support();
173 return result;
174 }
175
log_jdk_jfr_module_resolution_error(TRAPS)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
is_cds_dump_requested()183 static bool is_cds_dump_requested() {
184 // we will not be able to launch recordings if a cds dump is being requested
185 if (DumpSharedSpaces && (JfrOptionSet::start_flight_recording_options() != NULL)) {
186 warning("JFR will be disabled during CDS dumping");
187 teardown_startup_support();
188 return true;
189 }
190 return false;
191 }
192
on_create_vm_2()193 bool JfrRecorder::on_create_vm_2() {
194 if (is_cds_dump_requested()) {
195 return true;
196 }
197 Thread* const thread = Thread::current();
198 if (!JfrOptionSet::initialize(thread)) {
199 return false;
200 }
201 if (!register_jfr_dcmds()) {
202 return false;
203 }
204 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available();
205 if (in_graph) {
206 if (!validate_recording_options(thread)) {
207 return false;
208 }
209 if (!JfrOptionSet::configure(thread)) {
210 return false;
211 }
212 }
213 if (!is_enabled()) {
214 return true;
215 }
216 if (!in_graph) {
217 log_jdk_jfr_module_resolution_error(thread);
218 return false;
219 }
220 return true;
221 }
222
on_create_vm_3()223 bool JfrRecorder::on_create_vm_3() {
224 assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
225 return launch_command_line_recordings(Thread::current());
226 }
227
228 static bool _created = false;
229
230 //
231 // Main entry point for starting Jfr functionality.
232 // Non-protected initializations assume single-threaded setup.
233 //
create(bool simulate_failure)234 bool JfrRecorder::create(bool simulate_failure) {
235 assert(!is_disabled(), "invariant");
236 assert(!is_created(), "invariant");
237 if (!is_enabled()) {
238 enable();
239 }
240 if (!create_components() || simulate_failure) {
241 destroy_components();
242 return false;
243 }
244 if (!create_recorder_thread()) {
245 destroy_components();
246 return false;
247 }
248 _created = true;
249 return true;
250 }
251
is_created()252 bool JfrRecorder::is_created() {
253 return _created;
254 }
255
create_components()256 bool JfrRecorder::create_components() {
257 ResourceMark rm;
258 HandleMark hm;
259
260 if (!create_java_event_writer()) {
261 return false;
262 }
263 if (!create_jvmti_agent()) {
264 return false;
265 }
266 if (!create_post_box()) {
267 return false;
268 }
269 if (!create_chunk_repository()) {
270 return false;
271 }
272 if (!create_storage()) {
273 return false;
274 }
275 if (!create_checkpoint_manager()) {
276 return false;
277 }
278 if (!create_stacktrace_repository()) {
279 return false;
280 }
281 if (!create_os_interface()) {
282 return false;
283 }
284 if (!create_stringpool()) {
285 return false;
286 }
287 if (!create_thread_sampling()) {
288 return false;
289 }
290 return true;
291 }
292
293 // subsystems
294 static JfrPostBox* _post_box = NULL;
295 static JfrStorage* _storage = NULL;
296 static JfrCheckpointManager* _checkpoint_manager = NULL;
297 static JfrRepository* _repository = NULL;
298 static JfrStackTraceRepository* _stack_trace_repository;
299 static JfrStringPool* _stringpool = NULL;
300 static JfrOSInterface* _os_interface = NULL;
301 static JfrThreadSampling* _thread_sampling = NULL;
302
create_java_event_writer()303 bool JfrRecorder::create_java_event_writer() {
304 return JfrJavaEventWriter::initialize();
305 }
306
create_jvmti_agent()307 bool JfrRecorder::create_jvmti_agent() {
308 return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
309 }
310
create_post_box()311 bool JfrRecorder::create_post_box() {
312 assert(_post_box == NULL, "invariant");
313 _post_box = JfrPostBox::create();
314 return _post_box != NULL;
315 }
316
create_chunk_repository()317 bool JfrRecorder::create_chunk_repository() {
318 assert(_repository == NULL, "invariant");
319 assert(_post_box != NULL, "invariant");
320 _repository = JfrRepository::create(*_post_box);
321 return _repository != NULL && _repository->initialize();
322 }
323
create_os_interface()324 bool JfrRecorder::create_os_interface() {
325 assert(_os_interface == NULL, "invariant");
326 _os_interface = JfrOSInterface::create();
327 return _os_interface != NULL && _os_interface->initialize();
328 }
329
create_storage()330 bool JfrRecorder::create_storage() {
331 assert(_repository != NULL, "invariant");
332 assert(_post_box != NULL, "invariant");
333 _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
334 return _storage != NULL && _storage->initialize();
335 }
336
create_checkpoint_manager()337 bool JfrRecorder::create_checkpoint_manager() {
338 assert(_checkpoint_manager == NULL, "invariant");
339 assert(_repository != NULL, "invariant");
340 _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
341 return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
342 }
343
create_stacktrace_repository()344 bool JfrRecorder::create_stacktrace_repository() {
345 assert(_stack_trace_repository == NULL, "invariant");
346 _stack_trace_repository = JfrStackTraceRepository::create();
347 return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
348 }
349
create_stringpool()350 bool JfrRecorder::create_stringpool() {
351 assert(_stringpool == NULL, "invariant");
352 assert(_repository != NULL, "invariant");
353 _stringpool = JfrStringPool::create(_repository->chunkwriter());
354 return _stringpool != NULL && _stringpool->initialize();
355 }
356
create_thread_sampling()357 bool JfrRecorder::create_thread_sampling() {
358 assert(_thread_sampling == NULL, "invariant");
359 _thread_sampling = JfrThreadSampling::create();
360 return _thread_sampling != NULL;
361 }
362
destroy_components()363 void JfrRecorder::destroy_components() {
364 JfrJvmtiAgent::destroy();
365 if (_post_box != NULL) {
366 JfrPostBox::destroy();
367 _post_box = NULL;
368 }
369 if (_repository != NULL) {
370 JfrRepository::destroy();
371 _repository = NULL;
372 }
373 if (_storage != NULL) {
374 JfrStorage::destroy();
375 _storage = NULL;
376 }
377 if (_checkpoint_manager != NULL) {
378 JfrCheckpointManager::destroy();
379 _checkpoint_manager = NULL;
380 }
381 if (_stack_trace_repository != NULL) {
382 JfrStackTraceRepository::destroy();
383 _stack_trace_repository = NULL;
384 }
385 if (_stringpool != NULL) {
386 JfrStringPool::destroy();
387 _stringpool = NULL;
388 }
389 if (_os_interface != NULL) {
390 JfrOSInterface::destroy();
391 _os_interface = NULL;
392 }
393 if (_thread_sampling != NULL) {
394 JfrThreadSampling::destroy();
395 _thread_sampling = NULL;
396 }
397 }
398
create_recorder_thread()399 bool JfrRecorder::create_recorder_thread() {
400 return JfrRecorderThread::start(_checkpoint_manager, _post_box, Thread::current());
401 }
402
destroy()403 void JfrRecorder::destroy() {
404 assert(is_created(), "invariant");
405 _post_box->post(MSG_SHUTDOWN);
406 JfrJvmtiAgent::destroy();
407 }
408
on_recorder_thread_exit()409 void JfrRecorder::on_recorder_thread_exit() {
410 assert(!is_recording(), "invariant");
411 // intent is to destroy the recorder instance and components,
412 // but need sensitive coordination not yet in place
413 //
414 // destroy_components();
415 //
416 log_debug(jfr, system)("Recorder thread STOPPED");
417 }
418
start_recording()419 void JfrRecorder::start_recording() {
420 _post_box->post(MSG_START);
421 }
422
is_recording()423 bool JfrRecorder::is_recording() {
424 return JfrRecorderService::is_recording();
425 }
426
stop_recording()427 void JfrRecorder::stop_recording() {
428 _post_box->post(MSG_STOP);
429 }
430