Summary
jfr2pprof's frame.format mapping config (e.g. "{class}.{method}") is loaded by MappingLoader into a FrameFormat, but the conversion path never renders through it. The result: every pprof Function.Name is just the bare class name, and the method name is silently dropped into Function.SystemName, which google/pprof (and most pprof consumers) don't use for symbolization/folded-stack display.
Root cause
PprofBuilder.internStack():
FrameExtractor.FrameData data = FrameExtractor.extractData(frameElement);
if (data == null) continue;
long fnId =
internFunction(
data.className(), data.methodName(), data.lineNumber() < 0 ? 0 : data.lineNumber());
calls internFunction(className, methodName, ...) directly with the raw extracted class/method strings. internFunction writes className into Function.Name and methodName into Function.SystemName:
public long internFunction(String className, String methodName, long startLine) {
...
functionEntries.add(
new long[] {
id, internString(className), internString(methodName), internString(""), startLine
});
...
}
FrameExtractor.extract(Object frame, FrameFormat fmt) — the method that actually calls fmt.render(...) to combine class+method per the configured format — exists but is never called anywhere in jfr2pprof's main source. It's dead code. The FrameFormat fmt parameter threaded into internStack(Object frames, FrameFormat fmt) is effectively unused.
Impact
Every frame from the same class collapses into a single pprof Function/node, regardless of which method it's actually in. Verified with pprof -raw on a real conversion:
30: 0x0 M=1 Workload$CpuBurner :29:0 s=29(spin)
31: 0x0 M=1 Workload$CpuBurner :22:0 s=22(run)
Both Workload$CpuBurner.run and Workload$CpuBurner.spin render as the same Function.Name (Workload$CpuBurner); the method landed in SystemName (s=...) instead. go tool pprof -top then folds both into one node.
This breaks any expected_profile.json-style assertion (used throughout DataDog/prof-correctness, and presumably any other consumer) that matches a folded stack string like ClassA.methodA;ClassB.methodB — the method-qualified regex can never match, for any mapping config, on any platform. It is not specific to a particular JFR event schema.
Suggested fix
In PprofBuilder.internStack, render the frame through the configured FrameFormat before interning it as the function's display name, e.g.:
String renderedName = fmt.render(data.className(), data.methodName(), data.lineNumber());
long fnId = internFunction(renderedName, data.methodName(), data.lineNumber() < 0 ? 0 : data.lineNumber());
(keeping raw methodName in SystemName as before). Discovered while validating datadog.yaml/the java-profiler prof-correctness scenario (PROF-15289/PROF-15290) — the mapping config and event data were confirmed correct; this is purely a converter-side gap.
Summary
jfr2pprof'sframe.formatmapping config (e.g."{class}.{method}") is loaded byMappingLoaderinto aFrameFormat, but the conversion path never renders through it. The result: every pprofFunction.Nameis just the bare class name, and the method name is silently dropped intoFunction.SystemName, whichgoogle/pprof(and most pprof consumers) don't use for symbolization/folded-stack display.Root cause
PprofBuilder.internStack():calls
internFunction(className, methodName, ...)directly with the raw extracted class/method strings.internFunctionwritesclassNameintoFunction.NameandmethodNameintoFunction.SystemName:FrameExtractor.extract(Object frame, FrameFormat fmt)— the method that actually callsfmt.render(...)to combine class+method per the configured format — exists but is never called anywhere injfr2pprof's main source. It's dead code. TheFrameFormat fmtparameter threaded intointernStack(Object frames, FrameFormat fmt)is effectively unused.Impact
Every frame from the same class collapses into a single pprof
Function/node, regardless of which method it's actually in. Verified withpprof -rawon a real conversion:Both
Workload$CpuBurner.runandWorkload$CpuBurner.spinrender as the sameFunction.Name(Workload$CpuBurner); the method landed inSystemName(s=...) instead.go tool pprof -topthen folds both into one node.This breaks any
expected_profile.json-style assertion (used throughoutDataDog/prof-correctness, and presumably any other consumer) that matches a folded stack string likeClassA.methodA;ClassB.methodB— the method-qualified regex can never match, for any mapping config, on any platform. It is not specific to a particular JFR event schema.Suggested fix
In
PprofBuilder.internStack, render the frame through the configuredFrameFormatbefore interning it as the function's display name, e.g.:(keeping raw
methodNameinSystemNameas before). Discovered while validatingdatadog.yaml/the java-profiler prof-correctness scenario (PROF-15289/PROF-15290) — the mapping config and event data were confirmed correct; this is purely a converter-side gap.