diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java index 95f538a715c..f6a2e4251aa 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerFlareReporter.java @@ -352,6 +352,13 @@ private String getProfilerConfig() { ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER, ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER_DEFAULT), ProfilingConfig.PROFILING_DATADOG_PROFILER_WALL_CONTEXT_FILTER_DEFAULT); + appendConfig( + sb, + "DDProf Force Preload jmethodIDs", + configProvider.getBoolean( + ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID, + ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID_DEFAULT), + ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID_DEFAULT); sb.append("\n=== DDProf Allocation Profiling ===\n"); appendConfig( sb, diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java index 0005e8ea659..de23d38668b 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java @@ -1,5 +1,6 @@ package com.datadog.profiling.ddprof; +import static com.datadog.profiling.ddprof.DatadogProfilerConfig.forceJMethodID; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getAllocationInterval; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getCStack; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getContextAttributes; @@ -418,6 +419,12 @@ String cmdStartProfiling(Path file) throws IllegalStateException { if (omitLineNumbers(configProvider)) { cmd.append(",linenumbers=f"); } + + // Default is true + if (!forceJMethodID(configProvider)) { + cmd.append(",fjmethodid=false"); + } + if (profilingModes.contains(CPU)) { // cpu profiling is enabled. String schedulingEvent = getSchedulingEvent(configProvider); diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java index 60c0d5c2e60..f400a06f901 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java @@ -15,6 +15,8 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CPU_INTERVAL_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LIBPATH; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LINE_NUMBERS; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_LINE_NUMBERS_DEFAULT; @@ -439,6 +441,13 @@ public static long getLong(ConfigProvider configProvider, String key) { return configProvider.getLong(key, configProvider.getLong(normalizeKey(key), -1)); } + public static boolean forceJMethodID(ConfigProvider configProvider) { + return getBoolean( + configProvider, + PROFILING_DATADOG_PROFILER_FORCE_JMETHODID, + PROFILING_DATADOG_PROFILER_FORCE_JMETHODID_DEFAULT); + } + private static String normalizeKey(String key) { return key.replace(".ddprof.", ".async."); } diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java index 2be7d129e68..ed1a7d0d33a 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/test/java/com/datadog/profiling/ddprof/DatadogProfilerTest.java @@ -108,6 +108,22 @@ private static Stream profilingModes() { Arguments.of((x & 0x1000) != 0, (x & 0x100) != 0, (x & 0x10) != 0, (x & 0x1) != 0)); } + @Test + void testStartCmdForceJMethodIDDisabled() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + Properties props = new Properties(); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_FORCE_JMETHODID, "false"); + DatadogProfiler profiler = + DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props)); + + Path targetFile = Paths.get("/tmp/target.jfr"); + String cmd = profiler.cmdStartProfiling(targetFile); + + assertTrue(cmd.contains(",fjmethodid=false"), cmd); + } + @ParameterizedTest @MethodSource("wallContextFilterModes") void testWallContextFilter(boolean tracingEnabled, boolean contextFilterEnabled) diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java index 4076f4aae30..61dc3bf81a2 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java @@ -34,6 +34,12 @@ public final class ProfilingConfig { public static final String PROFILING_UPLOAD_TIMEOUT = "profiling.upload.timeout"; public static final int PROFILING_UPLOAD_TIMEOUT_DEFAULT = 30; + // When set to false, ddprof skips preloading jmethodIDs for eligible system classes to reduce + // native memory usage. Default is true to preserve current behavior (force preloading). + public static final String PROFILING_DATADOG_PROFILER_FORCE_JMETHODID = + "profiling.experimental.ddprof.force_jmethodid"; + public static final boolean PROFILING_DATADOG_PROFILER_FORCE_JMETHODID_DEFAULT = true; + /** * @deprecated Use {@link #PROFILING_DEBUG_UPLOAD_COMPRESSION} instead. This will be removed in a * future release. diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 2410bcd59be..9c9f3b8fc51 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -3121,6 +3121,14 @@ "aliases": [] } ], + "DD_PROFILING_EXPERIMENTAL_ASYNC_FORCE_JMETHODID": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_EXPERIMENTAL_ASYNC_SCHEDULING_EVENT": [ { "version": "A", @@ -3145,6 +3153,14 @@ "aliases": [] } ], + "DD_PROFILING_EXPERIMENTAL_DDPROF_FORCE_JMETHODID": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_EXPERIMENTAL_DDPROF_SCHEDULING_EVENT": [ { "version": "A",