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 68ee109a137..0d68e2e0c3f 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 @@ -7,6 +7,7 @@ import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getCpuInterval; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getLiveHeapSamplePercent; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getLogLevel; +import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getNativeMemoryInterval; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSafeMode; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSchedulingEvent; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.getSchedulingEventInterval; @@ -18,6 +19,7 @@ import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isCpuProfilerEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isLiveHeapSizeTrackingEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isMemoryLeakProfilingEnabled; +import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isNativeMemoryProfilingEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isResourceNameContextAttributeEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isSpanNameContextAttributeEnabled; import static com.datadog.profiling.ddprof.DatadogProfilerConfig.isTrackingGenerations; @@ -26,6 +28,7 @@ import static com.datadog.profiling.utils.ProfilingMode.ALLOCATION; import static com.datadog.profiling.utils.ProfilingMode.CPU; import static com.datadog.profiling.utils.ProfilingMode.MEMLEAK; +import static com.datadog.profiling.utils.ProfilingMode.NATIVEMEM; import static com.datadog.profiling.utils.ProfilingMode.WALL; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DETAILED_DEBUG_LOGGING; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DETAILED_DEBUG_LOGGING_DEFAULT; @@ -237,6 +240,9 @@ private DatadogProfiler(ConfigProvider configProvider) { if (isWallClockProfilerEnabled(configProvider)) { profilingModes.add(WALL); } + if (isNativeMemoryProfilingEnabled(configProvider)) { + profilingModes.add(NATIVEMEM); + } Set contextAttributes = getContextAttributes(configProvider); this.orderedContextAttributes = getOrderedContextAttributes(contextAttributes, configProvider); this.contextSetter = new ContextSetter(profiler, orderedContextAttributes); @@ -459,6 +465,10 @@ String cmdStartProfiling(Path file) throws IllegalStateException { .append(String.format("%.2f", getLiveHeapSamplePercent(configProvider) / 100.0d)); } } + if (profilingModes.contains(NATIVEMEM)) { + // native memory (malloc) profiling is enabled + cmd.append(",nativemem=").append(getNativeMemoryInterval(configProvider)); + } String cmdString = cmd.toString(); log.debug("Datadog profiler command line: {}", cmdString); return cmdString; 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 8582e27c853..c95db897fb3 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 @@ -33,6 +33,10 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_CAPACITY; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_ENABLED; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_MEMLEAK_INTERVAL; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED_DEFAULT; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL; +import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SAFEMODE_DEFAULT; import static datadog.trace.api.config.ProfilingConfig.PROFILING_DATADOG_PROFILER_SCHEDULING_EVENT; @@ -290,6 +294,30 @@ public static int getMemleakCapacity() { return getMemleakCapacity(ConfigProvider.getInstance()); } + public static boolean isNativeMemoryProfilingEnabled(ConfigProvider configProvider) { + // nativemem never shipped under the legacy '.async.' naming, so it has no async-translated + // form to fall back to — call the provider directly instead of the ddprof->async helper. + return configProvider.getBoolean( + PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED, + PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED_DEFAULT); + } + + public static boolean isNativeMemoryProfilingEnabled() { + return isNativeMemoryProfilingEnabled(ConfigProvider.getInstance()); + } + + public static int getNativeMemoryInterval(ConfigProvider configProvider) { + // nativemem never shipped under the legacy '.async.' naming, so it has no async-translated + // form to fall back to — call the provider directly instead of the ddprof->async helper. + return configProvider.getInteger( + PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL, + PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL_DEFAULT); + } + + public static int getNativeMemoryInterval() { + return getNativeMemoryInterval(ConfigProvider.getInstance()); + } + public static int getStackDepth(ConfigProvider configProvider) { return getInteger( configProvider, 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 0ef487f3630..008b70b1e66 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 @@ -118,11 +118,38 @@ void testStartCmdEnableJMethodIDOptim() throws Exception { DatadogProfiler profiler = DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props)); - Path dir = Paths.get("/tmp"); - Path targetFile = Files.createTempFile(dir, "target_", ".jfr"); - String cmd = profiler.cmdStartProfiling(targetFile); + assertTrue(startCmd(profiler).contains(",fjmethodid=false")); + } + + @Test + void testStartCmdNativeMemDisabledByDefault() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + DatadogProfiler profiler = DatadogProfiler.newInstance(ConfigProvider.getInstance()); + assertFalse(profiler.enabledModes().contains(ProfilingMode.NATIVEMEM)); + + assertFalse(startCmd(profiler).contains(",nativemem=")); + } + + @Test + void testStartCmdNativeMemEnabled() throws Exception { + assertDoesNotThrow( + () -> DdprofLibraryLoader.jvmAccess().getReasonNotLoaded(), "Profiler not available"); + + Properties props = new Properties(); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED, "true"); + props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL, "131072"); + DatadogProfiler profiler = + DatadogProfiler.newInstance(ConfigProvider.withPropertiesOverride(props)); + assertTrue(profiler.enabledModes().contains(ProfilingMode.NATIVEMEM)); + + assertTrue(startCmd(profiler).contains(",nativemem=131072")); + } - assertTrue(cmd.contains(",fjmethodid=false"), cmd); + private static String startCmd(DatadogProfiler profiler) throws Exception { + Path targetFile = Files.createTempFile(Paths.get("/tmp"), "target_", ".jfr"); + return profiler.cmdStartProfiling(targetFile); } @ParameterizedTest diff --git a/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java b/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java index 9697edd74a1..e313c064445 100644 --- a/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java +++ b/dd-java-agent/agent-profiling/profiling-utils/src/main/java/com/datadog/profiling/utils/ProfilingMode.java @@ -7,7 +7,8 @@ public enum ProfilingMode { CPU(1 << 0), WALL(1 << 1), ALLOCATION(1 << 2), - MEMLEAK(1 << 3); + MEMLEAK(1 << 3), + NATIVEMEM(1 << 4); public final int bitmask; 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 6d60ab686a7..bf5f7a552e9 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 @@ -180,6 +180,13 @@ public final class ProfilingConfig { public static final int PROFILING_DATADOG_PROFILER_LIVEHEAP_SAMPLE_PERCENT_DEFAULT = 50; // default to 10% of allocation samples + public static final String PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED = + "profiling.experimental.ddprof.nativemem.enabled"; + public static final boolean PROFILING_DATADOG_PROFILER_NATIVEMEM_ENABLED_DEFAULT = false; + public static final String PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL = + "profiling.experimental.ddprof.nativemem.interval"; + public static final int PROFILING_DATADOG_PROFILER_NATIVEMEM_INTERVAL_DEFAULT = 512 * 1024; + public static final String PROFILING_ENDPOINT_COLLECTION_ENABLED = "profiling.endpoint.collection.enabled"; public static final boolean PROFILING_ENDPOINT_COLLECTION_ENABLED_DEFAULT = true; diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index af0caea701f..aaad660aae9 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -3233,6 +3233,22 @@ "aliases": [] } ], + "DD_PROFILING_EXPERIMENTAL_DDPROF_NATIVEMEM_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "false", + "aliases": [] + } + ], + "DD_PROFILING_EXPERIMENTAL_DDPROF_NATIVEMEM_INTERVAL": [ + { + "version": "A", + "type": "int", + "default": "524288", + "aliases": [] + } + ], "DD_PROFILING_EXPERIMENTAL_DDPROF_SCHEDULING_EVENT": [ { "version": "A",