Skip to content

Commit c17d0e8

Browse files
authored
Provide a safe default stackwalker for non-hotspot JVMs (#9930)
1 parent d422f6d commit c17d0e8

File tree

3 files changed

+151
-4
lines changed

3 files changed

+151
-4
lines changed

components/environment/src/main/java/datadog/environment/JavaVirtualMachine.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ public static boolean isOracleJDK8() {
9393
&& !runtime.name.contains("OpenJDK");
9494
}
9595

96+
public static boolean isHotspot() {
97+
String prop = SystemProperties.getOrDefault("java.vm.name", "");
98+
if (prop.isEmpty()) {
99+
return false;
100+
}
101+
return prop.contains("OpenJDK")
102+
|| prop.contains("HotSpot")
103+
|| prop.contains("GraalVM")
104+
|| prop.contains("Dynamic Code Evolution");
105+
}
106+
96107
public static boolean isJ9() {
97108
return SystemProperties.getOrDefault("java.vm.name", "").contains("J9");
98109
}

dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,17 @@ public static int getSafeMode() {
295295
}
296296

297297
public static String getCStack(ConfigProvider configProvider) {
298-
return getString(
299-
configProvider,
300-
PROFILING_DATADOG_PROFILER_CSTACK,
301-
PROFILING_DATADOG_PROFILER_CSTACK_DEFAULT);
298+
String cstack =
299+
getString(
300+
configProvider,
301+
PROFILING_DATADOG_PROFILER_CSTACK,
302+
PROFILING_DATADOG_PROFILER_CSTACK_DEFAULT);
303+
if (cstack.startsWith("vm") && !(JavaVirtualMachine.isHotspot())) {
304+
// can't use the VM stackwalking on non-hotspot VMs
305+
// fall-back to 'dwarf' unwinding
306+
cstack = "dwarf";
307+
}
308+
return cstack;
302309
}
303310

304311
public static boolean isEndpointTrackingEnabled() {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.datadog.profiling.ddprof;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import datadog.trace.api.config.ProfilingConfig;
6+
import datadog.trace.bootstrap.config.provider.ConfigProvider;
7+
import java.util.Properties;
8+
import java.util.stream.Stream;
9+
import org.junit.jupiter.api.AfterEach;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.params.ParameterizedTest;
12+
import org.junit.jupiter.params.provider.Arguments;
13+
import org.junit.jupiter.params.provider.MethodSource;
14+
15+
class DatadogProfilerConfigTest {
16+
private String originalVmName;
17+
18+
@BeforeEach
19+
void setUp() {
20+
originalVmName = System.getProperty("java.vm.name");
21+
}
22+
23+
@AfterEach
24+
void tearDown() {
25+
if (originalVmName != null) {
26+
System.setProperty("java.vm.name", originalVmName);
27+
} else {
28+
System.clearProperty("java.vm.name");
29+
}
30+
}
31+
32+
@ParameterizedTest
33+
@MethodSource("j9StackwalkerTestCases")
34+
void testGetCStackWithJ9(String configuredStackwalker, String expectedStackwalker) {
35+
System.setProperty("java.vm.name", "Eclipse OpenJ9 VM");
36+
37+
Properties props = new Properties();
38+
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK, configuredStackwalker);
39+
ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props);
40+
41+
String result = DatadogProfilerConfig.getCStack(configProvider);
42+
43+
assertEquals(
44+
expectedStackwalker,
45+
result,
46+
"J9 JVM with configured stackwalker '"
47+
+ configuredStackwalker
48+
+ "' should return '"
49+
+ expectedStackwalker
50+
+ "'");
51+
}
52+
53+
@ParameterizedTest
54+
@MethodSource("zingStackwalkerTestCases")
55+
void testGetCStackWithZing(String configuredStackwalker, String expectedStackwalker) {
56+
System.setProperty("java.vm.name", "Zing 64-Bit Tiered VM");
57+
58+
Properties props = new Properties();
59+
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK, configuredStackwalker);
60+
ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props);
61+
62+
String result = DatadogProfilerConfig.getCStack(configProvider);
63+
64+
assertEquals(
65+
expectedStackwalker,
66+
result,
67+
"Zing JVM with configured stackwalker '"
68+
+ configuredStackwalker
69+
+ "' should return '"
70+
+ expectedStackwalker
71+
+ "'");
72+
}
73+
74+
@ParameterizedTest
75+
@MethodSource("hotspotStackwalkerTestCases")
76+
void testGetCStackWithHotspot(String configuredStackwalker, String expectedStackwalker) {
77+
System.setProperty("java.vm.name", "Java HotSpot(TM) 64-Bit Server VM");
78+
79+
Properties props = new Properties();
80+
props.put(ProfilingConfig.PROFILING_DATADOG_PROFILER_CSTACK, configuredStackwalker);
81+
ConfigProvider configProvider = ConfigProvider.withPropertiesOverride(props);
82+
83+
String result = DatadogProfilerConfig.getCStack(configProvider);
84+
85+
assertEquals(
86+
expectedStackwalker,
87+
result,
88+
"HotSpot JVM with configured stackwalker '"
89+
+ configuredStackwalker
90+
+ "' should return '"
91+
+ expectedStackwalker
92+
+ "'");
93+
}
94+
95+
private static Stream<Arguments> j9StackwalkerTestCases() {
96+
return Stream.of(
97+
// Unsupported stackwalkers - should fall back to dwarf
98+
Arguments.of("vm", "dwarf"),
99+
Arguments.of("vmx", "dwarf"),
100+
// Supported stackwalkers - should pass through
101+
Arguments.of("dwarf", "dwarf"),
102+
Arguments.of("fp", "fp"),
103+
Arguments.of("lbr", "lbr"),
104+
Arguments.of("no", "no"));
105+
}
106+
107+
private static Stream<Arguments> zingStackwalkerTestCases() {
108+
return Stream.of(
109+
// Unsupported stackwalkers - should fall back to dwarf
110+
Arguments.of("vm", "dwarf"),
111+
Arguments.of("vmx", "dwarf"),
112+
// Supported stackwalkers - should pass through
113+
Arguments.of("dwarf", "dwarf"),
114+
Arguments.of("fp", "fp"),
115+
Arguments.of("lbr", "lbr"),
116+
Arguments.of("no", "no"));
117+
}
118+
119+
private static Stream<Arguments> hotspotStackwalkerTestCases() {
120+
return Stream.of(
121+
// All stackwalkers should pass through unchanged
122+
Arguments.of("vm", "vm"),
123+
Arguments.of("vmx", "vmx"),
124+
Arguments.of("dwarf", "dwarf"),
125+
Arguments.of("fp", "fp"),
126+
Arguments.of("lbr", "lbr"),
127+
Arguments.of("no", "no"));
128+
}
129+
}

0 commit comments

Comments
 (0)