This is an automated email from the ASF dual-hosted git repository. dataroaring pushed a commit to branch branch-3.0 in repository https://gitbox.apache.org/repos/asf/doris.git
commit d23a5aa8f1ff455b362520e1f0af01ce35062963 Author: daidai <[email protected]> AuthorDate: Mon May 27 17:20:32 2024 +0800 [feature](metrics)support be jvm metrics. (#35023) support be jvm metrics. if you `curl http://be_host:webserver_port/metrics` , you will get : ``` doris_be_jvm_heap_size_bytes{type="max"} 8589934592 doris_be_jvm_heap_size_bytes{type="committed"} 8589934592 doris_be_jvm_heap_size_bytes{type="used"} 364159504 doris_be_jvm_non_heap_size_bytes{type="committed"} 117899264 doris_be_jvm_non_heap_size_bytes{type="used"} 115330424 doris_be_jvm_young_size_bytes{type="used"} 255852544 doris_be_jvm_young_size_bytes{type="peak_used"} 255852544 doris_be_jvm_young_size_bytes{type="max"} 8589934592 doris_be_jvm_old_size_bytes{type="used"} 94393344 doris_be_jvm_old_size_bytes{type="peak_used"} 94393344 doris_be_jvm_old_size_bytes{type="max"} 8589934592 doris_be_jvm_gc{name="G1 Young Generation Count", type="count"} 3 doris_be_jvm_gc{name="G1 Young Generation Time", type="time"} 33 doris_be_jvm_gc{name="G1 Old Generation Count", type="count"} 0 doris_be_jvm_gc{name="G1 Old Generation Time", type="time"} 0 doris_be_jvm_thread{type="count"} 147 doris_be_jvm_thread{type="peak_count"} 147 doris_be_jvm_thread{type="new_count"} 0 doris_be_jvm_thread{type="runnable_count"} 25 doris_be_jvm_thread{type="blocked_count"} 0 doris_be_jvm_thread{type="waiting_count"} 48 doris_be_jvm_thread{type="timed_waiting_count"} 74 doris_be_jvm_thread{type="terminated_count"} 0 ``` --- be/src/util/doris_metrics.cpp | 4 + be/src/util/doris_metrics.h | 6 + be/src/util/jni-util.cpp | 2 + be/src/util/jvm_metrics.cpp | 423 ++++++++++++++++++++++++++++++++++++++++++ be/src/util/jvm_metrics.h | 149 +++++++++++++++ 5 files changed, 584 insertions(+) diff --git a/be/src/util/doris_metrics.cpp b/be/src/util/doris_metrics.cpp index 0b80b37bc9d..daecaf5e7fd 100644 --- a/be/src/util/doris_metrics.cpp +++ b/be/src/util/doris_metrics.cpp @@ -316,6 +316,10 @@ void DorisMetrics::initialize(bool init_system_metrics, const std::set<std::stri } } +void DorisMetrics::init_jvm_metrics(JNIEnv* env) { + _jvm_metrics.reset(new JvmMetrics(&_metric_registry, env)); +} + void DorisMetrics::_update() { _update_process_thread_num(); _update_process_fd_num(); diff --git a/be/src/util/doris_metrics.h b/be/src/util/doris_metrics.h index ea6b68aa24e..c568098195b 100644 --- a/be/src/util/doris_metrics.h +++ b/be/src/util/doris_metrics.h @@ -17,11 +17,14 @@ #pragma once +#include <jni.h> + #include <memory> #include <set> #include <string> #include <vector> +#include "util/jvm_metrics.h" #include "util/metrics.h" #include "util/system_metrics.h" @@ -244,6 +247,8 @@ public: MetricRegistry* metric_registry() { return &_metric_registry; } SystemMetrics* system_metrics() { return _system_metrics.get(); } MetricEntity* server_entity() { return _server_metric_entity.get(); } + JvmMetrics* jvm_metrics() { return _jvm_metrics.get(); } + void init_jvm_metrics(JNIEnv* env); private: // Don't allow constructor @@ -260,6 +265,7 @@ private: MetricRegistry _metric_registry; std::unique_ptr<SystemMetrics> _system_metrics; + std::unique_ptr<JvmMetrics> _jvm_metrics; std::shared_ptr<MetricEntity> _server_metric_entity; }; diff --git a/be/src/util/jni-util.cpp b/be/src/util/jni-util.cpp index 3c8f2b0a30f..428c587f667 100644 --- a/be/src/util/jni-util.cpp +++ b/be/src/util/jni-util.cpp @@ -35,6 +35,7 @@ #include "common/config.h" #include "gutil/strings/substitute.h" +#include "util/doris_metrics.h" #include "util/jni_native_method.h" #include "util/libjvm_loader.h" @@ -571,6 +572,7 @@ Status JniUtil::Init() { } RETURN_IF_ERROR(init_jni_scanner_loader(env)); jvm_inited_ = true; + DorisMetrics::instance()->init_jvm_metrics(env); return Status::OK(); } diff --git a/be/src/util/jvm_metrics.cpp b/be/src/util/jvm_metrics.cpp new file mode 100644 index 00000000000..e55cf8f3fbe --- /dev/null +++ b/be/src/util/jvm_metrics.cpp @@ -0,0 +1,423 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "jvm_metrics.h" + +#include <functional> + +#include "util/metrics.h" + +namespace doris { + +#define DEFINE_JVM_SIZE_BYTES_METRIC(name, type) \ + DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(name##_##type, MetricUnit::BYTES, "", name, \ + Labels({{"type", #type}})); + +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, max); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, committed); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_heap_size_bytes, used); + +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_non_heap_size_bytes, used); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_non_heap_size_bytes, committed); + +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, used); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, peak_used); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_young_size_bytes, max); + +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, used); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, peak_used); +DEFINE_JVM_SIZE_BYTES_METRIC(jvm_old_size_bytes, max); + +#define DEFINE_JVM_THREAD_METRIC(type) \ + DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_thread_##type, MetricUnit::NOUNIT, "", jvm_thread, \ + Labels({{"type", #type}})); + +DEFINE_JVM_THREAD_METRIC(count); +DEFINE_JVM_THREAD_METRIC(peak_count); +DEFINE_JVM_THREAD_METRIC(new_count); +DEFINE_JVM_THREAD_METRIC(runnable_count); +DEFINE_JVM_THREAD_METRIC(blocked_count); +DEFINE_JVM_THREAD_METRIC(waiting_count); +DEFINE_JVM_THREAD_METRIC(timed_waiting_count); +DEFINE_JVM_THREAD_METRIC(terminated_count); + +DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_young_generation_count, MetricUnit::NOUNIT, "", + jvm_gc, + Labels({{"name", "G1 Young generation Count"}, + {"type", "count"}})); + +DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_young_generation_time_ms, MetricUnit::MILLISECONDS, + "", jvm_gc, + Labels({{"name", "G1 Young generation Time"}, + {"type", "time"}})); + +DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_old_generation_count, MetricUnit::NOUNIT, "", jvm_gc, + Labels({{"name", "G1 Old generation Count"}, + {"type", "count"}})); + +DEFINE_COUNTER_METRIC_PROTOTYPE_5ARG(jvm_gc_g1_old_generation_time_ms, MetricUnit::MILLISECONDS, "", + jvm_gc, + Labels({{"name", "G1 Old generation Time"}, + {"type", "time"}})); + +const char* JvmMetrics::_s_hook_name = "jvm_metrics"; + +JvmMetrics::JvmMetrics(MetricRegistry* registry, JNIEnv* env) : _jvm_stats(env) { + DCHECK(registry != nullptr); + _registry = registry; + + _server_entity = _registry->register_entity("server"); + DCHECK(_server_entity != nullptr); + if (_jvm_stats.init_complete()) { + _server_entity->register_hook(_s_hook_name, std::bind(&JvmMetrics::update, this)); + } + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_max); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_committed); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_heap_size_bytes_used); + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_non_heap_size_bytes_used); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_non_heap_size_bytes_committed); + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_used); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_peak_used); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_young_size_bytes_max); + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_used); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_peak_used); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_old_size_bytes_max); + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_peak_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_new_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_runnable_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_blocked_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_waiting_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_timed_waiting_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_thread_terminated_count); + + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_young_generation_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_young_generation_time_ms); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_old_generation_count); + INT_GAUGE_METRIC_REGISTER(_server_entity, jvm_gc_g1_old_generation_time_ms); +} + +void JvmMetrics::update() { + _jvm_stats.refresh(this); +} +#include <util/jni-util.h> + +jvmStats::jvmStats(JNIEnv* ENV) : env(ENV) { + _managementFactoryClass = env->FindClass("java/lang/management/ManagementFactory"); + if (_managementFactoryClass == nullptr) { + LOG(WARNING) + << "Class java/lang/management/ManagementFactory Not Find.JVM monitoring fails."; + return; + } + + _getMemoryMXBeanMethod = env->GetStaticMethodID(_managementFactoryClass, "getMemoryMXBean", + "()Ljava/lang/management/MemoryMXBean;"); + + _memoryUsageClass = env->FindClass("java/lang/management/MemoryUsage"); + if (_memoryUsageClass == nullptr) { + LOG(WARNING) << "Class java/lang/management/MemoryUsage Not Find.JVM monitoring fails."; + return; + } + _getMemoryUsageUsedMethod = env->GetMethodID(_memoryUsageClass, "getUsed", "()J"); + _getMemoryUsageCommittedMethod = env->GetMethodID(_memoryUsageClass, "getCommitted", "()J"); + _getMemoryUsageMaxMethod = env->GetMethodID(_memoryUsageClass, "getMax", "()J"); + + _memoryMXBeanClass = env->FindClass("java/lang/management/MemoryMXBean"); + if (_memoryMXBeanClass == nullptr) { + LOG(WARNING) << "Class java/lang/management/MemoryMXBean Not Find.JVM monitoring fails."; + return; + } + _getHeapMemoryUsageMethod = env->GetMethodID(_memoryMXBeanClass, "getHeapMemoryUsage", + "()Ljava/lang/management/MemoryUsage;"); + _getNonHeapMemoryUsageMethod = env->GetMethodID(_memoryMXBeanClass, "getNonHeapMemoryUsage", + "()Ljava/lang/management/MemoryUsage;"); + + _getMemoryPoolMXBeansMethod = env->GetStaticMethodID( + _managementFactoryClass, "getMemoryPoolMXBeans", "()Ljava/util/List;"); + + _listClass = env->FindClass("java/util/List"); + if (_listClass == nullptr) { + LOG(WARNING) << "Class java/util/List Not Find.JVM monitoring fails."; + return; + } + _getListSizeMethod = env->GetMethodID(_listClass, "size", "()I"); + _getListUseIndexMethod = env->GetMethodID(_listClass, "get", "(I)Ljava/lang/Object;"); + + _memoryPoolMXBeanClass = env->FindClass("java/lang/management/MemoryPoolMXBean"); + if (_memoryPoolMXBeanClass == nullptr) { + LOG(WARNING) + << "Class java/lang/management/MemoryPoolMXBean Not Find.JVM monitoring fails."; + return; + } + _getMemoryPoolMXBeanUsageMethod = env->GetMethodID(_memoryPoolMXBeanClass, "getUsage", + "()Ljava/lang/management/MemoryUsage;"); + _getMemoryPollMXBeanPeakMethod = env->GetMethodID(_memoryPoolMXBeanClass, "getPeakUsage", + "()Ljava/lang/management/MemoryUsage;"); + _getMemoryPollMXBeanNameMethod = + env->GetMethodID(_memoryPoolMXBeanClass, "getName", "()Ljava/lang/String;"); + + _getThreadMXBeanMethod = env->GetStaticMethodID(_managementFactoryClass, "getThreadMXBean", + "()Ljava/lang/management/ThreadMXBean;"); + + _getGarbageCollectorMXBeansMethod = env->GetStaticMethodID( + _managementFactoryClass, "getGarbageCollectorMXBeans", "()Ljava/util/List;"); + + _garbageCollectorMXBeanClass = env->FindClass("java/lang/management/GarbageCollectorMXBean"); + if (_garbageCollectorMXBeanClass == nullptr) { + LOG(WARNING) << "Class java/lang/management/GarbageCollectorMXBean Not Find.JVM monitoring " + "fails."; + return; + } + _getGCNameMethod = + env->GetMethodID(_garbageCollectorMXBeanClass, "getName", "()Ljava/lang/String;"); + _getGCCollectionCountMethod = + env->GetMethodID(_garbageCollectorMXBeanClass, "getCollectionCount", "()J"); + _getGCCollectionTimeMethod = + env->GetMethodID(_garbageCollectorMXBeanClass, "getCollectionTime", "()J"); + + _threadMXBeanClass = env->FindClass("java/lang/management/ThreadMXBean"); + if (_threadMXBeanClass == nullptr) { + LOG(WARNING) << "Class java/lang/management/ThreadMXBean Not Find.JVM monitoring fails."; + return; + } + _getAllThreadIdsMethod = env->GetMethodID(_threadMXBeanClass, "getAllThreadIds", "()[J"); + _getThreadInfoMethod = env->GetMethodID(_threadMXBeanClass, "getThreadInfo", + "([JI)[Ljava/lang/management/ThreadInfo;"); + _getPeakThreadCountMethod = env->GetMethodID(_threadMXBeanClass, "getPeakThreadCount", "()I"); + + _threadInfoClass = env->FindClass("java/lang/management/ThreadInfo"); + if (_threadInfoClass == nullptr) { + LOG(WARNING) << "Class java/lang/management/ThreadInfo Not Find.JVM monitoring fails."; + return; + } + + _getThreadStateMethod = + env->GetMethodID(_threadInfoClass, "getThreadState", "()Ljava/lang/Thread$State;"); + + _threadStateClass = env->FindClass("java/lang/Thread$State"); + if (_threadStateClass == nullptr) { + LOG(WARNING) << "Class java/lang/Thread$State Not Find.JVM monitoring fails."; + return; + } + + jfieldID newThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "NEW", "Ljava/lang/Thread$State;"); + jfieldID runnableThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "RUNNABLE", "Ljava/lang/Thread$State;"); + jfieldID blockedThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "BLOCKED", "Ljava/lang/Thread$State;"); + jfieldID waitingThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "WAITING", "Ljava/lang/Thread$State;"); + jfieldID timedWaitingThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "TIMED_WAITING", "Ljava/lang/Thread$State;"); + jfieldID terminatedThreadFieldID = + env->GetStaticFieldID(_threadStateClass, "TERMINATED", "Ljava/lang/Thread$State;"); + + _newThreadStateObj = env->GetStaticObjectField(_threadStateClass, newThreadFieldID); + _runnableThreadStateObj = env->GetStaticObjectField(_threadStateClass, runnableThreadFieldID); + _blockedThreadStateObj = env->GetStaticObjectField(_threadStateClass, blockedThreadFieldID); + _waitingThreadStateObj = env->GetStaticObjectField(_threadStateClass, waitingThreadFieldID); + _timedWaitingThreadStateObj = + env->GetStaticObjectField(_threadStateClass, timedWaitingThreadFieldID); + _terminatedThreadStateObj = + env->GetStaticObjectField(_threadStateClass, terminatedThreadFieldID); + + LOG(INFO) << "Start JVM monitoring."; + + _init_complete = true; +} + +#include "jni.h" + +void jvmStats::refresh(JvmMetrics* jvm_metrics) { + if (!_init_complete) { + return; + } + static_cast<void>(JniUtil::GetJNIEnv(&env)); + + jobject memoryMXBeanObj = + env->CallStaticObjectMethod(_managementFactoryClass, _getMemoryMXBeanMethod); + + jobject heapMemoryUsageObj = env->CallObjectMethod(memoryMXBeanObj, _getHeapMemoryUsageMethod); + + jlong heapMemoryUsed = env->CallLongMethod(heapMemoryUsageObj, _getMemoryUsageUsedMethod); + jlong heapMemoryCommitted = + env->CallLongMethod(heapMemoryUsageObj, _getMemoryUsageCommittedMethod); + jlong heapMemoryMax = env->CallLongMethod(heapMemoryUsageObj, _getMemoryUsageMaxMethod); + + jvm_metrics->jvm_heap_size_bytes_used->set_value(heapMemoryUsed < 0 ? 0 : heapMemoryUsed); + jvm_metrics->jvm_heap_size_bytes_committed->set_value( + heapMemoryCommitted < 0 ? 0 : heapMemoryCommitted); + jvm_metrics->jvm_heap_size_bytes_max->set_value(heapMemoryMax < 0 ? 0 : heapMemoryMax); + + jobject nonHeapMemoryUsageObj = + env->CallObjectMethod(memoryMXBeanObj, _getNonHeapMemoryUsageMethod); + + jlong nonHeapMemoryCommitted = + env->CallLongMethod(nonHeapMemoryUsageObj, _getMemoryUsageCommittedMethod); + jlong nonHeapMemoryUsed = env->CallLongMethod(nonHeapMemoryUsageObj, _getMemoryUsageUsedMethod); + + jvm_metrics->jvm_non_heap_size_bytes_committed->set_value( + nonHeapMemoryCommitted < 0 ? 0 : nonHeapMemoryCommitted); + jvm_metrics->jvm_non_heap_size_bytes_used->set_value(nonHeapMemoryUsed < 0 ? 0 + : nonHeapMemoryUsed); + + jobject memoryPoolMXBeansList = + env->CallStaticObjectMethod(_managementFactoryClass, _getMemoryPoolMXBeansMethod); + + jint size = env->CallIntMethod(memoryPoolMXBeansList, _getListSizeMethod); + + for (int i = 0; i < size; ++i) { + jobject memoryPoolMXBean = + env->CallObjectMethod(memoryPoolMXBeansList, _getListUseIndexMethod, i); + jobject usageObject = + env->CallObjectMethod(memoryPoolMXBean, _getMemoryPoolMXBeanUsageMethod); + + jlong used = env->CallLongMethod(usageObject, _getMemoryUsageUsedMethod); + jlong max = env->CallLongMethod(usageObject, _getMemoryUsageMaxMethod); + + jobject peakUsageObject = + env->CallObjectMethod(memoryPoolMXBean, _getMemoryPollMXBeanPeakMethod); + + jlong peakUsed = env->CallLongMethod(peakUsageObject, _getMemoryUsageUsedMethod); + + jstring name = + (jstring)env->CallObjectMethod(memoryPoolMXBean, _getMemoryPollMXBeanNameMethod); + const char* nameStr = env->GetStringUTFChars(name, NULL); + if (nameStr != NULL) { + auto it = _memoryPoolName.find(nameStr); + if (it == _memoryPoolName.end()) { + continue; + } + if (it->second == memoryPoolNameEnum::YOUNG) { + jvm_metrics->jvm_young_size_bytes_used->set_value(used < 0 ? 0 : used); + jvm_metrics->jvm_young_size_bytes_peak_used->set_value(peakUsed < 0 ? 0 : peakUsed); + jvm_metrics->jvm_young_size_bytes_max->set_value(max < 0 ? 0 : max); + + } else if (it->second == memoryPoolNameEnum::OLD) { + jvm_metrics->jvm_old_size_bytes_used->set_value(used < 0 ? 0 : used); + jvm_metrics->jvm_old_size_bytes_peak_used->set_value(peakUsed < 0 ? 0 : peakUsed); + jvm_metrics->jvm_old_size_bytes_max->set_value(max < 0 ? 0 : max); + } + + env->ReleaseStringUTFChars(name, nameStr); + } + env->DeleteLocalRef(memoryPoolMXBean); + env->DeleteLocalRef(usageObject); + env->DeleteLocalRef(peakUsageObject); + } + + jobject threadMXBean = + env->CallStaticObjectMethod(_managementFactoryClass, _getThreadMXBeanMethod); + + jlongArray threadIds = (jlongArray)env->CallObjectMethod(threadMXBean, _getAllThreadIdsMethod); + jint threadCount = env->GetArrayLength(threadIds); + + jobjectArray threadInfos = + (jobjectArray)env->CallObjectMethod(threadMXBean, _getThreadInfoMethod, threadIds, 0); + + int threadsNew = 0, threadsRunnable = 0, threadsBlocked = 0, threadsWaiting = 0, + threadsTimedWaiting = 0, threadsTerminated = 0; + jint peakThreadCount = env->CallIntMethod(threadMXBean, _getPeakThreadCountMethod); + + jvm_metrics->jvm_thread_peak_count->set_value(peakThreadCount < 0 ? 0 : peakThreadCount); + jvm_metrics->jvm_thread_count->set_value(threadCount < 0 ? 0 : threadCount); + + for (int i = 0; i < threadCount; i++) { + jobject threadInfo = env->GetObjectArrayElement(threadInfos, i); + if (threadInfo == nullptr) { + continue; + } + jobject threadState = env->CallObjectMethod(threadInfo, _getThreadStateMethod); + + if (env->IsSameObject(threadState, _newThreadStateObj)) { + threadsNew++; + } else if (env->IsSameObject(threadState, _runnableThreadStateObj)) { + threadsRunnable++; + } else if (env->IsSameObject(threadState, _blockedThreadStateObj)) { + threadsBlocked++; + } else if (env->IsSameObject(threadState, _waitingThreadStateObj)) { + threadsWaiting++; + } else if (env->IsSameObject(threadState, _timedWaitingThreadStateObj)) { + threadsTimedWaiting++; + } else if (env->IsSameObject(threadState, _terminatedThreadStateObj)) { + threadsTerminated++; + } + env->DeleteLocalRef(threadInfo); + env->DeleteLocalRef(threadState); + } + + jvm_metrics->jvm_thread_new_count->set_value(threadsNew < 0 ? 0 : threadsNew); + jvm_metrics->jvm_thread_runnable_count->set_value(threadsRunnable < 0 ? 0 : threadsRunnable); + jvm_metrics->jvm_thread_blocked_count->set_value(threadsBlocked < 0 ? 0 : threadsBlocked); + jvm_metrics->jvm_thread_waiting_count->set_value(threadsWaiting < 0 ? 0 : threadsWaiting); + jvm_metrics->jvm_thread_timed_waiting_count->set_value( + threadsTimedWaiting < 0 ? 0 : threadsTimedWaiting); + jvm_metrics->jvm_thread_terminated_count->set_value(threadsTerminated < 0 ? 0 + : threadsTerminated); + + jobject gcMXBeansList = + env->CallStaticObjectMethod(_managementFactoryClass, _getGarbageCollectorMXBeansMethod); + + jint numCollectors = env->CallIntMethod(gcMXBeansList, _getListSizeMethod); + + for (int i = 0; i < numCollectors; i++) { + jobject gcMXBean = env->CallObjectMethod(gcMXBeansList, _getListUseIndexMethod, i); + + jstring gcName = (jstring)env->CallObjectMethod(gcMXBean, _getGCNameMethod); + jlong gcCollectionCount = env->CallLongMethod(gcMXBean, _getGCCollectionCountMethod); + jlong gcCollectionTime = env->CallLongMethod(gcMXBean, _getGCCollectionTimeMethod); + const char* gcNameStr = env->GetStringUTFChars(gcName, NULL); + if (gcNameStr != nullptr) { + if (strcmp(gcNameStr, "G1 Young Generation") == 0) { + jvm_metrics->jvm_gc_g1_young_generation_count->set_value(gcCollectionCount); + jvm_metrics->jvm_gc_g1_young_generation_time_ms->set_value(gcCollectionTime); + + } else { + jvm_metrics->jvm_gc_g1_old_generation_count->set_value(gcCollectionCount); + jvm_metrics->jvm_gc_g1_old_generation_time_ms->set_value(gcCollectionTime); + } + + env->ReleaseStringUTFChars(gcName, gcNameStr); + } + env->DeleteLocalRef(gcMXBean); + } + env->DeleteLocalRef(memoryMXBeanObj); + env->DeleteLocalRef(heapMemoryUsageObj); + env->DeleteLocalRef(nonHeapMemoryUsageObj); + env->DeleteLocalRef(memoryPoolMXBeansList); + env->DeleteLocalRef(threadMXBean); + env->DeleteLocalRef(gcMXBeansList); +} +jvmStats::~jvmStats() { + if (!_init_complete) { + return; + } + env->DeleteLocalRef(_newThreadStateObj); + env->DeleteLocalRef(_runnableThreadStateObj); + env->DeleteLocalRef(_blockedThreadStateObj); + env->DeleteLocalRef(_waitingThreadStateObj); + env->DeleteLocalRef(_timedWaitingThreadStateObj); + env->DeleteLocalRef(_terminatedThreadStateObj); +} + +} // namespace doris diff --git a/be/src/util/jvm_metrics.h b/be/src/util/jvm_metrics.h new file mode 100644 index 00000000000..5f9929d8cf0 --- /dev/null +++ b/be/src/util/jvm_metrics.h @@ -0,0 +1,149 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +#include <jni.h> + +#include "jni.h" +#include "util/jni-util.h" +#include "util/metrics.h" + +namespace doris { + +class JvmMetrics; + +class jvmStats { +private: + JNIEnv* env = nullptr; + jclass _managementFactoryClass = nullptr; + jmethodID _getMemoryMXBeanMethod = nullptr; + jclass _memoryUsageClass = nullptr; + jclass _memoryMXBeanClass = nullptr; + jmethodID _getHeapMemoryUsageMethod = nullptr; + jmethodID _getNonHeapMemoryUsageMethod = nullptr; + jmethodID _getMemoryUsageUsedMethod = nullptr; + jmethodID _getMemoryUsageCommittedMethod = nullptr; + jmethodID _getMemoryUsageMaxMethod = nullptr; + + jmethodID _getMemoryPoolMXBeansMethod = nullptr; + + jclass _listClass = nullptr; + jmethodID _getListSizeMethod = nullptr; + jmethodID _getListUseIndexMethod = nullptr; + + jclass _memoryPoolMXBeanClass = nullptr; + jmethodID _getMemoryPoolMXBeanUsageMethod = nullptr; + + jmethodID _getMemoryPollMXBeanPeakMethod = nullptr; + jmethodID _getMemoryPollMXBeanNameMethod = nullptr; + + enum memoryPoolNameEnum { YOUNG, SURVIVOR, OLD }; + const std::map<std::string, memoryPoolNameEnum> _memoryPoolName = { + {"Eden Space", YOUNG}, + {"PS Eden Space", YOUNG}, + {"Par Eden Space", YOUNG}, + {"G1 Eden Space", YOUNG}, + + {"Survivor Space", SURVIVOR}, + {"PS Survivor Space", SURVIVOR}, + {"Par Survivor Space", SURVIVOR}, + {"G1 Survivor Space", SURVIVOR}, + + {"Tenured Gen", OLD}, + {"PS Old Gen", OLD}, + {"CMS Old Gen", OLD}, + {"G1 Old Gen", OLD}, + + }; + + jmethodID _getThreadMXBeanMethod = nullptr; + jclass _threadMXBeanClass = nullptr; + jmethodID _getAllThreadIdsMethod = nullptr; + jmethodID _getThreadInfoMethod = nullptr; + jclass _threadInfoClass = nullptr; + + jmethodID _getPeakThreadCountMethod = nullptr; + + jmethodID _getThreadStateMethod = nullptr; + jclass _threadStateClass = nullptr; + + jobject _newThreadStateObj = nullptr; + jobject _runnableThreadStateObj = nullptr; + jobject _blockedThreadStateObj = nullptr; + jobject _waitingThreadStateObj = nullptr; + jobject _timedWaitingThreadStateObj = nullptr; + jobject _terminatedThreadStateObj = nullptr; + + jclass _garbageCollectorMXBeanClass = nullptr; + jmethodID _getGCNameMethod = nullptr; + jmethodID _getGarbageCollectorMXBeansMethod = nullptr; + jmethodID _getGCCollectionCountMethod = nullptr; + jmethodID _getGCCollectionTimeMethod = nullptr; + + bool _init_complete = false; + +public: + jvmStats(JNIEnv* ENV); + bool init_complete() { return _init_complete; } + void refresh(JvmMetrics* jvm_metrics); + ~jvmStats(); +}; + +class JvmMetrics { +public: + JvmMetrics(MetricRegistry* registry, JNIEnv* env); + ~JvmMetrics() {} + void update(); + + IntGauge* jvm_heap_size_bytes_max = nullptr; + IntGauge* jvm_heap_size_bytes_committed = nullptr; + IntGauge* jvm_heap_size_bytes_used = nullptr; + + IntGauge* jvm_non_heap_size_bytes_used = nullptr; + IntGauge* jvm_non_heap_size_bytes_committed = nullptr; + + IntGauge* jvm_young_size_bytes_used = nullptr; + IntGauge* jvm_young_size_bytes_peak_used = nullptr; + IntGauge* jvm_young_size_bytes_max = nullptr; + + IntGauge* jvm_old_size_bytes_used = nullptr; + IntGauge* jvm_old_size_bytes_peak_used = nullptr; + IntGauge* jvm_old_size_bytes_max = nullptr; + + IntGauge* jvm_thread_count = nullptr; + IntGauge* jvm_thread_peak_count = nullptr; + IntGauge* jvm_thread_new_count = nullptr; + IntGauge* jvm_thread_runnable_count = nullptr; + IntGauge* jvm_thread_blocked_count = nullptr; + IntGauge* jvm_thread_waiting_count = nullptr; + IntGauge* jvm_thread_timed_waiting_count = nullptr; + IntGauge* jvm_thread_terminated_count = nullptr; + + IntGauge* jvm_gc_g1_young_generation_count = nullptr; + IntGauge* jvm_gc_g1_young_generation_time_ms = nullptr; + IntGauge* jvm_gc_g1_old_generation_count = nullptr; + IntGauge* jvm_gc_g1_old_generation_time_ms = nullptr; + +private: + jvmStats _jvm_stats; + std::shared_ptr<MetricEntity> _server_entity; + static const char* _s_hook_name; + MetricRegistry* _registry = nullptr; +}; + +} // namespace doris --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
