be/src/common/metrics/jvm_metrics.cpp
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include "common/metrics/jvm_metrics.h" |
19 | | |
20 | | #include <functional> |
21 | | |
22 | | #include "common/config.h" |
23 | | #include "common/metrics/metrics.h" |
24 | | #include "util/defer_op.h" |
25 | | #include "util/jni-util.h" |
26 | | #include "util/jvm_launcher.h" |
27 | | |
28 | | namespace doris { |
29 | | |
30 | | namespace { |
31 | | // The env these stats run on, taken from the JVM directly rather than through Jni::Env::Get(), |
32 | | // and primed as this thread's cached env for as long as the guard lives. |
33 | | // |
34 | | // Env::Get() is the gate for code that runs Java of Doris's own, and it refuses whenever the |
35 | | // plugin SPI could not be resolved. These stats are not that: JvmStats reaches only for |
36 | | // java.lang.management, which every JVM has and no plugin supplies, and it is published precisely |
37 | | // so that a BE whose JVM came up through libhdfs alone still reports its Java heap instead of |
38 | | // having it counted as untracked memory. Routing it through the SPI gate undid that in the one |
39 | | // deployment it was written for: init() succeeded on the bootstrap thread (env already primed, so |
40 | | // Env::Get() took its fast path and never asked), while every later refresh() ran on the metrics |
41 | | // daemon, took the slow path, and got the cached base failure - 30 of those and JvmMetrics::update |
42 | | // logs "Jvm Stats CLOSE!" and sets every jvm_* gauge to 0. Published once, frozen, then zeroed. |
43 | | // |
44 | | // Why a guard around the whole body rather than one call at the top. Two reasons, and neither is |
45 | | // served by taking the env alone: |
46 | | // |
47 | | // * init() is called from JvmLauncher::_bootstrap(), INSIDE ensure_jvm()'s call_once. Anything |
48 | | // on this path that reaches ensure_jvm() - which is what both Jni::Env::Get()'s slow path and |
49 | | // JvmLauncher::attach_current_thread() do - re-enters that once flag and hangs the BE on the |
50 | | // first JVM it ever creates. |
51 | | // * every Jni::Local* this file allocates releases itself through Env::Get() (see |
52 | | // RefHelper<Local>::get_env), so an unprimed thread would put each of those destructors back |
53 | | // behind the same SPI gate: it logs "Can't destroy Jni Ref" and returns without deleting, once |
54 | | // per object, every 15 seconds, on exactly the deployment this indirection exists for. |
55 | | using ScopedManagementEnv = Jni::JvmLauncher::ScopedVmEnv; |
56 | | } // namespace |
57 | | |
58 | | #define DEFINE_JVM_SIZE_BYTES_METRIC(name, type) \ |
59 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(name##_##type, MetricUnit::BYTES, "", name, \ |
60 | | Labels({{"type", #type}})); |
61 | | |
62 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, max); |
63 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, committed); |
64 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, used); |
65 | | |
66 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_non_heap_size_bytes, used); |
67 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_non_heap_size_bytes, committed); |
68 | | |
69 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, used); |
70 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, peak_used); |
71 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, max); |
72 | | |
73 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, used); |
74 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, peak_used); |
75 | | DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, max); |
76 | | |
77 | | #define DEFINE_JVM_THREAD_METRIC(type) \ |
78 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_thread_##type, MetricUnit::NOUNIT, "", jvm_thread, \ |
79 | | Labels({{"type", #type}})); |
80 | | |
81 | | DEFINE_JVM_THREAD_METRIC(count); |
82 | | DEFINE_JVM_THREAD_METRIC(peak_count); |
83 | | DEFINE_JVM_THREAD_METRIC(new_count); |
84 | | DEFINE_JVM_THREAD_METRIC(runnable_count); |
85 | | DEFINE_JVM_THREAD_METRIC(blocked_count); |
86 | | DEFINE_JVM_THREAD_METRIC(waiting_count); |
87 | | DEFINE_JVM_THREAD_METRIC(timed_waiting_count); |
88 | | DEFINE_JVM_THREAD_METRIC(terminated_count); |
89 | | |
90 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_young_generation_count, MetricUnit::NOUNIT, "", |
91 | | jvm_gc, |
92 | | Labels({{"name", "G1 Young generation Count"}, |
93 | | {"type", "count"}})); |
94 | | |
95 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_young_generation_time_ms, MetricUnit::MILLISECONDS, |
96 | | "", jvm_gc, |
97 | | Labels({{"name", "G1 Young generation Time"}, |
98 | | {"type", "time"}})); |
99 | | |
100 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_old_generation_count, MetricUnit::NOUNIT, "", jvm_gc, |
101 | | Labels({{"name", "G1 Old generation Count"}, |
102 | | {"type", "count"}})); |
103 | | |
104 | | DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_old_generation_time_ms, MetricUnit::MILLISECONDS, "", |
105 | | jvm_gc, |
106 | | Labels({{"name", "G1 Old generation Time"}, |
107 | | {"type", "time"}})); |
108 | | |
109 | | const char* JvmMetrics::_s_hook_name = "jvm_metrics"; |
110 | | |
111 | 3 | JvmMetrics::JvmMetrics(MetricRegistry* registry) { |
112 | 3 | DCHECK(registry != nullptr); |
113 | 3 | _registry = registry; |
114 | | |
115 | 3 | _server_entity = _registry->register_entity("server"); |
116 | 3 | DCHECK(_server_entity != nullptr); |
117 | | |
118 | 3 | do { |
119 | 3 | if (!doris::config::enable_jvm_monitor) { |
120 | 0 | break; |
121 | 0 | } |
122 | 3 | try { |
123 | 3 | Status st = _jvm_stats.init(); |
124 | 3 | if (!st) { |
125 | 0 | LOG(WARNING) << "jvm Stats Init Fail. " << st.to_string(); |
126 | 0 | break; |
127 | 0 | } |
128 | 3 | } catch (...) { |
129 | 0 | LOG(WARNING) << "jvm Stats Throw Exception Init Fail."; |
130 | 0 | break; |
131 | 0 | } |
132 | 3 | } while (false); |
133 | | |
134 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_max); |
135 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_committed); |
136 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_used); |
137 | | |
138 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_non_heap_size_bytes_used); |
139 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_non_heap_size_bytes_committed); |
140 | | |
141 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_used); |
142 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_peak_used); |
143 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_max); |
144 | | |
145 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_used); |
146 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_peak_used); |
147 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_max); |
148 | | |
149 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_count); |
150 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_peak_count); |
151 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_new_count); |
152 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_runnable_count); |
153 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_blocked_count); |
154 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_waiting_count); |
155 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_timed_waiting_count); |
156 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_terminated_count); |
157 | | |
158 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_young_generation_count); |
159 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_young_generation_time_ms); |
160 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_old_generation_count); |
161 | 3 | INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_old_generation_time_ms); |
162 | | |
163 | | // Last, after every register above. MetricRegistry::trigger_all_hooks runs a hook while it |
164 | | // holds both its own lock and MetricEntity::_lock, and this hook re-enters JNI through |
165 | | // attach_current_thread() - which, on the metrics daemon thread, blocks on the once flag |
166 | | // whichever thread is bringing the JVM up holds. Publishing the hook before these registers means the |
167 | | // daemon can be holding the very lock they need while it waits for that flag: an ABBA |
168 | | // deadlock that leaves /metrics dead for good. Since the JVM is created on demand, the |
169 | | // thread running this constructor is any query thread rather than main(). |
170 | 3 | if (_jvm_stats.init_complete()) { |
171 | 3 | _server_entity->register_hook(_s_hook_name, std::bind(&JvmMetrics::update, this)); |
172 | 3 | } |
173 | 3 | } |
174 | | |
175 | 1 | JvmMetrics::~JvmMetrics() { |
176 | 1 | if (_jvm_stats.init_complete()) { |
177 | 1 | _server_entity->deregister_hook(_s_hook_name); |
178 | 1 | } |
179 | 1 | } |
180 | | |
181 | 336 | void JvmMetrics::update() { |
182 | | // If enable_jvm_monitor is false, the jvm stats object is not initialized. call jvm_stats.refresh() may core. |
183 | 336 | if (!doris::config::enable_jvm_monitor) { |
184 | 0 | return; |
185 | 0 | } |
186 | 336 | static long fail_count = 0; |
187 | 336 | if (fail_count >= 30) { |
188 | 0 | return; |
189 | 0 | } |
190 | | |
191 | 336 | try { |
192 | 336 | Status st = _jvm_stats.refresh(this); |
193 | 336 | if (!st) { |
194 | 0 | fail_count++; |
195 | 0 | LOG(WARNING) << "Jvm Stats update Fail! " << st.to_string(); |
196 | 336 | } else { |
197 | 336 | fail_count = 0; |
198 | 336 | } |
199 | 336 | } catch (...) { |
200 | 0 | LOG(WARNING) << "Jvm Stats update throw Exception!"; |
201 | 0 | fail_count++; |
202 | 0 | } |
203 | | |
204 | | //When 30 consecutive exceptions occur, turn off jvm information collection. |
205 | 336 | if (fail_count >= 30) { |
206 | 0 | LOG(WARNING) << "Jvm Stats CLOSE!"; |
207 | 0 | jvm_heap_size_bytes_max->set_value(0); |
208 | 0 | jvm_heap_size_bytes_committed->set_value(0); |
209 | 0 | jvm_heap_size_bytes_used->set_value(0); |
210 | |
|
211 | 0 | jvm_non_heap_size_bytes_used->set_value(0); |
212 | 0 | jvm_non_heap_size_bytes_committed->set_value(0); |
213 | |
|
214 | 0 | jvm_young_size_bytes_used->set_value(0); |
215 | 0 | jvm_young_size_bytes_peak_used->set_value(0); |
216 | 0 | jvm_young_size_bytes_max->set_value(0); |
217 | |
|
218 | 0 | jvm_old_size_bytes_used->set_value(0); |
219 | 0 | jvm_old_size_bytes_peak_used->set_value(0); |
220 | 0 | jvm_old_size_bytes_max->set_value(0); |
221 | |
|
222 | 0 | jvm_thread_count->set_value(0); |
223 | 0 | jvm_thread_peak_count->set_value(0); |
224 | 0 | jvm_thread_new_count->set_value(0); |
225 | 0 | jvm_thread_runnable_count->set_value(0); |
226 | 0 | jvm_thread_blocked_count->set_value(0); |
227 | 0 | jvm_thread_waiting_count->set_value(0); |
228 | 0 | jvm_thread_timed_waiting_count->set_value(0); |
229 | 0 | jvm_thread_terminated_count->set_value(0); |
230 | |
|
231 | 0 | jvm_gc_g1_young_generation_count->set_value(0); |
232 | 0 | jvm_gc_g1_young_generation_time_ms->set_value(0); |
233 | 0 | jvm_gc_g1_old_generation_count->set_value(0); |
234 | 0 | jvm_gc_g1_old_generation_time_ms->set_value(0); |
235 | 0 | } |
236 | 336 | } |
237 | | |
238 | 3 | Status JvmStats::init() { |
239 | | // First declaration in the scope, so it is the last thing destroyed: every JNI wrapper below |
240 | | // is released while this is still in force. |
241 | 3 | ScopedManagementEnv scoped_env; |
242 | 3 | JNIEnv* env = nullptr; |
243 | 3 | RETURN_IF_ERROR(scoped_env.attach(&env)); |
244 | | |
245 | 3 | RETURN_IF_ERROR(Jni::Util::find_class(env, "java/lang/management/ManagementFactory", |
246 | 3 | &_managementFactoryClass)); |
247 | 3 | RETURN_IF_ERROR(_managementFactoryClass.get_static_method( |
248 | 3 | env, "getMemoryMXBean", "()Ljava/lang/management/MemoryMXBean;", |
249 | 3 | &_getMemoryMXBeanMethod)); |
250 | | |
251 | 3 | RETURN_IF_ERROR( |
252 | 3 | Jni::Util::find_class(env, "java/lang/management/MemoryUsage", &_memoryUsageClass)); |
253 | 3 | RETURN_IF_ERROR( |
254 | 3 | _memoryUsageClass.get_method(env, "getUsed", "()J", &_getMemoryUsageUsedMethod)); |
255 | 3 | RETURN_IF_ERROR(_memoryUsageClass.get_method(env, "getCommitted", "()J", |
256 | 3 | &_getMemoryUsageCommittedMethod)); |
257 | 3 | RETURN_IF_ERROR(_memoryUsageClass.get_method(env, "getMax", "()J", &_getMemoryUsageMaxMethod)); |
258 | | |
259 | 3 | RETURN_IF_ERROR( |
260 | 3 | Jni::Util::find_class(env, "java/lang/management/MemoryMXBean", &_memoryMXBeanClass)); |
261 | 3 | RETURN_IF_ERROR(_memoryMXBeanClass.get_method(env, "getHeapMemoryUsage", |
262 | 3 | "()Ljava/lang/management/MemoryUsage;", |
263 | 3 | &_getHeapMemoryUsageMethod)); |
264 | 3 | RETURN_IF_ERROR(_memoryMXBeanClass.get_method(env, "getNonHeapMemoryUsage", |
265 | 3 | "()Ljava/lang/management/MemoryUsage;", |
266 | 3 | &_getNonHeapMemoryUsageMethod)); |
267 | | |
268 | 3 | RETURN_IF_ERROR(_managementFactoryClass.get_static_method( |
269 | 3 | env, "getMemoryPoolMXBeans", "()Ljava/util/List;", &_getMemoryPoolMXBeansMethod)); |
270 | | |
271 | 3 | RETURN_IF_ERROR(Jni::Util::find_class(env, "java/util/List", &_listClass)); |
272 | 3 | RETURN_IF_ERROR(_listClass.get_method(env, "size", "()I", &_getListSizeMethod)); |
273 | 3 | RETURN_IF_ERROR( |
274 | 3 | _listClass.get_method(env, "get", "(I)Ljava/lang/Object;", &_getListUseIndexMethod)); |
275 | | |
276 | 3 | RETURN_IF_ERROR(Jni::Util::find_class(env, "java/lang/management/MemoryPoolMXBean", |
277 | 3 | &_memoryPoolMXBeanClass)); |
278 | 3 | RETURN_IF_ERROR(_memoryPoolMXBeanClass.get_method(env, "getUsage", |
279 | 3 | "()Ljava/lang/management/MemoryUsage;", |
280 | 3 | &_getMemoryPoolMXBeanUsageMethod)); |
281 | 3 | RETURN_IF_ERROR(_memoryPoolMXBeanClass.get_method(env, "getPeakUsage", |
282 | 3 | "()Ljava/lang/management/MemoryUsage;", |
283 | 3 | &_getMemoryPoolMXBeanPeakMethod)); |
284 | 3 | RETURN_IF_ERROR(_memoryPoolMXBeanClass.get_method(env, "getName", "()Ljava/lang/String;", |
285 | 3 | &_getMemoryPoolMXBeanNameMethod)); |
286 | | |
287 | 3 | RETURN_IF_ERROR(_managementFactoryClass.get_static_method( |
288 | 3 | env, "getThreadMXBean", "()Ljava/lang/management/ThreadMXBean;", |
289 | 3 | &_getThreadMXBeanMethod)); |
290 | 3 | RETURN_IF_ERROR(_managementFactoryClass.get_static_method(env, "getGarbageCollectorMXBeans", |
291 | 3 | "()Ljava/util/List;", |
292 | 3 | &_getGarbageCollectorMXBeansMethod)); |
293 | | |
294 | 3 | RETURN_IF_ERROR(Jni::Util::find_class(env, "java/lang/management/GarbageCollectorMXBean", |
295 | 3 | &_garbageCollectorMXBeanClass)); |
296 | 3 | RETURN_IF_ERROR(_garbageCollectorMXBeanClass.get_method(env, "getName", "()Ljava/lang/String;", |
297 | 3 | &_getGCNameMethod)); |
298 | 3 | RETURN_IF_ERROR(_garbageCollectorMXBeanClass.get_method(env, "getCollectionCount", "()J", |
299 | 3 | &_getGCCollectionCountMethod)); |
300 | 3 | RETURN_IF_ERROR(_garbageCollectorMXBeanClass.get_method(env, "getCollectionTime", "()J", |
301 | 3 | &_getGCCollectionTimeMethod)); |
302 | | |
303 | 3 | RETURN_IF_ERROR( |
304 | 3 | Jni::Util::find_class(env, "java/lang/management/ThreadMXBean", &_threadMXBeanClass)); |
305 | 3 | RETURN_IF_ERROR( |
306 | 3 | _threadMXBeanClass.get_method(env, "getAllThreadIds", "()[J", &_getAllThreadIdsMethod)); |
307 | 3 | RETURN_IF_ERROR(_threadMXBeanClass.get_method(env, "getThreadInfo", |
308 | 3 | "([JI)[Ljava/lang/management/ThreadInfo;", |
309 | 3 | &_getThreadInfoMethod)); |
310 | 3 | RETURN_IF_ERROR(_threadMXBeanClass.get_method(env, "getPeakThreadCount", "()I", |
311 | 3 | &_getPeakThreadCountMethod)); |
312 | | |
313 | 3 | RETURN_IF_ERROR( |
314 | 3 | Jni::Util::find_class(env, "java/lang/management/ThreadInfo", &_threadInfoClass)); |
315 | 3 | RETURN_IF_ERROR(_threadInfoClass.get_method(env, "getThreadState", "()Ljava/lang/Thread$State;", |
316 | 3 | &_getThreadStateMethod)); |
317 | | |
318 | 3 | RETURN_IF_ERROR(Jni::Util::find_class(env, "java/lang/Thread$State", &_threadStateClass)); |
319 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
320 | 3 | env, "NEW", "Ljava/lang/Thread$State;", &_newThreadStateObj)); |
321 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
322 | 3 | env, "RUNNABLE", "Ljava/lang/Thread$State;", &_runnableThreadStateObj)); |
323 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
324 | 3 | env, "BLOCKED", "Ljava/lang/Thread$State;", &_blockedThreadStateObj)); |
325 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
326 | 3 | env, "WAITING", "Ljava/lang/Thread$State;", &_waitingThreadStateObj)); |
327 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
328 | 3 | env, "TIMED_WAITING", "Ljava/lang/Thread$State;", &_timedWaitingThreadStateObj)); |
329 | 3 | RETURN_IF_ERROR(_threadStateClass.get_static_object_field( |
330 | 3 | env, "TERMINATED", "Ljava/lang/Thread$State;", &_terminatedThreadStateObj)); |
331 | | |
332 | 3 | _init_complete = true; |
333 | 3 | LOG(INFO) << "Start JVM monitoring."; |
334 | 3 | return Status::OK(); |
335 | 3 | } |
336 | | |
337 | 336 | Status JvmStats::refresh(JvmMetrics* jvm_metrics) const { |
338 | 336 | if (!_init_complete) { |
339 | 0 | return Status::InternalError("Jvm Stats not init complete."); |
340 | 0 | } |
341 | | |
342 | | // First declaration in the scope, so it is the last thing destroyed: every Jni::Local* below |
343 | | // is released while this is still in force. See ScopedManagementEnv at the top of this file. |
344 | 336 | ScopedManagementEnv scoped_env; |
345 | 336 | JNIEnv* env = nullptr; |
346 | 336 | RETURN_IF_ERROR(scoped_env.attach(&env)); |
347 | | |
348 | 336 | Jni::LocalObject memoryMXBeanObj; |
349 | 336 | RETURN_IF_ERROR(_managementFactoryClass.call_static_object_method(env, _getMemoryMXBeanMethod) |
350 | 336 | .call(&memoryMXBeanObj)); |
351 | | |
352 | 336 | Jni::LocalObject heapMemoryUsageObj; |
353 | 336 | RETURN_IF_ERROR(memoryMXBeanObj.call_object_method(env, _getHeapMemoryUsageMethod) |
354 | 336 | .call(&heapMemoryUsageObj)); |
355 | | |
356 | 336 | jlong heapMemoryUsed = 0; |
357 | 336 | RETURN_IF_ERROR(heapMemoryUsageObj.call_long_method(env, _getMemoryUsageUsedMethod) |
358 | 336 | .call(&heapMemoryUsed)); |
359 | | |
360 | 336 | jlong heapMemoryCommitted = 0; |
361 | 336 | RETURN_IF_ERROR(heapMemoryUsageObj.call_long_method(env, _getMemoryUsageCommittedMethod) |
362 | 336 | .call(&heapMemoryCommitted)); |
363 | | |
364 | 336 | jlong heapMemoryMax = 0; |
365 | 336 | RETURN_IF_ERROR(heapMemoryUsageObj.call_long_method(env, _getMemoryUsageMaxMethod) |
366 | 336 | .call(&heapMemoryMax)); |
367 | | |
368 | 336 | jvm_metrics->jvm_heap_size_bytes_used->set_value(heapMemoryUsed < 0 ? 0 : heapMemoryUsed); |
369 | 336 | jvm_metrics->jvm_heap_size_bytes_committed->set_value( |
370 | 336 | heapMemoryCommitted < 0 ? 0 : heapMemoryCommitted); |
371 | 336 | jvm_metrics->jvm_heap_size_bytes_max->set_value(heapMemoryMax < 0 ? 0 : heapMemoryMax); |
372 | | |
373 | 336 | Jni::LocalObject nonHeapMemoryUsageObj; |
374 | 336 | RETURN_IF_ERROR(memoryMXBeanObj.call_object_method(env, _getNonHeapMemoryUsageMethod) |
375 | 336 | .call(&nonHeapMemoryUsageObj)); |
376 | | |
377 | 336 | jlong nonHeapMemoryCommitted = 0; |
378 | 336 | RETURN_IF_ERROR(nonHeapMemoryUsageObj.call_long_method(env, _getMemoryUsageCommittedMethod) |
379 | 336 | .call(&nonHeapMemoryCommitted)); |
380 | | |
381 | 336 | jlong nonHeapMemoryUsed = 0; |
382 | 336 | RETURN_IF_ERROR(nonHeapMemoryUsageObj.call_long_method(env, _getMemoryUsageUsedMethod) |
383 | 336 | .call(&nonHeapMemoryUsed)); |
384 | | |
385 | 336 | jvm_metrics->jvm_non_heap_size_bytes_committed->set_value( |
386 | 336 | nonHeapMemoryCommitted < 0 ? 0 : nonHeapMemoryCommitted); |
387 | 336 | jvm_metrics->jvm_non_heap_size_bytes_used->set_value(nonHeapMemoryUsed < 0 ? 0 |
388 | 336 | : nonHeapMemoryUsed); |
389 | | |
390 | 336 | Jni::LocalObject memoryPoolMXBeansList; |
391 | 336 | RETURN_IF_ERROR( |
392 | 336 | _managementFactoryClass.call_static_object_method(env, _getMemoryPoolMXBeansMethod) |
393 | 336 | .call(&memoryPoolMXBeansList)); |
394 | | |
395 | 336 | jint beanSize = 0; |
396 | 336 | RETURN_IF_ERROR(memoryPoolMXBeansList.call_int_method(env, _getListSizeMethod).call(&beanSize)); |
397 | | |
398 | 3.02k | for (int i = 0; i < beanSize; ++i) { |
399 | 2.68k | Jni::LocalObject memoryPoolMXBean; |
400 | 2.68k | RETURN_IF_ERROR(memoryPoolMXBeansList.call_object_method(env, _getListUseIndexMethod) |
401 | 2.68k | .with_arg(i) |
402 | 2.68k | .call(&memoryPoolMXBean)); |
403 | | |
404 | 2.68k | Jni::LocalObject usageObject; |
405 | 2.68k | RETURN_IF_ERROR(memoryPoolMXBean.call_object_method(env, _getMemoryPoolMXBeanUsageMethod) |
406 | 2.68k | .call(&usageObject)); |
407 | | |
408 | 2.68k | jlong used = 0; |
409 | 2.68k | RETURN_IF_ERROR(usageObject.call_long_method(env, _getMemoryUsageUsedMethod).call(&used)); |
410 | | |
411 | 2.68k | jlong max = 0; |
412 | 2.68k | RETURN_IF_ERROR(usageObject.call_long_method(env, _getMemoryUsageMaxMethod).call(&max)); |
413 | | |
414 | 2.68k | Jni::LocalObject peakUsageObject; |
415 | 2.68k | RETURN_IF_ERROR(memoryPoolMXBean.call_object_method(env, _getMemoryPoolMXBeanPeakMethod) |
416 | 2.68k | .call(&peakUsageObject)); |
417 | | |
418 | 2.68k | jlong peakUsed = 0; |
419 | 2.68k | RETURN_IF_ERROR( |
420 | 2.68k | peakUsageObject.call_long_method(env, _getMemoryUsageUsedMethod).call(&peakUsed)); |
421 | | |
422 | 2.68k | Jni::LocalString name; |
423 | 2.68k | RETURN_IF_ERROR(memoryPoolMXBean.call_object_method(env, _getMemoryPoolMXBeanNameMethod) |
424 | 2.68k | .call(&name)); |
425 | | |
426 | 2.68k | Jni::LocalStringBufferGuard nameStr; |
427 | 2.68k | RETURN_IF_ERROR(name.get_string_chars(env, &nameStr)); |
428 | 2.68k | if (nameStr.get() != nullptr) { |
429 | 2.68k | auto it = _memoryPoolName.find(nameStr.get()); |
430 | 2.68k | if (it == _memoryPoolName.end()) { |
431 | 1.68k | continue; |
432 | 1.68k | } |
433 | 1.00k | if (it->second == memoryPoolNameEnum::YOUNG) { |
434 | 336 | jvm_metrics->jvm_young_size_bytes_used->set_value(used < 0 ? 0 : used); |
435 | 336 | jvm_metrics->jvm_young_size_bytes_peak_used->set_value(peakUsed < 0 ? 0 : peakUsed); |
436 | 336 | jvm_metrics->jvm_young_size_bytes_max->set_value(max < 0 ? 0 : max); |
437 | | |
438 | 672 | } else if (it->second == memoryPoolNameEnum::OLD) { |
439 | 336 | jvm_metrics->jvm_old_size_bytes_used->set_value(used < 0 ? 0 : used); |
440 | 336 | jvm_metrics->jvm_old_size_bytes_peak_used->set_value(peakUsed < 0 ? 0 : peakUsed); |
441 | 336 | jvm_metrics->jvm_old_size_bytes_max->set_value(max < 0 ? 0 : max); |
442 | 336 | } |
443 | 1.00k | } |
444 | 2.68k | } |
445 | | |
446 | 336 | Jni::LocalObject threadMXBean; |
447 | 336 | RETURN_IF_ERROR(_managementFactoryClass.call_static_object_method(env, _getThreadMXBeanMethod) |
448 | 336 | .call(&threadMXBean)); |
449 | | |
450 | 336 | Jni::LocalArray threadIds; |
451 | 336 | RETURN_IF_ERROR(threadMXBean.call_object_method(env, _getAllThreadIdsMethod).call(&threadIds)); |
452 | | |
453 | 336 | jsize threadCount = 0; |
454 | 336 | RETURN_IF_ERROR(threadIds.get_length(env, &threadCount)); |
455 | | |
456 | 336 | Jni::LocalArray threadInfos; |
457 | 336 | RETURN_IF_ERROR(threadMXBean.call_object_method(env, _getThreadInfoMethod) |
458 | 336 | .with_arg(threadIds) |
459 | 336 | .with_arg(0) |
460 | 336 | .call(&threadInfos)); |
461 | | |
462 | 336 | int threadsNew = 0, threadsRunnable = 0, threadsBlocked = 0, threadsWaiting = 0, |
463 | 336 | threadsTimedWaiting = 0, threadsTerminated = 0; |
464 | | |
465 | 336 | jint peakThreadCount = 0; |
466 | 336 | RETURN_IF_ERROR( |
467 | 336 | threadMXBean.call_int_method(env, _getPeakThreadCountMethod).call(&peakThreadCount)); |
468 | | |
469 | 336 | jvm_metrics->jvm_thread_peak_count->set_value(peakThreadCount < 0 ? 0 : peakThreadCount); |
470 | 336 | jvm_metrics->jvm_thread_count->set_value(threadCount < 0 ? 0 : threadCount); |
471 | | |
472 | 54.5k | for (int i = 0; i < threadCount; i++) { |
473 | 54.1k | Jni::LocalObject threadInfo; |
474 | 54.1k | RETURN_IF_ERROR(threadInfos.get_object_array_element(env, i, &threadInfo)); |
475 | 54.1k | if (threadInfo.uninitialized()) { |
476 | 0 | continue; |
477 | 0 | } |
478 | 54.1k | Jni::LocalObject threadState; |
479 | 54.1k | RETURN_IF_ERROR( |
480 | 54.1k | threadInfo.call_object_method(env, _getThreadStateMethod).call(&threadState)); |
481 | | |
482 | 54.1k | if (threadState.equal(env, _newThreadStateObj)) { |
483 | 0 | threadsNew++; |
484 | 54.1k | } else if (threadState.equal(env, _runnableThreadStateObj)) { |
485 | 53.0k | threadsRunnable++; |
486 | 53.0k | } else if (threadState.equal(env, _blockedThreadStateObj)) { |
487 | 0 | threadsBlocked++; |
488 | 1.09k | } else if (threadState.equal(env, _waitingThreadStateObj)) { |
489 | 375 | threadsWaiting++; |
490 | 719 | } else if (threadState.equal(env, _timedWaitingThreadStateObj)) { |
491 | 719 | threadsTimedWaiting++; |
492 | 719 | } else if (threadState.equal(env, _terminatedThreadStateObj)) { |
493 | 0 | threadsTerminated++; |
494 | 0 | } |
495 | 54.1k | } |
496 | | |
497 | 336 | jvm_metrics->jvm_thread_new_count->set_value(threadsNew < 0 ? 0 : threadsNew); |
498 | 336 | jvm_metrics->jvm_thread_runnable_count->set_value(threadsRunnable < 0 ? 0 : threadsRunnable); |
499 | 336 | jvm_metrics->jvm_thread_blocked_count->set_value(threadsBlocked < 0 ? 0 : threadsBlocked); |
500 | 336 | jvm_metrics->jvm_thread_waiting_count->set_value(threadsWaiting < 0 ? 0 : threadsWaiting); |
501 | 336 | jvm_metrics->jvm_thread_timed_waiting_count->set_value( |
502 | 336 | threadsTimedWaiting < 0 ? 0 : threadsTimedWaiting); |
503 | 336 | jvm_metrics->jvm_thread_terminated_count->set_value(threadsTerminated < 0 ? 0 |
504 | 336 | : threadsTerminated); |
505 | | |
506 | 336 | Jni::LocalObject gcMXBeansList; |
507 | 336 | RETURN_IF_ERROR(_managementFactoryClass |
508 | 336 | .call_static_object_method(env, _getGarbageCollectorMXBeansMethod) |
509 | 336 | .call(&gcMXBeansList)); |
510 | 336 | jint numCollectors = 0; |
511 | 336 | RETURN_IF_ERROR(gcMXBeansList.call_int_method(env, _getListSizeMethod).call(&numCollectors)); |
512 | | |
513 | 1.00k | for (int i = 0; i < numCollectors; i++) { |
514 | 672 | Jni::LocalObject gcMXBean; |
515 | 672 | RETURN_IF_ERROR(gcMXBeansList.call_object_method(env, _getListUseIndexMethod) |
516 | 672 | .with_arg(i) |
517 | 672 | .call(&gcMXBean)); |
518 | | |
519 | 672 | Jni::LocalString gcName; |
520 | 672 | RETURN_IF_ERROR(gcMXBean.call_object_method(env, _getGCNameMethod).call(&gcName)); |
521 | | |
522 | 672 | jlong gcCollectionCount = 0; |
523 | 672 | RETURN_IF_ERROR(gcMXBean.call_long_method(env, _getGCCollectionCountMethod) |
524 | 672 | .call(&gcCollectionCount)); |
525 | | |
526 | 672 | jlong gcCollectionTime = 0; |
527 | 672 | RETURN_IF_ERROR( |
528 | 672 | gcMXBean.call_long_method(env, _getGCCollectionTimeMethod).call(&gcCollectionTime)); |
529 | | |
530 | 672 | Jni::LocalStringBufferGuard gcNameStr; |
531 | 672 | RETURN_IF_ERROR(gcName.get_string_chars(env, &gcNameStr)); |
532 | | |
533 | 672 | if (gcNameStr.get() != nullptr) { |
534 | 672 | if (strcmp(gcNameStr.get(), "G1 Young Generation") == 0) { |
535 | 336 | jvm_metrics->jvm_gc_g1_young_generation_count->set_value(gcCollectionCount); |
536 | 336 | jvm_metrics->jvm_gc_g1_young_generation_time_ms->set_value(gcCollectionTime); |
537 | | |
538 | 336 | } else { |
539 | 336 | jvm_metrics->jvm_gc_g1_old_generation_count->set_value(gcCollectionCount); |
540 | 336 | jvm_metrics->jvm_gc_g1_old_generation_time_ms->set_value(gcCollectionTime); |
541 | 336 | } |
542 | 672 | } |
543 | 672 | } |
544 | | |
545 | 336 | return Status::OK(); |
546 | 336 | } |
547 | 1 | JvmStats::~JvmStats() {} |
548 | | |
549 | | } // namespace doris |