1 /*
  2  * Copyright (c) 2012, 2021, 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 "classfile/javaClasses.hpp"
 27 #include "jfr/dcmd/jfrDcmds.hpp"
 28 #include "jfr/instrumentation/jfrJvmtiAgent.hpp"
 29 #include "jfr/jni/jfrJavaSupport.hpp"
 30 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
 31 #include "jfr/periodic/jfrOSInterface.hpp"
 32 #include "jfr/periodic/sampling/jfrThreadSampler.hpp"
 33 #include "jfr/recorder/jfrRecorder.hpp"
 34 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 35 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
 36 #include "jfr/recorder/repository/jfrRepository.hpp"
 37 #include "jfr/recorder/service/jfrEventThrottler.hpp"
 38 #include "jfr/recorder/service/jfrOptionSet.hpp"
 39 #include "jfr/recorder/service/jfrPostBox.hpp"
 40 #include "jfr/recorder/service/jfrRecorderService.hpp"
 41 #include "jfr/recorder/service/jfrRecorderThread.hpp"
 42 #include "jfr/recorder/storage/jfrStorage.hpp"
 43 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
 44 #include "jfr/recorder/stringpool/jfrStringPool.hpp"
 45 #include "jfr/support/jfrJavaThread.hpp"
 46 #include "jfr/utilities/jfrTime.hpp"
 47 #include "jfr/writers/jfrJavaEventWriter.hpp"
 48 #include "logging/log.hpp"
 49 #include "logging/logStream.hpp"
 50 #include "memory/resourceArea.inline.hpp"
 51 #include "runtime/handles.inline.hpp"
 52 #include "runtime/globals_extension.hpp"
 53 #include "utilities/growableArray.hpp"
 54 #ifdef ASSERT
 55 #include "prims/jvmtiEnvBase.hpp"
 56 #endif
 57 
 58 bool JfrRecorder::is_disabled() {
 59   // True if -XX:-FlightRecorder has been explicitly set on the
 60   // command line
 61   return FLAG_IS_CMDLINE(FlightRecorder) ? !FlightRecorder : false;
 62 }
 63 
 64 static bool _enabled = false;
 65 
 66 static bool enable() {
 67   assert(!_enabled, "invariant");
 68   if (!FlightRecorder) {
 69     FLAG_SET_MGMT(FlightRecorder, true);
 70   }
 71   _enabled = FlightRecorder;
 72   assert(_enabled, "invariant");
 73   return _enabled;
 74 }
 75 
 76 bool JfrRecorder::is_enabled() {
 77   return _enabled;
 78 }
 79 
 80 bool JfrRecorder::create_oop_storages() {
 81   // currently only a single weak oop storage for Leak Profiler
 82   return ObjectSampler::create_oop_storage();
 83 }
 84 
 85 bool JfrRecorder::on_create_vm_1() {
 86   if (!is_disabled()) {
 87     if (FlightRecorder || StartFlightRecording != NULL) {
 88       enable();
 89     }
 90   }
 91   if (!create_oop_storages()) {
 92     return false;
 93   }
 94   // fast time initialization
 95   return JfrTime::initialize();
 96 }
 97 
 98 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL;
 99 
100 static void release_recordings() {
101   if (dcmd_recordings_array != NULL) {
102     const int length = dcmd_recordings_array->length();
103     for (int i = 0; i < length; ++i) {
104       delete dcmd_recordings_array->at(i);
105     }
106     delete dcmd_recordings_array;
107     dcmd_recordings_array = NULL;
108   }
109 }
110 
111 static void teardown_startup_support() {
112   release_recordings();
113   JfrOptionSet::release_start_flight_recording_options();
114 }
115 
116 // Parsing options here to detect errors as soon as possible
117 static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
118   assert(options != NULL, "invariant");
119   assert(dcmd_recording != NULL, "invariant");
120   CmdLine cmdline(options, strlen(options), true);
121   dcmd_recording->parse(&cmdline, ',', THREAD);
122   if (HAS_PENDING_EXCEPTION) {
123     java_lang_Throwable::print(PENDING_EXCEPTION, tty);
124     CLEAR_PENDING_EXCEPTION;
125     return false;
126   }
127   return true;
128 }
129 
130 static bool validate_recording_options(TRAPS) {
131   const GrowableArray<const char*>* options = JfrOptionSet::start_flight_recording_options();
132   if (options == NULL) {
133     return true;
134   }
135   const int length = options->length();
136   assert(length >= 1, "invariant");
137   assert(dcmd_recordings_array == NULL, "invariant");
138   dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, mtTracing);
139   assert(dcmd_recordings_array != NULL, "invariant");
140   for (int i = 0; i < length; ++i) {
141     JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true);
142     assert(dcmd_recording != NULL, "invariant");
143     dcmd_recordings_array->append(dcmd_recording);
144     if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) {
145       return false;
146     }
147   }
148   return true;
149 }
150 
151 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) {
152   assert(dcmd_recording != NULL, "invariant");
153   log_trace(jfr, system)("Starting a recording");
154   dcmd_recording->execute(DCmd_Source_Internal, THREAD);
155   if (HAS_PENDING_EXCEPTION) {
156     log_debug(jfr, system)("Exception while starting a recording");
157     CLEAR_PENDING_EXCEPTION;
158     return false;
159   }
160   log_trace(jfr, system)("Finished starting a recording");
161   return true;
162 }
163 
164 static bool launch_command_line_recordings(TRAPS) {
165   bool result = true;
166   if (dcmd_recordings_array != NULL) {
167     const int length = dcmd_recordings_array->length();
168     assert(length >= 1, "invariant");
169     for (int i = 0; i < length; ++i) {
170       if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) {
171         result = false;
172         break;
173       }
174     }
175   }
176   teardown_startup_support();
177   return result;
178 }
179 
180 static void log_jdk_jfr_module_resolution_error(TRAPS) {
181   LogTarget(Error, jfr, system) lt_error;
182   LogTargetHandle handle(lt_error);
183   LogStream stream(handle);
184   JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD);
185 }
186 
187 static bool is_cds_dump_requested() {
188   // we will not be able to launch recordings on startup if a cds dump is being requested
189   if (Arguments::is_dumping_archive() && JfrOptionSet::start_flight_recording_options() != NULL) {
190     warning("JFR will be disabled during CDS dumping");
191     teardown_startup_support();
192     return true;
193   }
194   return false;
195 }
196 
197 bool JfrRecorder::on_create_vm_2() {
198   if (is_cds_dump_requested()) {
199     return true;
200   }
201   if (!JfrTraceId::initialize()) {
202     return false;
203   }
204   JavaThread* const thread = JavaThread::current();
205   if (!JfrOptionSet::initialize(thread)) {
206     return false;
207   }
208   if (!register_jfr_dcmds()) {
209     return false;
210   }
211   const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available();
212   if (in_graph) {
213     if (!validate_recording_options(thread)) {
214       return false;
215     }
216     if (!JfrOptionSet::configure(thread)) {
217       return false;
218     }
219   }
220   if (!is_enabled()) {
221     return true;
222   }
223   if (!in_graph) {
224     log_jdk_jfr_module_resolution_error(thread);
225     return false;
226   }
227   return true;
228 }
229 
230 bool JfrRecorder::on_create_vm_3() {
231   assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
232   return Arguments::is_dumping_archive() || launch_command_line_recordings(JavaThread::current());
233 }
234 
235 static bool _created = false;
236 
237 //
238 // Main entry point for starting Jfr functionality.
239 // Non-protected initializations assume single-threaded setup.
240 //
241 bool JfrRecorder::create(bool simulate_failure) {
242   assert(!is_disabled(), "invariant");
243   assert(!is_created(), "invariant");
244   if (!is_enabled()) {
245     enable();
246   }
247   if (!create_components() || simulate_failure) {
248     destroy_components();
249     return false;
250   }
251   if (!create_recorder_thread()) {
252     destroy_components();
253     return false;
254   }
255   _created = true;
256   return true;
257 }
258 
259 bool JfrRecorder::is_created() {
260   return _created;
261 }
262 
263 bool JfrRecorder::create_components() {
264   // Move these down into the functions that might create handles!
265   ResourceMark rm(Thread::current());
266   HandleMark hm(Thread::current());
267 
268   if (!create_java_event_writer()) {
269     return false;
270   }
271   if (!create_jvmti_agent()) {
272     return false;
273   }
274   if (!create_post_box()) {
275     return false;
276   }
277   if (!create_chunk_repository()) {
278     return false;
279   }
280   if (!create_storage()) {
281     return false;
282   }
283   if (!create_checkpoint_manager()) {
284     return false;
285   }
286   if (!create_stacktrace_repository()) {
287     return false;
288   }
289   if (!create_os_interface()) {
290     return false;
291   }
292   if (!create_stringpool()) {
293     return false;
294   }
295   if (!create_thread_sampling()) {
296     return false;
297   }
298   if (!create_event_throttler()) {
299     return false;
300   }
301   if (!create_virtual_thread_support()) {
302     return false;
303   }
304   return true;
305 }
306 
307 // subsystems
308 static JfrPostBox* _post_box = NULL;
309 static JfrStorage* _storage = NULL;
310 static JfrCheckpointManager* _checkpoint_manager = NULL;
311 static JfrRepository* _repository = NULL;
312 static JfrStackTraceRepository* _stack_trace_repository;
313 static JfrStringPool* _stringpool = NULL;
314 static JfrOSInterface* _os_interface = NULL;
315 static JfrThreadSampling* _thread_sampling = NULL;
316 
317 bool JfrRecorder::create_java_event_writer() {
318   return JfrJavaEventWriter::initialize();
319 }
320 
321 bool JfrRecorder::create_jvmti_agent() {
322   return JfrOptionSet::allow_retransforms() ? JfrJvmtiAgent::create() : true;
323 }
324 
325 bool JfrRecorder::create_post_box() {
326   assert(_post_box == NULL, "invariant");
327   _post_box = JfrPostBox::create();
328   return _post_box != NULL;
329 }
330 
331 bool JfrRecorder::create_chunk_repository() {
332   assert(_repository == NULL, "invariant");
333   assert(_post_box != NULL, "invariant");
334   _repository = JfrRepository::create(*_post_box);
335   return _repository != NULL && _repository->initialize();
336 }
337 
338 bool JfrRecorder::create_os_interface() {
339   assert(_os_interface == NULL, "invariant");
340   _os_interface = JfrOSInterface::create();
341   return _os_interface != NULL && _os_interface->initialize();
342 }
343 
344 bool JfrRecorder::create_storage() {
345   assert(_repository != NULL, "invariant");
346   assert(_post_box != NULL, "invariant");
347   _storage = JfrStorage::create(_repository->chunkwriter(), *_post_box);
348   return _storage != NULL && _storage->initialize();
349 }
350 
351 bool JfrRecorder::create_checkpoint_manager() {
352   assert(_checkpoint_manager == NULL, "invariant");
353   assert(_repository != NULL, "invariant");
354   _checkpoint_manager = JfrCheckpointManager::create(_repository->chunkwriter());
355   return _checkpoint_manager != NULL && _checkpoint_manager->initialize();
356 }
357 
358 bool JfrRecorder::create_stacktrace_repository() {
359   assert(_stack_trace_repository == NULL, "invariant");
360   _stack_trace_repository = JfrStackTraceRepository::create();
361   return _stack_trace_repository != NULL && _stack_trace_repository->initialize();
362 }
363 
364 bool JfrRecorder::create_stringpool() {
365   assert(_stringpool == NULL, "invariant");
366   assert(_repository != NULL, "invariant");
367   _stringpool = JfrStringPool::create(_repository->chunkwriter());
368   return _stringpool != NULL && _stringpool->initialize();
369 }
370 
371 bool JfrRecorder::create_thread_sampling() {
372   assert(_thread_sampling == NULL, "invariant");
373   _thread_sampling = JfrThreadSampling::create();
374   return _thread_sampling != NULL;
375 }
376 
377 bool JfrRecorder::create_event_throttler() {
378   return JfrEventThrottler::create();
379 }
380 
381 bool JfrRecorder::create_virtual_thread_support() {
382   // bool parameter, notifyJvmti, enables jvmti events related to VirtualThreads.
383   // Thread start events hooks into some of these callbacks for JFR.
384   return JfrJavaThread::initialize(false);
385 }
386 
387 void JfrRecorder::destroy_components() {
388   JfrJvmtiAgent::destroy();
389   if (_post_box != NULL) {
390     JfrPostBox::destroy();
391     _post_box = NULL;
392   }
393   if (_repository != NULL) {
394     JfrRepository::destroy();
395     _repository = NULL;
396   }
397   if (_storage != NULL) {
398     JfrStorage::destroy();
399     _storage = NULL;
400   }
401   if (_checkpoint_manager != NULL) {
402     JfrCheckpointManager::destroy();
403     _checkpoint_manager = NULL;
404   }
405   if (_stack_trace_repository != NULL) {
406     JfrStackTraceRepository::destroy();
407     _stack_trace_repository = NULL;
408   }
409   if (_stringpool != NULL) {
410     JfrStringPool::destroy();
411     _stringpool = NULL;
412   }
413   if (_os_interface != NULL) {
414     JfrOSInterface::destroy();
415     _os_interface = NULL;
416   }
417   if (_thread_sampling != NULL) {
418     JfrThreadSampling::destroy();
419     _thread_sampling = NULL;
420   }
421   JfrEventThrottler::destroy();
422 }
423 
424 bool JfrRecorder::create_recorder_thread() {
425   return JfrRecorderThread::start(_checkpoint_manager, _post_box, JavaThread::current());
426 }
427 
428 void JfrRecorder::destroy() {
429   assert(is_created(), "invariant");
430   _post_box->post(MSG_SHUTDOWN);
431   JfrJvmtiAgent::destroy();
432 }
433 
434 void JfrRecorder::on_recorder_thread_exit() {
435   assert(!is_recording(), "invariant");
436   // intent is to destroy the recorder instance and components,
437   // but need sensitive coordination not yet in place
438   //
439   // destroy_components();
440   //
441   log_debug(jfr, system)("Recorder thread STOPPED");
442 }
443 
444 void JfrRecorder::start_recording() {
445   _post_box->post(MSG_START);
446 }
447 
448 bool JfrRecorder::is_recording() {
449   return JfrRecorderService::is_recording();
450 }
451 
452 void JfrRecorder::stop_recording() {
453   _post_box->post(MSG_STOP);
454 }