Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ jdk.ExecutionSample#enabled=true
# Note: we use 9 ms sampling rate in a hope to avoid 'lockstep' sampling.
# Ideally JFR should provide random jitter in sampling to ensure this doesn't happen.
jdk.ExecutionSample#period=9 ms
# In JDK 25+ we want to use CPUTimeSample instead
# Disabling the ExecutionSample will be done in OpenJDKController impl
jdk.CPUTimeSample#enabled=true
jdk.CPUTimeSample#throttle=9ms
jdk.CPUTimeSamplesLost#enabled=true
# ---
jdk.NativeMethodSample#enabled=false
jdk.SafepointBegin#enabled=true
jdk.SafepointBegin#threshold=0 ms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.datadog.profiling.controller.jfr.JfpUtils;
import com.datadog.profiling.controller.openjdk.events.AvailableProcessorCoresEvent;
import datadog.environment.JavaVirtualMachine;
import datadog.environment.OperatingSystem;
import datadog.trace.api.Config;
import datadog.trace.api.config.ProfilingConfig;
import datadog.trace.bootstrap.config.provider.ConfigProvider;
Expand Down Expand Up @@ -62,6 +63,8 @@ public final class OpenJdkController implements Controller {
private static final String EXPLICITLY_ENABLED = "explicitly enabled by user";
private static final String EXPENSIVE_ON_CURRENT_JVM =
"expensive on this version of the JVM (" + JavaVirtualMachine.getRuntimeVersion() + ")";
private static final String CPUTIME_SAMPLE_JDK25 = "Switching to CPUTimeSample on JDK 25+";

static final Duration RECORDING_MAX_AGE = Duration.ofMinutes(5);

private final ConfigProvider configProvider;
Expand Down Expand Up @@ -164,6 +167,13 @@ public OpenJdkController(final ConfigProvider configProvider)
throw new ConfigurationException(e);
}

// switch to CPUTimeSample event on JDK 25 and Linux
if (JavaVirtualMachine.isJavaVersionAtLeast(25) && OperatingSystem.isLinux()) {
disableEvent(recordingSettings, "jdk.ExecutionSample", CPUTIME_SAMPLE_JDK25);
enableEvent(recordingSettings, "jdk.CPUTimeSample", CPUTIME_SAMPLE_JDK25);
enableEvent(recordingSettings, "jdk.CPUTimeSamplesLost", CPUTIME_SAMPLE_JDK25);
}

// Toggle settings from override args

String disabledEventsArgs = configProvider.getString(ProfilingConfig.PROFILING_DISABLED_EVENTS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Multimap;
import datadog.environment.JavaVirtualMachine;
import datadog.environment.OperatingSystem;
import datadog.environment.SystemProperties;
import datadog.trace.api.Pair;
import datadog.trace.api.config.ProfilingConfig;
import delight.fileupload.FileUpload;
Expand Down Expand Up @@ -49,8 +51,9 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.openjdk.jmc.common.IMCStackTrace;
import org.openjdk.jmc.common.item.Aggregators;
import org.openjdk.jmc.common.item.IAttribute;
Expand All @@ -68,12 +71,8 @@
import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spock.util.environment.OperatingSystem;

@DisabledIfSystemProperty(named = "java.vm.name", matches = ".*J9.*")
@DisabledIf(
value = "isJavaVersionAtLeast24",
disabledReason = "Failing on Java 24. Skip until we have a fix.")
class JFRBasedProfilingIntegrationTest {
private static final Logger log = LoggerFactory.getLogger(JFRBasedProfilingIntegrationTest.class);
private static final Duration ONE_NANO = Duration.ofNanos(1);
Expand Down Expand Up @@ -155,47 +154,57 @@ void teardown() throws Exception {
}
}

@Test
@ParameterizedTest
@ValueSource(strings = {"jfr", "ddprof"})
@DisplayName("Test continuous recording - no jmx delay, default compression")
public void testContinuousRecording_no_jmx_delay(final TestInfo testInfo) throws Exception {
public void testContinuousRecording_no_jmx_delay(String profiler, final TestInfo testInfo)
throws Exception {
Assumptions.assumeTrue("jfr".equals(profiler) || OperatingSystem.isLinux());
testWithRetry(
() ->
testContinuousRecording(
0, ENDPOINT_COLLECTION_ENABLED, OperatingSystem.getCurrent().isLinux(), false),
0, ENDPOINT_COLLECTION_ENABLED, "ddprof".equals(profiler), false),
testInfo,
5);
}

@Test
@ParameterizedTest
@ValueSource(strings = {"jfr", "ddprof"})
@DisplayName("Test continuous recording - no jmx delay, zstd compression")
public void testContinuousRecording_no_jmx_delay_jmethodid_cache(final TestInfo testInfo)
public void testContinuousRecording_no_jmx_delay_zstd(String profiler, final TestInfo testInfo)
throws Exception {
Assumptions.assumeTrue("jfr".equals(profiler) || OperatingSystem.isLinux());
testWithRetry(
() ->
testContinuousRecording(
0, ENDPOINT_COLLECTION_ENABLED, OperatingSystem.getCurrent().isLinux(), true),
0, ENDPOINT_COLLECTION_ENABLED, "ddprof".equals(profiler), true),
testInfo,
5);
}

@Test
@ParameterizedTest
@ValueSource(strings = {"jfr", "ddprof"})
@DisplayName("Test continuous recording - 1 sec jmx delay, default compression")
public void testContinuousRecording(final TestInfo testInfo) throws Exception {
public void testContinuousRecording(String profiler, final TestInfo testInfo) throws Exception {
Assumptions.assumeTrue("jfr".equals(profiler) || OperatingSystem.isLinux());
testWithRetry(
() ->
testContinuousRecording(
1, ENDPOINT_COLLECTION_ENABLED, OperatingSystem.getCurrent().isLinux(), false),
1, ENDPOINT_COLLECTION_ENABLED, "ddprof".equals(profiler), false),
testInfo,
5);
}

@Test
@ParameterizedTest
@ValueSource(strings = {"jfr", "ddprof"})
@DisplayName("Test continuous recording - 1 sec jmx delay, zstd compression")
public void testContinuousRecording_zstd(final TestInfo testInfo) throws Exception {
public void testContinuousRecording_zstd(String profiler, final TestInfo testInfo)
throws Exception {
Assumptions.assumeTrue("jfr".equals(profiler) || OperatingSystem.isLinux());
testWithRetry(
() ->
testContinuousRecording(
1, ENDPOINT_COLLECTION_ENABLED, OperatingSystem.getCurrent().isLinux(), true),
1, ENDPOINT_COLLECTION_ENABLED, "ddprof".equals(profiler), true),
testInfo,
5);
}
Expand Down Expand Up @@ -368,6 +377,15 @@ private static void verifyJdkEventsDisabled(IItemCollection events) {
assertFalse(events.apply(ItemFilters.type("jdk.ThreadPark")).hasItems());
}

private static void verifyJdkEvents(IItemCollection events) {
String cpuSampleType = "jdk.ExecutionSample";
if (JavaVirtualMachine.isJavaVersionAtLeast(25) && OperatingSystem.isLinux()) {
// for Java 25+ we are defaulting to 'jdk.CPUTimeSample' on Linux
cpuSampleType = "jdk.CPUTimeSample";
}
assertTrue(events.apply(ItemFilters.type(cpuSampleType)).hasItems());
}

private static void verifyDatadogEventsNotCorrupt(IItemCollection events) {
// if we emit any of these events during the test they mustn't have corrupted context
for (String eventName :
Expand Down Expand Up @@ -621,6 +639,7 @@ private void assertRecordingEvents(
// TODO ddprof (async) profiler seems to be having some issues with stack depth limit and
// native frames
} else {
verifyJdkEvents(events);
// make sure the stack depth limit is respected
for (IItemIterable lane : events.apply(ItemFilters.type(JdkTypeIDs.EXECUTION_SAMPLE))) {
IMemberAccessor<IMCStackTrace, IItem> stackTraceAccessor =
Expand Down Expand Up @@ -838,8 +857,7 @@ private static ProcessBuilder createProcessBuilder(
}

private static String javaPath() {
final String separator = System.getProperty("file.separator");
return System.getProperty("java.home") + separator + "bin" + separator + "java";
return Paths.get(SystemProperties.getOrDefault("java.home", ""), "bin", "java").toString();
}

private static String buildDirectory() {
Expand Down