83 } |
84 } |
84 // fast time initialization |
85 // fast time initialization |
85 return JfrTime::initialize(); |
86 return JfrTime::initialize(); |
86 } |
87 } |
87 |
88 |
88 static JfrStartFlightRecordingDCmd* _startup_recording = NULL; |
89 static GrowableArray<JfrStartFlightRecordingDCmd*>* dcmd_recordings_array = NULL; |
89 |
90 |
90 static void release_startup_recording() { |
91 static void release_recordings() { |
91 if (_startup_recording != NULL) { |
92 if (dcmd_recordings_array != NULL) { |
92 delete _startup_recording; |
93 const int length = dcmd_recordings_array->length(); |
93 _startup_recording = NULL; |
94 for (int i = 0; i < length; ++i) { |
|
95 delete dcmd_recordings_array->at(i); |
|
96 } |
|
97 delete dcmd_recordings_array; |
|
98 dcmd_recordings_array = NULL; |
94 } |
99 } |
95 } |
100 } |
96 |
101 |
97 static void teardown_startup_support() { |
102 static void teardown_startup_support() { |
98 release_startup_recording(); |
103 release_recordings(); |
99 JfrOptionSet::release_startup_recordings(); |
104 JfrOptionSet::release_startup_recording_options(); |
100 } |
105 } |
101 |
|
102 |
106 |
103 // Parsing options here to detect errors as soon as possible |
107 // Parsing options here to detect errors as soon as possible |
104 static bool parse_recording_options(const char* options, TRAPS) { |
108 static bool parse_recording_options(const char* options, JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) { |
105 assert(options != NULL, "invariant"); |
109 assert(options != NULL, "invariant"); |
106 if (_startup_recording != NULL) { |
110 assert(dcmd_recording != NULL, "invariant"); |
107 delete _startup_recording; |
|
108 } |
|
109 CmdLine cmdline(options, strlen(options), true); |
111 CmdLine cmdline(options, strlen(options), true); |
110 _startup_recording = new (ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true); |
112 dcmd_recording->parse(&cmdline, ',', THREAD); |
111 assert(_startup_recording != NULL, "invariant"); |
|
112 _startup_recording->parse(&cmdline, ',', THREAD); |
|
113 if (HAS_PENDING_EXCEPTION) { |
113 if (HAS_PENDING_EXCEPTION) { |
114 java_lang_Throwable::print(PENDING_EXCEPTION, tty); |
114 java_lang_Throwable::print(PENDING_EXCEPTION, tty); |
115 CLEAR_PENDING_EXCEPTION; |
115 CLEAR_PENDING_EXCEPTION; |
116 return false; |
116 return false; |
117 } |
117 } |
118 return true; |
118 return true; |
119 } |
119 } |
120 |
120 |
121 static bool validate_recording_options(TRAPS) { |
121 static bool validate_recording_options(TRAPS) { |
122 const GrowableArray<const char*>* startup_options = JfrOptionSet::startup_recordings(); |
122 const GrowableArray<const char*>* options = JfrOptionSet::startup_recording_options(); |
123 if (startup_options == NULL) { |
123 if (options == NULL) { |
124 return true; |
124 return true; |
125 } |
125 } |
126 const int length = startup_options->length(); |
126 const int length = options->length(); |
127 assert(length >= 1, "invariant"); |
127 assert(length >= 1, "invariant"); |
|
128 assert(dcmd_recordings_array == NULL, "invariant"); |
|
129 dcmd_recordings_array = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<JfrStartFlightRecordingDCmd*>(length, true, mtTracing); |
|
130 assert(dcmd_recordings_array != NULL, "invariant"); |
128 for (int i = 0; i < length; ++i) { |
131 for (int i = 0; i < length; ++i) { |
129 if (!parse_recording_options(startup_options->at(i), THREAD)) { |
132 JfrStartFlightRecordingDCmd* const dcmd_recording = new(ResourceObj::C_HEAP, mtTracing) JfrStartFlightRecordingDCmd(tty, true); |
|
133 assert(dcmd_recording != NULL, "invariant"); |
|
134 dcmd_recordings_array->append(dcmd_recording); |
|
135 if (!parse_recording_options(options->at(i), dcmd_recording, THREAD)) { |
130 return false; |
136 return false; |
131 } |
137 } |
132 } |
138 } |
133 return true; |
139 return true; |
134 } |
140 } |
135 |
141 |
136 static bool launch_recording(TRAPS) { |
142 static bool launch_recording(JfrStartFlightRecordingDCmd* dcmd_recording, TRAPS) { |
137 assert(_startup_recording != NULL, "invariant"); |
143 assert(dcmd_recording != NULL, "invariant"); |
138 log_trace(jfr, system)("Starting a recording"); |
144 log_trace(jfr, system)("Starting a recording"); |
139 _startup_recording->execute(DCmd_Source_Internal, Thread::current()); |
145 dcmd_recording->execute(DCmd_Source_Internal, THREAD); |
140 if (HAS_PENDING_EXCEPTION) { |
146 if (HAS_PENDING_EXCEPTION) { |
141 log_debug(jfr, system)("Exception while starting a recording"); |
147 log_debug(jfr, system)("Exception while starting a recording"); |
142 CLEAR_PENDING_EXCEPTION; |
148 CLEAR_PENDING_EXCEPTION; |
143 return false; |
149 return false; |
144 } |
150 } |
145 log_trace(jfr, system)("Finished starting a recording"); |
151 log_trace(jfr, system)("Finished starting a recording"); |
146 return true; |
152 return true; |
147 } |
153 } |
148 |
154 |
149 static bool launch_recordings(const GrowableArray<const char*>* startup_options, TRAPS) { |
155 static bool launch_recordings(TRAPS) { |
150 assert(startup_options != NULL, "invariant"); |
156 bool result = true; |
151 const int length = startup_options->length(); |
157 if (dcmd_recordings_array != NULL) { |
152 assert(length >= 1, "invariant"); |
158 const int length = dcmd_recordings_array->length(); |
153 if (length == 1) { |
159 assert(length >= 1, "invariant"); |
154 // already parsed and ready, launch it |
160 for (int i = 0; i < length; ++i) { |
155 return launch_recording(THREAD); |
161 if (!launch_recording(dcmd_recordings_array->at(i), THREAD)) { |
156 } |
162 result = false; |
157 for (int i = 0; i < length; ++i) { |
163 break; |
158 parse_recording_options(startup_options->at(i), THREAD); |
164 } |
159 if (!launch_recording(THREAD)) { |
165 } |
160 return false; |
166 } |
161 } |
|
162 } |
|
163 return true; |
|
164 } |
|
165 |
|
166 static bool startup_recordings(TRAPS) { |
|
167 const GrowableArray<const char*>* startup_options = JfrOptionSet::startup_recordings(); |
|
168 if (startup_options == NULL) { |
|
169 return true; |
|
170 } |
|
171 const bool ret = launch_recordings(startup_options, THREAD); |
|
172 teardown_startup_support(); |
167 teardown_startup_support(); |
173 return ret; |
168 return result; |
174 } |
169 } |
175 |
170 |
176 static void log_jdk_jfr_module_resolution_error(TRAPS) { |
171 static void log_jdk_jfr_module_resolution_error(TRAPS) { |
177 LogTarget(Error, jfr, system) lt_error; |
172 LogTarget(Error, jfr, system) lt_error; |
178 LogTargetHandle handle(lt_error); |
173 LogTargetHandle handle(lt_error); |
179 LogStream stream(handle); |
174 LogStream stream(handle); |
180 JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD); |
175 JfrJavaSupport::is_jdk_jfr_module_available(&stream, THREAD); |
181 } |
176 } |
182 |
177 |
183 bool JfrRecorder::on_vm_start() { |
178 static bool is_cds_dump_requested() { |
184 if (DumpSharedSpaces && (JfrOptionSet::startup_recordings() != NULL)) { |
179 // we will not be able to launch recordings if a cds dump is being requested |
|
180 if (DumpSharedSpaces && (JfrOptionSet::startup_recording_options() != NULL)) { |
185 warning("JFR will be disabled during CDS dumping"); |
181 warning("JFR will be disabled during CDS dumping"); |
186 teardown_startup_support(); |
182 teardown_startup_support(); |
187 return true; |
183 return true; |
188 } |
184 } |
189 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); |
185 return false; |
|
186 } |
|
187 |
|
188 bool JfrRecorder::on_vm_start() { |
|
189 if (is_cds_dump_requested()) { |
|
190 return true; |
|
191 } |
190 Thread* const thread = Thread::current(); |
192 Thread* const thread = Thread::current(); |
191 if (!JfrOptionSet::initialize(thread)) { |
193 if (!JfrOptionSet::initialize(thread)) { |
192 return false; |
194 return false; |
193 } |
195 } |
194 if (!register_jfr_dcmds()) { |
196 if (!register_jfr_dcmds()) { |
195 return false; |
197 return false; |
196 } |
198 } |
197 if (!validate_recording_options(thread)) { |
199 |
198 return false; |
200 const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); |
199 } |
201 |
200 if (in_graph) { |
202 if (in_graph) { |
|
203 if (!validate_recording_options(thread)) { |
|
204 return false; |
|
205 } |
201 if (!JfrJavaEventWriter::initialize()) { |
206 if (!JfrJavaEventWriter::initialize()) { |
202 return false; |
207 return false; |
203 } |
208 } |
204 if (!JfrOptionSet::configure(thread)) { |
209 if (!JfrOptionSet::configure(thread)) { |
205 return false; |
210 return false; |
206 } |
211 } |
207 } |
212 } |
|
213 |
208 if (!is_enabled()) { |
214 if (!is_enabled()) { |
209 return true; |
215 return true; |
210 } |
216 } |
|
217 |
211 if (!in_graph) { |
218 if (!in_graph) { |
212 log_jdk_jfr_module_resolution_error(thread); |
219 log_jdk_jfr_module_resolution_error(thread); |
213 return false; |
220 return false; |
214 } |
221 } |
215 return startup_recordings(thread); |
222 |
|
223 return launch_recordings(thread); |
216 } |
224 } |
217 |
225 |
218 static bool _created = false; |
226 static bool _created = false; |
219 |
227 |
220 // |
228 // |