From 563b301401a53bec6aaffa59e7d6fa5ba50a7178 Mon Sep 17 00:00:00 2001 From: lvninglei Date: Mon, 8 Sep 2025 16:21:49 +0800 Subject: [PATCH] Add sysEvent of long time CMCGC https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/ICVKBB Signed-off-by: lvninglei Change-Id: Ib9e905e0e34f5620f280314783f57f197aa12aeb --- BUILD.gn | 5 + common_components/BUILD.gn | 9 + .../common_runtime}/clock_scope.h | 2 +- common_components/common_runtime/hooks.h | 1 + .../heap/ark_collector/ark_collector.cpp | 1 + common_components/heap/collector/gc_stats.h | 63 ++++ .../heap/collector/long_gc_stats.h | 280 ++++++++++++++++++ .../heap/collector/marking_collector.cpp | 71 ++++- .../heap/collector/marking_collector.h | 2 + common_components/platform/dfx_hisys_event.h | 32 ++ .../platform/unix/linux/dfx_hisys_event.cpp | 85 ++++++ .../platform/unix/mac/dfx_hisys_event.cpp | 35 +++ .../platform/windows/dfx_hisys_event.cpp | 35 +++ common_components/tests/test_hooks.cpp | 1 + ecmascript/compiler/compiler_log.h | 2 +- ecmascript/dfx/hprof/heap_profiler.h | 2 +- ecmascript/jit/jit.h | 2 +- ecmascript/js_vm/main.cpp | 2 +- ecmascript/mem/cmc_gc/hooks.cpp | 6 + ecmascript/mem/concurrent_marker.h | 2 +- ecmascript/mem/gc_stats.h | 2 +- ecmascript/tests/concurrent_marking_test.cpp | 2 +- ecmascript/tests/incremental_marking_test.cpp | 2 +- hisysevent.yaml | 27 ++ 24 files changed, 656 insertions(+), 15 deletions(-) rename {ecmascript/mem => common_components/common_runtime}/clock_scope.h (98%) create mode 100644 common_components/heap/collector/long_gc_stats.h create mode 100644 common_components/platform/dfx_hisys_event.h create mode 100644 common_components/platform/unix/linux/dfx_hisys_event.cpp create mode 100644 common_components/platform/unix/mac/dfx_hisys_event.cpp create mode 100644 common_components/platform/windows/dfx_hisys_event.cpp diff --git a/BUILD.gn b/BUILD.gn index eeb318d6af..ce0773f686 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1298,6 +1298,7 @@ if (is_mingw) { "common_components/platform/windows/cpu.cpp", "common_components/platform/windows/map.cpp", "common_components/platform/windows/os.cpp", + "common_components/platform/windows/dfx_hisys_event.cpp", "ecmascript/platform/common/dfx_crash_obj.cpp", "ecmascript/platform/windows/backtrace.cpp", "ecmascript/platform/windows/async_detect.cpp", @@ -1326,6 +1327,7 @@ if (is_mingw) { ecma_platform_source += [ "common_components/platform/unix/mac/cpu.cpp", "common_components/platform/unix/mac/os.cpp", + "common_components/platform/unix/mac/dfx_hisys_event.cpp", "ecmascript/platform/common/dfx_crash_obj.cpp", "ecmascript/platform/unix/mac/os.cpp", "ecmascript/platform/unix/mac/backtrace.cpp", @@ -1342,6 +1344,7 @@ if (is_mingw) { ecma_platform_source += [ "common_components/platform/unix/mac/cpu.cpp", "common_components/platform/unix/mac/os.cpp", + "common_components/platform/unix/mac/dfx_hisys_event.cpp", "ecmascript/platform/unix/mac/os.cpp", "ecmascript/platform/unix/mac/backtrace.cpp", "ecmascript/platform/unix/mac/async_detect.cpp", @@ -1358,6 +1361,7 @@ if (is_mingw) { ecma_platform_source += [ "common_components/platform/unix/linux/cpu.cpp", "common_components/platform/unix/linux/os.cpp", + "common_components/platform/unix/linux/dfx_hisys_event.cpp", "ecmascript/platform/unix/linux/os.cpp", "ecmascript/platform/unix/ohos/backtrace.cpp", "ecmascript/platform/unix/ohos/async_detect.cpp", @@ -1393,6 +1397,7 @@ if (is_mingw) { ecma_platform_source += [ "common_components/platform/unix/linux/cpu.cpp", "common_components/platform/unix/linux/os.cpp", + "common_components/platform/unix/linux/dfx_hisys_event.cpp", "ecmascript/platform/unix/linux/os.cpp", "ecmascript/platform/unix/linux/backtrace.cpp", "ecmascript/platform/unix/linux/async_detect.cpp", diff --git a/common_components/BUILD.gn b/common_components/BUILD.gn index 82c53975a7..4d9ecea19b 100755 --- a/common_components/BUILD.gn +++ b/common_components/BUILD.gn @@ -387,21 +387,25 @@ ohos_shared_library("libark_common_components_test") { sources += [ "platform/windows/cpu.cpp", "platform/windows/os.cpp", + "platform/windows/dfx_hisys_event.cpp", ] } else if (is_mac) { sources += [ "platform/unix/mac/cpu.cpp", "platform/unix/mac/os.cpp", + "platform/unix/mac/dfx_hisys_event.cpp", ] } else if (is_ohos || target_os == "android") { sources += [ "platform/unix/linux/cpu.cpp", "platform/unix/linux/os.cpp", + "platform/unix/linux/dfx_hisys_event.cpp", ] } else if (is_linux) { sources += [ "platform/unix/linux/cpu.cpp", "platform/unix/linux/os.cpp", + "platform/unix/linux/dfx_hisys_event.cpp", ] } @@ -458,27 +462,32 @@ ohos_shared_library("libark_common_components_fuzz_test") { sources = [ "log/log.cpp", "base/utf_helper.cpp", + "tests/test_hooks.cpp", ] if (is_mingw) { sources += [ "platform/windows/cpu.cpp", "platform/windows/os.cpp", + "platform/windows/dfx_hisys_event.cpp", ] } else if (is_mac) { sources += [ "platform/unix/mac/cpu.cpp", "platform/unix/mac/os.cpp", + "platform/unix/mac/dfx_hisys_event.cpp", ] } else if (is_ohos || target_os == "android") { sources += [ "platform/unix/linux/cpu.cpp", "platform/unix/linux/os.cpp", + "platform/unix/linux/dfx_hisys_event.cpp", ] } else if (is_linux) { sources += [ "platform/unix/linux/cpu.cpp", "platform/unix/linux/os.cpp", + "platform/unix/linux/dfx_hisys_event.cpp", ] } diff --git a/ecmascript/mem/clock_scope.h b/common_components/common_runtime/clock_scope.h similarity index 98% rename from ecmascript/mem/clock_scope.h rename to common_components/common_runtime/clock_scope.h index 1d4bd3f3aa..0439446968 100644 --- a/ecmascript/mem/clock_scope.h +++ b/common_components/common_runtime/clock_scope.h @@ -66,5 +66,5 @@ private: Clock::time_point start_; static constexpr uint32_t MILLION_TIME = 1000; }; -} // namespace panda::ecmascript +} // namespace common #endif // ECMASCRIPT_MEM_CLOCK_SCOPE_H diff --git a/common_components/common_runtime/hooks.h b/common_components/common_runtime/hooks.h index a59c64f5b8..3272e086db 100644 --- a/common_components/common_runtime/hooks.h +++ b/common_components/common_runtime/hooks.h @@ -51,6 +51,7 @@ PUBLIC_API void FillFreeObject(void *object, size_t size); PUBLIC_API void SetBaseAddress(uintptr_t base); PUBLIC_API void JSGCCallback(void *ecmaVM); PUBLIC_API bool IsPostForked(); +PUBLIC_API std::string GetBundleName(); // Jit interfaces PUBLIC_API void SweepThreadLocalJitFort(); diff --git a/common_components/heap/ark_collector/ark_collector.cpp b/common_components/heap/ark_collector/ark_collector.cpp index 2d90d19773..65eb48e545 100755 --- a/common_components/heap/ark_collector/ark_collector.cpp +++ b/common_components/heap/ark_collector/ark_collector.cpp @@ -764,6 +764,7 @@ void ArkCollector::FixHeap() { TransitionToGCPhase(GCPhase::GC_PHASE_FIX, true); COMMON_PHASE_TIMER("FixHeap"); + TRACE_CMCGC(GCStats::CMCScope::ScopeId::FixHeap, &GetGCStats()); OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::FixHeap", ""); ParallelFixHeap(); diff --git a/common_components/heap/collector/gc_stats.h b/common_components/heap/collector/gc_stats.h index ceb21991b8..51732681ce 100755 --- a/common_components/heap/collector/gc_stats.h +++ b/common_components/heap/collector/gc_stats.h @@ -26,16 +26,29 @@ #include "common_components/heap/collector/gc_request.h" #include "common_components/log/log.h" #include "common_interfaces/base_runtime.h" +#include "common_components/common_runtime/clock_scope.h" namespace common { + +#define CMC_SCOPE_LIST(V) \ + V(TotalGC) \ + V(MarkingRoots) \ + V(CopyFromSpace) \ + V(FixHeap) + +#define TRACE_CMCGC(scope_id, gc_stats) \ + [[maybe_unused]] GCStats::CMCScope sp(scope_id, gc_stats) // statistics for previous gc. class GCStats { + using Duration = std::chrono::duration; public: GCStats() = default; ~GCStats() = default; void Init(); + static constexpr uint32_t THOUSAND = 1000; + size_t GetThreshold() const { return heapThreshold; } inline uint64_t TotalSTWTime() const { return totalSTWTime; } @@ -62,6 +75,31 @@ public: void IncreaseAccumulatedFreeSize(size_t size) { accumulatedFreeSize += size; } + class CMCScope : public panda::ecmascript::ClockScope { + public: + enum ScopeId : uint8_t { +#define DEFINE_SCOPE(scope) scope, + CMC_SCOPE_LIST(DEFINE_SCOPE) +#undef DEFINE_SCOPE + CMC_SCOPE_NUM, + }; + + CMCScope(ScopeId id, GCStats* stats) : id_(id), stats_(stats) + { + } + + ~CMCScope() + { + float duration = stats_->PrintTimeMilliseconds(stats_->TimeToMicroseconds(GetPauseTime())); + stats_->SetScopeId(id_, duration); + } + + private: + ScopeId id_; + GCStats* stats_; + }; + + float scopeDuration_[CMCScope::ScopeId::CMC_SCOPE_NUM] {0.0f}; static uint64_t prevGcStartTime; static uint64_t prevGcFinishTime; @@ -99,6 +137,11 @@ public: size_t heapThreshold; size_t targetFootprint; + size_t beforeGCTAllocatedSize; + size_t beforeGCThreshold; + size_t beforeGCNativeAllocatedSize; + size_t beforeGCNativeThreshold; + // Use for heuristic request, set by last gc status. bool shouldRequestYoung; @@ -106,6 +149,26 @@ public: { return reason == GCReason::GC_REASON_YOUNG; } + + void SetScopeId(int pos, float duration) + { + scopeDuration_[pos] = duration; + } + + static float PrintTimeMilliseconds(uint64_t ms) + { + return (float)ms / THOUSAND; + } + + float GetScopeDuration(int pos) const + { + return scopeDuration_[pos]; + } + + static size_t TimeToMicroseconds(Duration time) + { + return std::chrono::duration_cast(time).count(); + } }; extern size_t g_gcCount; extern uint64_t g_gcTotalTimeUs; diff --git a/common_components/heap/collector/long_gc_stats.h b/common_components/heap/collector/long_gc_stats.h new file mode 100644 index 0000000000..a69aeebdc7 --- /dev/null +++ b/common_components/heap/collector/long_gc_stats.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed 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. + */ + +#ifndef ECMASCRIPT_MEM_LONG_CMC_GC_STATS_H +#define ECMASCRIPT_MEM_LONG_CMC_GC_STATS_H +#include +#include "common_components/heap/collector/gc_stats.h" +#include "common_components/heap/heap.h" + +namespace common { +class LongCMCGCStats { +public: + ~LongCMCGCStats() = default; + static constexpr uint32_t MB = 1024; + static constexpr uint32_t MILLION = 1000 * 1000; + static constexpr uint32_t STW_TIME = 16; + static constexpr uint32_t MAX_STW_TIME = 33; + void Reset() + { + gcType_ = 0; + gcReason_ = 0; + gcIsSensitive_ = false; + gcIsInBackground_ = false; + gcTotalTime_ = 0.0f; + gcCopyFromSpaceTime_ = 0.0f; + gcFixHeapTime_ = 0.0f; + gcMaxSTWTime_ = 0.0f; + gcSTWTime_ = 0.0f; + beforeGCTAllocatedSize_ = 0; + beforeGCThreshold_ = 0; + beforeGCNativeAllocatedSize_ = 0; + beforeGCNativeThreshold_ = 0; + afterGCTAllocatedSize_ = 0; + afterGCThreshold_ = 0; + afterGCNativeAllocatedSize_ = 0; + afterGCNativeThreshold_ = 0; + cpuLoad_ = 0.0; + } + static int SizeToIntKB(size_t size) + { + return static_cast(size / MB); + } + size_t GetGCType() const + { + return gcType_; + } + void SetGCType(size_t gcType) + { + gcType_ = gcType; + } + + size_t GetGCReason() const + { + return gcReason_; + } + void SetGCReason(size_t gcReason) + { + gcReason_ = gcReason; + } + + bool GetGCIsSensitive() const + { + return gcIsSensitive_; + } + void SetGCIsSensitive(bool gcIsSensitive) + { + gcIsSensitive_ = gcIsSensitive; + } + + bool GetGCIsInBackground() const + { + return gcIsInBackground_; + } + void SetGCIsInBackground(bool gcIsInBackground) + { + gcIsInBackground_ = gcIsInBackground; + } + + float GetGCTotalTime() const + { + return gcTotalTime_; + } + void SetGCTotalTime(float gcTotalTime) + { + gcTotalTime_ = gcTotalTime; + } + + float GetGCMarkRootsTime() const + { + return gcMarkRootsTime_; + } + + void SetGCMarkRootsTime(float gcMarkRootsTime) + { + gcMarkRootsTime_ = gcMarkRootsTime; + } + + float GetGCCopyFromSpaceTime() const + { + return gcCopyFromSpaceTime_; + } + + void SetGCCopyFromSpaceTime(float gcCopyFromSpaceTime) + { + gcCopyFromSpaceTime_ = gcCopyFromSpaceTime; + } + + float GetGCFixHeapTime() const + { + return gcFixHeapTime_; + } + void SetGCFixHeapTime(float gcFixHeapTime) + { + gcFixHeapTime_ = gcFixHeapTime; + } + + float GetGCMaxSTWTime() const + { + return gcMaxSTWTime_; + } + void SetGCMaxSTWTime(float gcMaxSTWTime) + { + gcMaxSTWTime_ = gcMaxSTWTime; + } + + float GetGCSTWTime() const + { + return gcSTWTime_; + } + void SetGCSTWTime(float gcSTWTime) + { + gcSTWTime_ = gcSTWTime; + } + + size_t GetBeforeGCTAllocatedSize() const + { + return beforeGCTAllocatedSize_; + } + void SetBeforeGCTAllocatedSize(size_t beforeGCTAllocatedSize) + { + beforeGCTAllocatedSize_ = beforeGCTAllocatedSize; + } + + size_t GetBeforeGCThreshold() const + { + return beforeGCThreshold_; + } + void SetBeforeGCThreshold(size_t beforeGCThreshold) + { + beforeGCThreshold_ = beforeGCThreshold; + } + + size_t GetBeforeGCNativeAllocatedSize() const + { + return beforeGCNativeAllocatedSize_; + } + void SetBeforeGCNativeAllocatedSize(size_t beforeGCNativeAllocatedSize) + { + beforeGCNativeAllocatedSize_ = beforeGCNativeAllocatedSize; + } + + size_t GetBeforeGCNativeThreshold() const + { + return beforeGCNativeThreshold_; + } + void SetBeforeGCNativeThreshold(size_t beforeGCNativeThreshold) + { + beforeGCNativeThreshold_ = beforeGCNativeThreshold; + } + + size_t GetAfterGCTAllocatedSize() const + { + return afterGCTAllocatedSize_; + } + void SetAfterGCTAllocatedSize(size_t afterGCTAllocatedSize) + { + afterGCTAllocatedSize_ = afterGCTAllocatedSize; + } + + size_t GetAfterGCThreshold() const + { + return afterGCThreshold_; + } + void SetAfterGCThreshold(size_t afterGCThreshold) + { + afterGCThreshold_ = afterGCThreshold; + } + + size_t GetAfterGCNativeAllocatedSize() const + { + return afterGCNativeAllocatedSize_; + } + void SetAfterGCNativeAllocatedSize(size_t afterGCNativeAllocatedSize) + { + afterGCNativeAllocatedSize_ = afterGCNativeAllocatedSize; + } + + size_t GetAfterGCNativeThreshold() const + { + return afterGCNativeThreshold_; + } + void SetAfterGCNativeThreshold(size_t afterGCNativeThreshold) + { + afterGCNativeThreshold_ = afterGCNativeThreshold; + } + + double GetCpuLoad() const + { + return cpuLoad_; + } + void SetCpuLoad(double cpuLoad) + { + cpuLoad_ = cpuLoad; + } + + void ProcessData(GCStats& gcStats) + { + auto currentAllocatedSize = Heap::GetHeap().GetAllocatedSize(); + auto currentThreshold = Heap::GetHeap().GetCollector().GetGCStats().GetThreshold(); + auto currentNative = Heap::GetHeap().GetNotifiedNativeSize(); + auto nativeThreshold = Heap::GetHeap().GetNativeHeapThreshold(); + bool gcIsSensitive = Heap::GetHeap().GetSensitiveStatus() == AppSensitiveStatus::ENTER_HIGH_SENSITIVE; + bool gcIsInBackground = gcStats.reason == GC_REASON_BACKGROUND; + SetGCType(gcStats.gcType); + SetGCReason(gcStats.reason); + SetGCIsSensitive(gcIsSensitive); + SetGCIsInBackground(gcIsInBackground); + SetGCTotalTime((float)gcStats.gcEndTime - gcStats.gcStartTime / MILLION); + SetGCMaxSTWTime((float)gcStats.maxSTWTime / MILLION); + SetGCSTWTime((float)gcStats.totalSTWTime / MILLION); + SetGCMarkRootsTime(gcStats.GetScopeDuration(GCStats::CMCScope::ScopeId::MarkingRoots)); + SetGCCopyFromSpaceTime(gcStats.GetScopeDuration(GCStats::CMCScope::ScopeId::CopyFromSpace)); + SetGCFixHeapTime(gcStats.GetScopeDuration(GCStats::CMCScope::ScopeId::FixHeap)); + SetBeforeGCTAllocatedSize(gcStats.beforeGCTAllocatedSize); + SetBeforeGCThreshold(gcStats.beforeGCThreshold); + SetBeforeGCNativeAllocatedSize(gcStats.beforeGCNativeAllocatedSize); + SetBeforeGCNativeThreshold(gcStats.beforeGCNativeThreshold); + SetAfterGCTAllocatedSize(currentAllocatedSize); + SetAfterGCThreshold(currentThreshold); + SetAfterGCNativeAllocatedSize(currentNative); + SetAfterGCNativeThreshold(nativeThreshold); + } + +private: + size_t gcType_ = 0; + size_t gcReason_ = 0; + bool gcIsSensitive_ = false; + bool gcIsInBackground_ = false; + float gcTotalTime_ = 0.0f; + float gcMarkRootsTime_ = 0.0f; + float gcCopyFromSpaceTime_ = 0.0f; + float gcFixHeapTime_ = 0.0f; + float gcMaxSTWTime_ = 0.0f; + float gcSTWTime_ = 0.0f; + + size_t beforeGCTAllocatedSize_ = 0; + size_t beforeGCThreshold_ = 0; + size_t beforeGCNativeAllocatedSize_ = 0; + size_t beforeGCNativeThreshold_ = 0; + size_t afterGCTAllocatedSize_ = 0; + size_t afterGCThreshold_ = 0; + size_t afterGCNativeAllocatedSize_ = 0; + size_t afterGCNativeThreshold_ = 0; + double cpuLoad_ = 0.0; +}; +} // common + +#endif // ECMASCRIPT_MEM_LONG_GC_STATS_H \ No newline at end of file diff --git a/common_components/heap/collector/marking_collector.cpp b/common_components/heap/collector/marking_collector.cpp index 3dbc188e8b..020f1a1913 100755 --- a/common_components/heap/collector/marking_collector.cpp +++ b/common_components/heap/collector/marking_collector.cpp @@ -17,14 +17,19 @@ #include #include -#include #include "common_components/heap/allocator/alloc_buffer.h" #include "common_components/heap/collector/heuristic_gc_policy.h" #include "common_interfaces/base/runtime_param.h" +#include #include "common_components/heap/collector/utils.h" +#ifdef ENABLE_HISYSEVENT +#include "hisysevent.h" +#endif +#include "common_components/platform/dfx_hisys_event.h" namespace common { +using DFXHiSysEvent = common::DFXHiSysEvent; const size_t MarkingCollector::MAX_MARKING_WORK_SIZE = 16; // fork task if bigger const size_t MarkingCollector::MIN_MARKING_WORK_SIZE = 8; // forbid forking task if smaller @@ -293,7 +298,7 @@ void MarkingCollector::PushRootsToWorkStack(LocalCollectStack &collectStack, void MarkingCollector::MarkingRoots(const CArrayList &collectedRoots) { OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::MarkingRoots", ""); - + TRACE_CMCGC(GCStats::CMCScope::ScopeId::MarkingRoots, &GetGCStats()); GlobalMarkStack globalMarkStack; { @@ -499,6 +504,10 @@ void MarkingCollector::PreGarbageCollection(bool isConcurrent) gcStats.gcStartTime = TimeUtil::NanoSeconds(); gcStats.totalSTWTime = 0; gcStats.maxSTWTime = 0; + gcStats.beforeGCTAllocatedSize = Heap::GetHeap().GetAllocatedSize(); + gcStats.beforeGCThreshold = Heap::GetHeap().GetCollector().GetGCStats().GetThreshold(); + gcStats.beforeGCNativeAllocatedSize = Heap::GetHeap().GetNotifiedNativeSize(); + gcStats.beforeGCNativeThreshold = Heap::GetHeap().GetNativeHeapThreshold(); #if defined(GCINFO_DEBUG) && GCINFO_DEBUG DumpBeforeGC(); #endif @@ -632,6 +641,8 @@ void MarkingCollector::RunGarbageCollection(uint64_t gcIndex, GCReason reason, G auto gcReasonName = std::string(g_gcRequests[gcReason_].name); auto currentAllocatedSize = Heap::GetHeap().GetAllocatedSize(); auto currentThreshold = Heap::GetHeap().GetCollector().GetGCStats().GetThreshold(); + auto currentNative = Heap::GetHeap().GetNotifiedNativeSize(); + auto nativeThreshold = Heap::GetHeap().GetNativeHeapThreshold(); VLOG(INFO, "Begin GC log. GCReason: %s, GCType: %s, Current allocated %s, Current threshold %s, gcIndex=%llu", gcReasonName.c_str(), GCTypeToString(gcType), Pretty(currentAllocatedSize).c_str(), Pretty(currentThreshold).c_str(), gcIndex); @@ -641,8 +652,8 @@ void MarkingCollector::RunGarbageCollection(uint64_t gcIndex, GCReason reason, G ";Startup:" + std::to_string(static_cast(Heap::GetHeap().GetStartupStatus())) + ";Current Allocated:" + Pretty(currentAllocatedSize) + ";Current Threshold:" + Pretty(currentThreshold) + - ";Current Native:" + Pretty(Heap::GetHeap().GetNotifiedNativeSize()) + - ";NativeThreshold:" + Pretty(Heap::GetHeap().GetNativeHeapThreshold()) + ";Current Native:" + Pretty(currentNative) + + ";NativeThreshold:" + Pretty(nativeThreshold) ).c_str()); // prevent other threads stop-the-world during GC. // this may be removed in the future. @@ -686,7 +697,7 @@ void MarkingCollector::RunGarbageCollection(uint64_t gcIndex, GCReason reason, G } UpdateGCStats(); - + ProcessLongGCEvent(); if (Heap::GetHeap().GetForceThrowOOM()) { Heap::throwOOM(); } @@ -694,10 +705,11 @@ void MarkingCollector::RunGarbageCollection(uint64_t gcIndex, GCReason reason, G void MarkingCollector::CopyFromSpace() { + GCStats& stats = GetGCStats(); OHOS_HITRACE(HITRACE_LEVEL_COMMERCIAL, "CMCGC::CopyFromSpace", ""); + TRACE_CMCGC(GCStats::CMCScope::ScopeId::CopyFromSpace, &stats); TransitionToGCPhase(GCPhase::GC_PHASE_COPY, true); RegionalHeap& space = reinterpret_cast(theAllocator_); - GCStats& stats = GetGCStats(); stats.liveBytesBeforeGC = space.GetAllocatedBytes(); stats.fromSpaceSize = space.FromSpaceSize(); space.CopyFromSpace(GetThreadPool()); @@ -711,4 +723,51 @@ void MarkingCollector::ExemptFromSpace() space.ExemptFromSpace(); } +/* +| The Judgment criteria of Long GC +| IsInBackground | IsSensitive or Idle | GCTime | +| -----------------| ---------------------|---------| +| false | Sensitive | 16 | +| false | !Sensitive & !Idle | 16 | +| true | Idle | 33 | +| true | !Idle | 33 | +| true | Idle | 33 | +*/ +void MarkingCollector::ProcessLongGCEvent() +{ +#ifdef ENABLE_HISYSEVENT + if (!DFXHiSysEvent::IsEnableDFXHiSysEvent()) { + return; + } + GCStats& gcStats = GetGCStats(); + LongCMCGCStats *longGCStats = new LongCMCGCStats(); + bool gcIsSensitive = longGCStats->GetGCIsSensitive(); + bool gcIsInBackground = longGCStats->GetGCIsInBackground(); + float gcMaxSTWTime = longGCStats->GetGCMaxSTWTime(); + longGCStats->ProcessData(gcStats); + if (gcIsSensitive) { + if (gcMaxSTWTime > LongCMCGCStats::STW_TIME) { + DFXHiSysEvent::SendLongCMCGCEvent(longGCStats); + longGCStats->Reset(); + } + } else { + if (gcReason_ == GC_REASON_IDLE) { + if (!gcIsInBackground && gcMaxSTWTime > LongCMCGCStats::STW_TIME) { + longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage()); + DFXHiSysEvent::SendLongCMCGCEvent(longGCStats); + } else if (gcIsInBackground && gcMaxSTWTime > LongCMCGCStats::MAX_STW_TIME) { + longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage()); + DFXHiSysEvent::SendLongCMCGCEvent(longGCStats); + } + } else { + if (!gcIsInBackground && gcMaxSTWTime > LongCMCGCStats::MAX_STW_TIME) { + DFXHiSysEvent::SendLongCMCGCEvent(longGCStats); + } else if (gcIsInBackground && gcMaxSTWTime > LongCMCGCStats::MAX_STW_TIME) { + longGCStats->SetCpuLoad(DFXHiSysEvent::GetCpuUsage()); + DFXHiSysEvent::SendLongCMCGCEvent(longGCStats); + } + } + } +#endif +} } // namespace common diff --git a/common_components/heap/collector/marking_collector.h b/common_components/heap/collector/marking_collector.h index 102bd56f1f..607be16303 100755 --- a/common_components/heap/collector/marking_collector.h +++ b/common_components/heap/collector/marking_collector.h @@ -26,6 +26,7 @@ #include "common_components/heap/allocator/regional_heap.h" #include "common_components/heap/collector/copy_data_manager.h" #include "common_components/mutator/mutator_manager.h" +#include "common_components/heap/collector/long_gc_stats.h" namespace common { @@ -330,6 +331,7 @@ private: void MarkAwaitingJitFort(); void EnumMutatorRoot(ObjectPtr& obj, RootSet& rootSet) const; void EnumConcurrencyModelRoots(RootSet& rootSet) const; + void ProcessLongGCEvent(); }; diff --git a/common_components/platform/dfx_hisys_event.h b/common_components/platform/dfx_hisys_event.h new file mode 100644 index 0000000000..d8bf2c254a --- /dev/null +++ b/common_components/platform/dfx_hisys_event.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed 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. + */ + +#ifndef COMMON_PLATFORM_DFX_HISYS_EVENT_H +#define COMMON_PLATFORM_DFX_HISYS_EVENT_H + +#include "common_components/heap/collector/long_gc_stats.h" + +namespace common { +class DFXHiSysEvent { + +public: + static void SendLongCMCGCEvent(LongCMCGCStats *longGCStats); + + static bool IsEnableDFXHiSysEvent(); + + static double GetCpuUsage(); +}; +} // namespace common +#endif // COMMON_PLATFORM_DFX_HISYS_EVENT_H diff --git a/common_components/platform/unix/linux/dfx_hisys_event.cpp b/common_components/platform/unix/linux/dfx_hisys_event.cpp new file mode 100644 index 0000000000..08196a7260 --- /dev/null +++ b/common_components/platform/unix/linux/dfx_hisys_event.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed 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 "common_components/platform/dfx_hisys_event.h" +#include "common_components/common_runtime/hooks.h" +#ifdef ENABLE_HISYSEVENT +#include "hisysevent.h" +#include "sys/syscall.h" +#endif +#ifdef ENABLE_UCOLLECTION +#include "cpu_collector_client.h" +#endif + +namespace common { + +void DFXHiSysEvent::SendLongCMCGCEvent([[maybe_unused]] LongCMCGCStats *longGCStats) +{ +#ifdef ENABLE_HISYSEVENT + LOG_GC(DEBUG) << "SendLongCMCGCEvent: GC_TYPE" << longGCStats->GetGCType() + << ";GC_REASON" << longGCStats->GetGCReason() + << ";GC_IS_SENSITIVE" << longGCStats->GetGCIsSensitive() + << ";GC_MAX_STW_TIME" << longGCStats->GetGCMaxSTWTime(); + int32_t ret = HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::ARKTS_RUNTIME, + "ARK_CMCGC_LONG_TIME", OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR, + "BUNDLE_NAME", GetBundleName(), + "PID", getpid(), + "TID", syscall(SYS_gettid), + "GC_TYPE", longGCStats->GetGCType(), + "GC_REASON", longGCStats->GetGCReason(), + "GC_IS_SENSITIVE", static_cast(longGCStats->GetGCIsSensitive()), + "GC_IS_INBACKGROUND", static_cast(longGCStats->GetGCIsInBackground()), + "GC_TOTAL_TIME", longGCStats->GetGCTotalTime(), + "GC_MAX_STW_TIME", longGCStats->GetGCMaxSTWTime(), + "GC_STW_TIME", longGCStats->GetGCSTWTime(), + "GC_MARKINGROOTS_TIME", longGCStats->GetGCMarkRootsTime(), + "GC_COPYFROMSPACE_TIME", longGCStats->GetGCCopyFromSpaceTime(), + "GC_FIXHEAP_TIME", longGCStats->GetGCFixHeapTime(), + "BEFORE_GC_ALLOCATED_SIZE", LongCMCGCStats::SizeToIntKB(longGCStats->GetBeforeGCTAllocatedSize()), + "BEFORE_GC_THRESHOLD", LongCMCGCStats::SizeToIntKB(longGCStats->GetBeforeGCThreshold()), + "BEFORE_GC_NATIVE_ALLOCATED_SIZE", LongCMCGCStats::SizeToIntKB(longGCStats->GetBeforeGCNativeAllocatedSize()), + "BEFORE_GC_NATIVE_THRESHOLD", LongCMCGCStats::SizeToIntKB(longGCStats->GetBeforeGCNativeThreshold()), + "AFTER_GC_ALLOCATED_SIZE", LongCMCGCStats::SizeToIntKB(longGCStats->GetAfterGCTAllocatedSize()), + "AFTER_GC_THRESHOLD", LongCMCGCStats::SizeToIntKB(longGCStats->GetAfterGCThreshold()), + "AFTER_GC_NATIVE_ALLOCATED_SIZE", LongCMCGCStats::SizeToIntKB(longGCStats->GetAfterGCNativeAllocatedSize()), + "AFTER_GC_NATIVE_THRESHOLD", LongCMCGCStats::SizeToIntKB(longGCStats->GetAfterGCNativeThreshold()), + "CPU_LOAD", longGCStats->GetCpuLoad()); + if (ret != 0) { + LOG_GC(ERROR) << "GCKeyStats HiSysEventWrite ARK_CMC_GC_LONG_TIME Failed! ret = " << ret; + } +#endif +} + +bool DFXHiSysEvent::IsEnableDFXHiSysEvent() +{ + return true; +} + +double DFXHiSysEvent::GetCpuUsage() +{ +#ifdef ENABLE_UCOLLECTION + auto collector = OHOS::HiviewDFX::UCollectClient::CpuCollector::Create(); + auto collectResult = collector->GetSysCpuUsage(); + if (collectResult.retCode == OHOS::HiviewDFX::UCollect::UcError::SUCCESS) { + LOG_GC(DEBUG) << "DFXHiSysEvent cpu usage: " << collectResult.data; + return collectResult.data; + } + LOG_GC(ERROR) << "DFXHiSysEvent get cpu usage failed, error code: " << collectResult.retCode; + return -1.0; +#else + return -1.0; +#endif +} +} // namespace common \ No newline at end of file diff --git a/common_components/platform/unix/mac/dfx_hisys_event.cpp b/common_components/platform/unix/mac/dfx_hisys_event.cpp new file mode 100644 index 0000000000..fd10b6fe27 --- /dev/null +++ b/common_components/platform/unix/mac/dfx_hisys_event.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed 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 "common_components/platform/dfx_hisys_event.h" + +namespace common { + +void DFXHiSysEvent::SendLongCMCGCEvent([[maybe_unused]]LongCMCGCStats *longGCStats) +{ + LOG_GC(FATAL) << "Send SendLongCMCGCEvent is not support in macos/ios."; +} + +bool DFXHiSysEvent::IsEnableDFXHiSysEvent() +{ + return false; +} + +double DFXHiSysEvent::GetCpuUsage() +{ + LOG_GC(WARN) << "Get CpuUsage is not support in mac."; + return -1.0; +} +} // namespace common diff --git a/common_components/platform/windows/dfx_hisys_event.cpp b/common_components/platform/windows/dfx_hisys_event.cpp new file mode 100644 index 0000000000..5885775e35 --- /dev/null +++ b/common_components/platform/windows/dfx_hisys_event.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed 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 "common_components/platform/dfx_hisys_event.h" + +namespace common { + +void DFXHiSysEvent::SendLongCMCGCEvent([[maybe_unused]]LongCMCGCStats *longGCStats) +{ + LOG_GC(FATAL) << "Send SendLongCMCGCEvent is not support in windows."; +} + +bool DFXHiSysEvent::IsEnableDFXHiSysEvent() +{ + return false; +} + +double DFXHiSysEvent::GetCpuUsage() +{ + LOG_GC(WARN) << "Get CpuUsage is not support in windows."; + return -1.0; +} +} // namespace common diff --git a/common_components/tests/test_hooks.cpp b/common_components/tests/test_hooks.cpp index bfda438f76..c27864375c 100755 --- a/common_components/tests/test_hooks.cpp +++ b/common_components/tests/test_hooks.cpp @@ -36,6 +36,7 @@ void MarkThreadLocalJitFortInstalled(void* thread, void* machineCode) {} void SynchronizeGCPhaseToJSThread(void *jsThread, GCPhase gcPhase) {} void JSGCCallback(void *ecmaVM) {} bool IsPostForked() { return true; } +std::string GetBundleName() { return ""; } void VisitJSThread(void *jsThread, CommonRootVisitor visitor) {} bool IsMachineCodeObject(uintptr_t objPtr) diff --git a/ecmascript/compiler/compiler_log.h b/ecmascript/compiler/compiler_log.h index 23b4fb43a8..21291e3194 100644 --- a/ecmascript/compiler/compiler_log.h +++ b/ecmascript/compiler/compiler_log.h @@ -26,7 +26,7 @@ #include #include #include "ecmascript/log_wrapper.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/compiler/argument_accessor.h" diff --git a/ecmascript/dfx/hprof/heap_profiler.h b/ecmascript/dfx/hprof/heap_profiler.h index 5a5dafa2c3..a8f4a55fb1 100644 --- a/ecmascript/dfx/hprof/heap_profiler.h +++ b/ecmascript/dfx/hprof/heap_profiler.h @@ -27,7 +27,7 @@ #include "ecmascript/dfx/hprof/string_hashmap.h" #include "ecmascript/dfx/hprof/heap_marker.h" #include "ecmascript/mem/c_containers.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" namespace panda::ecmascript { class HeapSnapshot; diff --git a/ecmascript/jit/jit.h b/ecmascript/jit/jit.h index 49c34906b5..7617f6734f 100644 --- a/ecmascript/jit/jit.h +++ b/ecmascript/jit/jit.h @@ -20,7 +20,7 @@ #include "ecmascript/compiler/compilation_env.h" #include "ecmascript/platform/mutex.h" #include "ecmascript/ecma_vm.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/machine_code.h" #include "ecmascript/compiler/compiler_log.h" #include "ecmascript/jit/jit_thread.h" diff --git a/ecmascript/js_vm/main.cpp b/ecmascript/js_vm/main.cpp index ec4c090156..462ea9a4e5 100644 --- a/ecmascript/js_vm/main.cpp +++ b/ecmascript/js_vm/main.cpp @@ -17,7 +17,7 @@ #include "ecmascript/base/string_helper.h" #include "ecmascript/ecma_vm.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/platform/os.h" diff --git a/ecmascript/mem/cmc_gc/hooks.cpp b/ecmascript/mem/cmc_gc/hooks.cpp index 51229f4e0b..33563242b3 100644 --- a/ecmascript/mem/cmc_gc/hooks.cpp +++ b/ecmascript/mem/cmc_gc/hooks.cpp @@ -27,6 +27,7 @@ #include "ecmascript/runtime.h" #include "objects/base_type.h" #include "objects/composite_base_class.h" +#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" namespace common { using panda::ecmascript::ObjectXRay; @@ -340,6 +341,11 @@ bool IsPostForked() return panda::ecmascript::Runtime::GetInstance()->IsPostForked(); } +std::string GetBundleName() +{ + return panda::ecmascript::pgo::PGOProfilerManager::GetInstance()->GetBundleName(); +} + void SetBaseAddress(uintptr_t base) { // Please be careful about reentrant diff --git a/ecmascript/mem/concurrent_marker.h b/ecmascript/mem/concurrent_marker.h index b5884a8536..9eb9af9017 100644 --- a/ecmascript/mem/concurrent_marker.h +++ b/ecmascript/mem/concurrent_marker.h @@ -21,7 +21,7 @@ #include "common_components/taskpool/task.h" #include "ecmascript/common.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/space.h" #include "ecmascript/mem/visitor.h" #include "ecmascript/mem/work_manager.h" diff --git a/ecmascript/mem/gc_stats.h b/ecmascript/mem/gc_stats.h index a7aed23b81..909d51716f 100644 --- a/ecmascript/mem/gc_stats.h +++ b/ecmascript/mem/gc_stats.h @@ -21,7 +21,7 @@ #include #include "ecmascript/common.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/mem_common.h" #include "ecmascript/mem/long_gc_stats.h" #include "libpandabase/macros.h" diff --git a/ecmascript/tests/concurrent_marking_test.cpp b/ecmascript/tests/concurrent_marking_test.cpp index 8cdb2f2a99..70e8a4eb24 100644 --- a/ecmascript/tests/concurrent_marking_test.cpp +++ b/ecmascript/tests/concurrent_marking_test.cpp @@ -18,7 +18,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_handle.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/concurrent_marker.h" #include "ecmascript/mem/verification.h" diff --git a/ecmascript/tests/incremental_marking_test.cpp b/ecmascript/tests/incremental_marking_test.cpp index b2c1f8efa3..7683c4d09e 100644 --- a/ecmascript/tests/incremental_marking_test.cpp +++ b/ecmascript/tests/incremental_marking_test.cpp @@ -18,7 +18,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_handle.h" -#include "ecmascript/mem/clock_scope.h" +#include "common_components/common_runtime/clock_scope.h" #include "ecmascript/mem/incremental_marker.h" #include "ecmascript/mem/verification.h" diff --git a/hisysevent.yaml b/hisysevent.yaml index 67d2755251..a5aeb453c2 100644 --- a/hisysevent.yaml +++ b/hisysevent.yaml @@ -111,3 +111,30 @@ ARK_RUNTIME_INCOMPATIBLE: FUNCTIONNAME: {type: STRING, desc: Name of the incompatible function} STACK: {type: STRING, desc: Function call stack} BUNDLE_NAME: {type: STRING, desc: Application bundle name} + + +ARK_CMCGC_LONG_TIME: + __BASE: {type: BEHAVIOR, level: CRITICAL, tag: GC, desc: Long time CMCGC event, preserve: true} + BUNDLE_NAME: {type: STRING, desc: bundleName} + VERSION_CODE: {type: STRING, desc: VERSION CODE} + PID: {type: INT8, desc: pid} + TID: {type: INT8, desc: TID of JSVM} + GC_TYPE: {type: INT8, desc: GC TYPE} + GC_REASON: {type: INT8, desc: GC REASON} + GC_IS_SENSITIVE: {type: INT8, desc: GC IS IN SENSITIVE OR NOT} + GC_IS_INBACKGROUND: {type: INT8, desc: GC IS INBACKGROUND OR NOT} + GC_TOTAL_TIME: {type: FLOAT, desc: GC TOTAL TIME} + GC_MAX_STW_TIME: {type: FLOAT, desc: GC MAX STW TIME} + GC_STW_TIME: {type: FLOAT, desc: GC STW TIME} + GC_MARKINGROOTS_TIME: {type: FLOAT, desc: GC MARKINGROOTS TIME} + GC_COPYFROMSPACE_TIME: {type: FLOAT, desc: GC COPYFROMSPACE TIME} + GC_FIXHEAP_TIME: {type: FLOAT, desc: GC FIXHEAP TIME} + BEFORE_GC_ALLOCATED_SIZE: {type: INT32, desc: TOTAL MEM USED BEFORE GC} + BEFORE_GC_THRESHOLD: {type: INT32, desc: BEFORE GC THRESHOLD} + BEFORE_GC_NATIVE_ALLOCATED_SIZE: {type: INT32, desc: BEFORE GC NATIVE MEM USED} + BEFORE_GC_NATIVE_THRESHOLD: {type: INT32, desc: BEFORE GC NATIVE THRESHOLD} + AFTER_GC_ALLOCATED_SIZE: {type: INT32, desc: TOTAL MEM USED AFTER GC} + AFTER_GC_THRESHOLD: {type: INT32, desc: AFTER GC THRESHOLD} + AFTER_GC_NATIVE_ALLOCATED_SIZE: {type: INT32, desc: AFTER GC NATIVE MEM USED} + AFTER_GC_NATIVE_THRESHOLD: {type: INT32, desc: AFTER GC NATIVE THRESHOLD} + CPU_LOAD: {type: DOUBLE, desc: CPU LOAD} \ No newline at end of file -- Gitee