From 85246bddc127160ee136788918cb3015832b6d02 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 22 Jul 2026 15:35:04 +0200 Subject: [PATCH 1/4] fix(codecache): report the real runtime-stubs cache size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CODECACHE_RUNTIME_STUBS_SIZE_BYTES was set to native_libs.memoryUsage() — the same value as CODECACHE_NATIVE_SIZE_BYTES — a copy-paste since the counter was introduced (d0b0d1e44). It never reflected the runtime-stubs cache. The runtime stubs live in JitCodeCache::_runtime_stubs (populated by DynamicCodeGenerated as the JVM emits stubs), a different cache from the native libraries. Add JitCodeCache::runtimeStubsMemoryUsage(), which reads that cache's size under its shared _stubs_lock (the cache is mutated concurrently by the JVMTI callback), and set the counter from it. Co-Authored-By: Claude Opus 4.8 (1M context) --- ddprof-lib/src/main/cpp/hotspot/jitCodeCache.cpp | 7 +++++++ ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h | 5 +++++ ddprof-lib/src/main/cpp/profiler.cpp | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.cpp b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.cpp index 00ec522bfe..a45483686d 100644 --- a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.cpp +++ b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.cpp @@ -52,3 +52,10 @@ CodeBlob* JitCodeCache::findRuntimeStub(const void *address) { _stubs_lock.unlockShared(); return stub; } + +long long JitCodeCache::runtimeStubsMemoryUsage() { + _stubs_lock.lockShared(); + long long usage = _runtime_stubs.memoryUsage(); + _stubs_lock.unlockShared(); + return usage; +} diff --git a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h index 005223384f..88c66be015 100644 --- a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h +++ b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h @@ -38,6 +38,11 @@ class JitCodeCache { } static CodeBlob* findRuntimeStub(const void *address); + + // Live heap footprint of the runtime-stubs code cache. Read under the + // shared stubs lock because DynamicCodeGenerated() mutates _runtime_stubs + // (add()/expand()) concurrently. + static long long runtimeStubsMemoryUsage(); static bool isJitCode(const void* pc) { return CodeHeap::contains(pc); } diff --git a/ddprof-lib/src/main/cpp/profiler.cpp b/ddprof-lib/src/main/cpp/profiler.cpp index ab674ab9c2..031a870b7a 100644 --- a/ddprof-lib/src/main/cpp/profiler.cpp +++ b/ddprof-lib/src/main/cpp/profiler.cpp @@ -21,6 +21,7 @@ #include "itimer.h" #include "hotspot/vmStructs.inline.h" #include "hotspot/hotspotSupport.h" +#include "hotspot/jitCodeCache.h" #include "j9/j9Support.h" #include "j9/j9WallClock.h" #include "jvmSupport.h" @@ -1780,8 +1781,11 @@ Error Profiler::dump(const char *path, const int length) { const CodeCacheArray& native_libs = _libs->native_libs(); Counters::set(CODECACHE_NATIVE_COUNT, native_libs.count()); Counters::set(CODECACHE_NATIVE_SIZE_BYTES, native_libs.memoryUsage()); + // The runtime-stubs counter reflects the JIT runtime-stubs code cache, a + // separate cache from the native libraries (it previously duplicated + // native_libs.memoryUsage() by copy-paste). Read under its shared lock. Counters::set(CODECACHE_RUNTIME_STUBS_SIZE_BYTES, - native_libs.memoryUsage()); + JitCodeCache::runtimeStubsMemoryUsage()); Error err = Error::OK; // rotateDictsAndRun rotates the dictionaries, takes lockAll() around the From 6679e6fa0b4d494b4ee54a7ea89752f2231bd7ac Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 22 Jul 2026 17:15:14 +0200 Subject: [PATCH 2/4] docs(codecache): word runtime-stubs usage as approximate, not "live footprint" CodeCache::memoryUsage() is a capacity/count-based estimate on main, so "live heap footprint" overstated it. Reword to "approximate heap usage" and note #677 makes memoryUsage() exact. Co-Authored-By: Claude Opus 4.8 (1M context) --- ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h index 88c66be015..8d369fe87c 100644 --- a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h +++ b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h @@ -39,9 +39,10 @@ class JitCodeCache { static CodeBlob* findRuntimeStub(const void *address); - // Live heap footprint of the runtime-stubs code cache. Read under the - // shared stubs lock because DynamicCodeGenerated() mutates _runtime_stubs - // (add()/expand()) concurrently. + // Approximate heap usage of the runtime-stubs code cache, via + // CodeCache::memoryUsage() (a capacity/count-based estimate today; #677 + // makes it exact). Read under the shared stubs lock because + // DynamicCodeGenerated() mutates _runtime_stubs (add()/expand()) concurrently. static long long runtimeStubsMemoryUsage(); static bool isJitCode(const void* pc) { return CodeHeap::contains(pc); From 83b5576dd650c89ebc1a7ed8c721eb183acd786c Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Thu, 23 Jul 2026 13:01:18 +0200 Subject: [PATCH 3/4] docs(codecache): drop stale "approximate/#677" note now that memoryUsage is exact With #677 merged, CodeCache::memoryUsage() is accurate on main, so the runtime-stubs accessor comment describing it as an approximation (pending #677) is no longer true. Describe current behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h index 8d369fe87c..0d116ca61f 100644 --- a/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h +++ b/ddprof-lib/src/main/cpp/hotspot/jitCodeCache.h @@ -39,10 +39,9 @@ class JitCodeCache { static CodeBlob* findRuntimeStub(const void *address); - // Approximate heap usage of the runtime-stubs code cache, via - // CodeCache::memoryUsage() (a capacity/count-based estimate today; #677 - // makes it exact). Read under the shared stubs lock because - // DynamicCodeGenerated() mutates _runtime_stubs (add()/expand()) concurrently. + // Heap usage of the runtime-stubs code cache, via CodeCache::memoryUsage(). + // Read under the shared stubs lock because DynamicCodeGenerated() mutates + // _runtime_stubs (add()/expand()) concurrently. static long long runtimeStubsMemoryUsage(); static bool isJitCode(const void* pc) { return CodeHeap::contains(pc); From df34493a9499f571fdee30235b6bc1a9c831a31a Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Thu, 23 Jul 2026 16:05:15 +0200 Subject: [PATCH 4/4] refactor(codecache): route runtime-stubs usage through JVMSupport The runtime-stubs memory counter called the HotSpot-specific JitCodeCache::runtimeStubsMemoryUsage() directly from shared profiler.cpp, with no VM guard. On J9/Zing that reports a fixed near-zero baseline with nothing in the code marking the value as meaningless there. Route it through the same JVMSupport -> HotspotSupport abstraction the sibling isJitCode() accessor uses: JVMSupport::runtimeStubsMemoryUsage() dispatches to HotspotSupport (-> JitCodeCache) on HotSpot and returns 0 elsewhere. profiler.cpp no longer references JitCodeCache directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h | 4 ++++ ddprof-lib/src/main/cpp/jvmSupport.h | 3 +++ ddprof-lib/src/main/cpp/jvmSupport.inline.h | 8 ++++++++ ddprof-lib/src/main/cpp/profiler.cpp | 9 +++++---- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h b/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h index 2fe809139f..e905d55c4a 100644 --- a/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h +++ b/ddprof-lib/src/main/cpp/hotspot/hotspotSupport.h @@ -46,6 +46,10 @@ class HotspotSupport { return JitCodeCache::isJitCode(p); } + static inline long long runtimeStubsMemoryUsage() { + return JitCodeCache::runtimeStubsMemoryUsage(); + } + // If should load all jmethodIDs static inline bool shouldPreloadJmethodIDs(Arguments& args) { CStack cstack = args._cstack; diff --git a/ddprof-lib/src/main/cpp/jvmSupport.h b/ddprof-lib/src/main/cpp/jvmSupport.h index 5ba33ae5ae..f3d664d2dc 100644 --- a/ddprof-lib/src/main/cpp/jvmSupport.h +++ b/ddprof-lib/src/main/cpp/jvmSupport.h @@ -55,6 +55,9 @@ class JVMSupport { static int walkJavaStack(StackWalkRequest& request); static inline bool canUnwind(const StackFrame& frame, const void*& pc); static inline bool isJitCode(const void* pc); + // Live heap usage of the JIT runtime-stubs code cache. HotSpot-only; 0 on + // other VMs (J9/Zing), which have no such cache. + static inline long long runtimeStubsMemoryUsage(); static void loadAllMethodIDsIfNeeded(jvmtiEnv *jvmti, JNIEnv *jni); static bool loadMethodIDsIfNeeded(jvmtiEnv *jvmti, JNIEnv *jni, jclass klass); diff --git a/ddprof-lib/src/main/cpp/jvmSupport.inline.h b/ddprof-lib/src/main/cpp/jvmSupport.inline.h index 6d1ca0639e..3be11d5902 100644 --- a/ddprof-lib/src/main/cpp/jvmSupport.inline.h +++ b/ddprof-lib/src/main/cpp/jvmSupport.inline.h @@ -26,6 +26,14 @@ bool JVMSupport::isJitCode(const void* pc) { } } +long long JVMSupport::runtimeStubsMemoryUsage() { + if (VM::isHotspot()) { + return HotspotSupport::runtimeStubsMemoryUsage(); + } else { + return 0; + } +} + // Resolve method pointer to jmethodID jmethodID JVMSupport::resolve(const void* method) { if (VM::isHotspot()) { diff --git a/ddprof-lib/src/main/cpp/profiler.cpp b/ddprof-lib/src/main/cpp/profiler.cpp index 031a870b7a..854d22beb3 100644 --- a/ddprof-lib/src/main/cpp/profiler.cpp +++ b/ddprof-lib/src/main/cpp/profiler.cpp @@ -21,10 +21,10 @@ #include "itimer.h" #include "hotspot/vmStructs.inline.h" #include "hotspot/hotspotSupport.h" -#include "hotspot/jitCodeCache.h" #include "j9/j9Support.h" #include "j9/j9WallClock.h" #include "jvmSupport.h" +#include "jvmSupport.inline.h" #include "jvmThread.h" #include "libraryPatcher.h" #include "objectSampler.h" @@ -1782,10 +1782,11 @@ Error Profiler::dump(const char *path, const int length) { Counters::set(CODECACHE_NATIVE_COUNT, native_libs.count()); Counters::set(CODECACHE_NATIVE_SIZE_BYTES, native_libs.memoryUsage()); // The runtime-stubs counter reflects the JIT runtime-stubs code cache, a - // separate cache from the native libraries (it previously duplicated - // native_libs.memoryUsage() by copy-paste). Read under its shared lock. + // separate cache from the native libraries. Routed through JVMSupport so + // the HotSpot-only implementation stays behind the VM abstraction (0 on + // J9/Zing). Read under its shared lock. Counters::set(CODECACHE_RUNTIME_STUBS_SIZE_BYTES, - JitCodeCache::runtimeStubsMemoryUsage()); + JVMSupport::runtimeStubsMemoryUsage()); Error err = Error::OK; // rotateDictsAndRun rotates the dictionaries, takes lockAll() around the