Coverage Report

Created: 2026-09-11 19:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
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