Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8ef576b
Add fjmethodid=lazy: resolve raw Method* frames via a class liveness …
rkennke Oct 15, 2026
581e2df
Tag raw Method* frames with a KlassRegistry epoch to reject reused Kl…
rkennke Oct 15, 2026
a3bab23
Locate Klass::_trace_id by probing array klasses
rkennke Oct 15, 2026
a9b6777
Tag raw Method* frames with the holder's JFR trace ID when calibrated
rkennke Oct 15, 2026
cd01bda
Mark each raw frame's tag kind and validate the trace-ID offset again…
rkennke Oct 15, 2026
f86c2d2
Harden lazy resolution against metadata reuse and redefinition
rkennke Oct 15, 2026
55a047a
Validate the trace-ID offset against jdk.ClassDefine instead of execu…
rkennke Oct 15, 2026
75e6870
Cache raw frame resolutions per dump
rkennke Oct 15, 2026
3f848c6
Let JVMTI validate redefinition arguments before the hooks inspect them
rkennke Oct 15, 2026
433e7f0
Stress-test lazy resolution against live class redefinition
rkennke Oct 15, 2026
fdbb8ca
Drop registry-epoch tags; lazy mode requires JFR trace IDs
rkennke Oct 15, 2026
8a5d5b8
Catch a malformed trace ID in LazyTraceIdJfrValidationTest's log parser
rkennke Oct 15, 2026
8201325
Add working plan for combining #864 and #867
rkennke Oct 16, 2026
ef10a2d
Resolve raw frames from VM metadata instead of allocating jmethodIDs
rkennke Oct 16, 2026
8340625
Update the combined plan: PR structure, phase 1 status, Linux hand-over
rkennke Oct 16, 2026
0c78fb1
Prototype: capture names of unloadable raw frames at GC start
rkennke Oct 16, 2026
6a6000d
Prototype: drain unloadable raw frames off-pause; measure on Linux
rkennke Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ddprof-lib/src/main/cpp/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,13 @@ Error Arguments::parse(const char *args) {
if (value != nullptr) {
if (strcmp(value, "false") == 0) {
_force_jmethodID = false;
_lazy_jmethodID = false;
} else if (strcmp(value, "true") == 0) {
_force_jmethodID = true;
_lazy_jmethodID = false;
} else if (strcmp(value, "lazy") == 0) {
_force_jmethodID = false;
_lazy_jmethodID = true;
} else {
msg = "Invalid jmethodID creation value";
}
Expand Down
4 changes: 3 additions & 1 deletion ddprof-lib/src/main/cpp/arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ class Arguments {
bool _nativesocket;
long _nativesocket_interval; // initial sampling period in nanoseconds; 0 = engine default
bool _force_jmethodID; // Load all jmethodIDs, true by default
bool _lazy_jmethodID; // fjmethodid=lazy: allocate jmethodIDs only for sampled classes, at dump time

Arguments(bool persistent = false)
: _buf(NULL),
Expand Down Expand Up @@ -324,7 +325,8 @@ class Arguments {
_jvmtistacks(false),
_nativesocket(false),
_nativesocket_interval(0),
_force_jmethodID(true) {}
_force_jmethodID(true),
_lazy_jmethodID(false) {}

~Arguments();

Expand Down
58 changes: 57 additions & 1 deletion ddprof-lib/src/main/cpp/counters.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,66 @@
X(METHOD_RESOLVE_FAULT_RECOVERED, "method_resolve_fault_recovered") \
/* Symbol length/body rejected during the same resolution: unreadable body, \
* empty (recycled slot), or over MAX_SYMBOL_LEN. A name that merely exceeds \
* the fixed inline buffers in hotspotSupport.cpp's ResolvedNames still \
* the fixed inline buffers in ResolvedMethod (hotspotSupport.h) still \
* resolves via its malloc fallback and does not land here. The frame \
* serializes as "unknown". */ \
X(METHOD_RESOLVE_SYMBOL_UNREADABLE, "method_resolve_symbol_unreadable") \
/* fjmethodid=lazy resolution outcomes. UNLOADED: the frame's class is no \
* longer registered or reachable. NOT_CURRENT: the class is alive but the \
* Method* is not among its current methods (freed or redefined). Both \
* serialize as "unknown". RESOLVED: raw frames whose names were read from \
* VM metadata, once per method and tag per dump. */ \
X(METHOD_RESOLVE_LAZY_UNLOADED, "method_resolve_lazy_unloaded") \
X(METHOD_RESOLVE_LAZY_NOT_CURRENT, "method_resolve_lazy_not_current") \
X(METHOD_RESOLVE_LAZY_RESOLVED, "method_resolve_lazy_resolved") \
/* STALE: the class now at the frame's holder address is a different load \
* (its trace ID differs); serializes as "unknown". \
* ADD_FAILED: registration failed, so the class was preloaded instead. \
* UNTAGGABLE: a Method* using address bits the raw-frame tag needs, or \
* an unreadable holder trace ID; the frame is stored as not walkable. */ \
X(METHOD_RESOLVE_LAZY_STALE, "method_resolve_lazy_stale") \
/* REDEFINED: raw frame of a class that has been redefined (its Method*s \
* may have been freed and reused); serializes as "unknown". */ \
X(METHOD_RESOLVE_LAZY_REDEFINED, "method_resolve_lazy_redefined") \
/* Registered classes marked by the redefinition hooks (once per class \
* per redefine/retransform call). */ \
X(KLASS_REGISTRY_REDEFINITIONS_MARKED, "klass_registry_redefinitions_marked") \
/* Registrations whose class trace ID no longer fits in a raw frame's \
* 25-bit tag. Nonzero means trace-ID tags of two classes can now collide: \
* a frame sampled from an unloaded class could then, if a newer class \
* also took over its Method* memory, resolve to that class's method. */ \
X(KLASS_TRACE_ID_BEYOND_TAG_RANGE, "klass_trace_id_beyond_tag_range") \
/* Raw Method* frame occurrences answered from Lookup's per-dump cache \
* instead of resolving them again. */ \
X(RAW_FRAME_RESOLVE_CACHE_HITS, "raw_frame_resolve_cache_hits") \
X(KLASS_REGISTRY_ADD_FAILED, "klass_registry_add_failed") \
/* PROTOTYPE UnloadCapture (DDPROF_CAPTURE_UNLOADING=1). */ \
X(UNLOAD_CAPTURE_PENDING_ADDED, "unload_capture_pending_added") \
X(UNLOAD_CAPTURE_PENDING_OVERFLOW, "unload_capture_pending_overflow") \
X(UNLOAD_CAPTURE_HOOK_CALLS, "unload_capture_hook_calls") \
X(UNLOAD_CAPTURE_HOOK_BUSY, "unload_capture_hook_busy") \
X(UNLOAD_CAPTURE_HOOK_NS, "unload_capture_hook_ns") \
X(UNLOAD_CAPTURE_HOOK_MAX_NS, "unload_capture_hook_max_ns") \
X(UNLOAD_CAPTURE_CAPTURED, "unload_capture_captured") \
X(UNLOAD_CAPTURE_REFUSED, "unload_capture_refused") \
X(UNLOAD_CAPTURE_CACHE_FULL, "unload_capture_cache_full") \
X(UNLOAD_CAPTURE_USED, "unload_capture_used") \
X(UNLOAD_CAPTURE_BG_PASSES, "unload_capture_bg_passes") \
X(UNLOAD_CAPTURE_BG_NS, "unload_capture_bg_ns") \
X(UNLOAD_CAPTURE_BG_CPU_NS, "unload_capture_bg_cpu_ns") \
X(UNLOAD_CAPTURE_PENDING_EVICTED, "unload_capture_pending_evicted") \
X(UNLOAD_CAPTURE_BG_MAX_NS, "unload_capture_bg_max_ns") \
X(UNLOAD_CAPTURE_BG_CAPTURED, "unload_capture_bg_captured") \
X(UNLOAD_CAPTURE_BG_REFUSED, "unload_capture_bg_refused") \
X(UNLOAD_CAPTURE_HOOK_DRAINED, "unload_capture_hook_drained") \
/* PROTOTYPE: lazy frames whose Method* could not even be read at dump \
* (freed metadata), not covered by the method_resolve_lazy_* counters. */ \
X(METHOD_RESOLVE_LAZY_UNREADABLE, "method_resolve_lazy_unreadable") \
X(WALKVM_RAW_FRAME_UNTAGGABLE, "walkvm_raw_frame_untaggable") \
/* Gauge, set at each fjmethodid=lazy start: the Klass::_trace_id offset \
* raw frames are tagged with, or -1 if it was not found (lazy mode then \
* falls back to fjmethodid=false). 0 if lazy mode was never requested. */ \
X(KLASS_TRACE_ID_OFFSET, "klass_trace_id_offset") \
/* Strict subset of SAMPLES_DROPPED_THREAD_LOCAL, not an independent count: \
* ThreadLocalDataPool::claim() increments this on capacity exhaustion, and \
* every acquireCurrent() caller that gets nullptr back -- for this or any \
Expand Down
Loading
Loading