Skip to content

Commit e705df1

Browse files
Added support for taking thread dumps for IBM8 Java.
1 parent af8b844 commit e705df1

3 files changed

Lines changed: 65 additions & 17 deletions

File tree

.gitlab-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ variables:
3131
GRADLE_PLUGIN_PROXY: "https://depot-read-api-java.us1.ddbuild.io/magicmirror/magicmirror/@current/"
3232
BUILDER_IMAGE_VERSION_PREFIX: "v26.01-" # use either an empty string (e.g. "") for latest images or a version followed by a hyphen (e.g. "v25.05-")
3333
REPO_NOTIFICATION_CHANNEL: "#apm-java-escalations"
34-
DEFAULT_TEST_JVMS: /^(8|11|17|21|25|stable)$/ # the latest "stable" version is 26
34+
DEFAULT_TEST_JVMS: /^(8|ibm8)$/ # the latest "stable" version is 26
3535
PROFILE_TESTS:
3636
description: "Enable profiling of tests"
3737
value: "false"

buildSrc/src/main/kotlin/datadog/gradle/plugin/dump/DumpHangedTestPlugin.kt

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,30 +123,37 @@ class DumpHangedTestPlugin : Plugin<Project> {
123123
fun file(name: String, ext: String = "log") =
124124
File(dumpsDir, "$name-${System.currentTimeMillis()}.$ext")
125125

126-
// For simplicity, use `0` as the PID, which collects all thread dumps across JVMs.
127-
val allThreadsFile = file("all-thread-dumps")
128-
runCmd(Redirect.to(allThreadsFile), "jcmd", "0", "Thread.print", "-l")
129-
130126
// Collect all JVMs pids.
131127
val allJavaProcessesFile = file("all-java-processes")
132128
runCmd(Redirect.to(allJavaProcessesFile), "jcmd", "-l")
133129

134-
// Collect pids for 'Gradle Test Executor'.
135-
val pids = allJavaProcessesFile.readLines()
136-
.filter { it.contains("Gradle Test Executor") }
137-
.map { it.substringBefore(' ') }
130+
// On IBM JDK javacore can be collected by signaling the matching `Gradle Test Executor` process with `kill -3`.
131+
// It will be writen into `/tmp/javacore.YYYYMMDD.HHMMSS.PID.SEQ.txt
132+
if (isIbm8Run(allJavaProcessesFile)) {
133+
val allProcessesFile = file("all-processes")
134+
runCmd(Redirect.to(allProcessesFile), "ps", "-ef")
135+
extractPidsIbm8(allProcessesFile).forEach { ibm8Pid ->
136+
runCmd(Redirect.INHERIT, "kill", "-3", ibm8Pid)
137+
}
138+
} else {
139+
val pids = extractPids(allJavaProcessesFile)
138140

139-
pids.forEach { pid ->
140-
// Collect heap dump by pid.
141-
val heapDumpPath = file("${pid}-heap-dump", "hprof").absolutePath
142-
runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath)
141+
pids.forEach { pid ->
142+
// Collect heap dump by pid.
143+
val heapDumpPath = file("${pid}-heap-dump", "hprof").absolutePath
144+
runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath)
143145

144-
// Collect thread dump by pid.
145-
val threadDumpFile = file("${pid}-thread-dump")
146-
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
146+
// Collect thread dump by pid.
147+
val threadDumpFile = file("${pid}-thread-dump")
148+
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
149+
}
150+
151+
// Just in case collect all thread dumps by using special PID `0`.
152+
val allThreadsFile = file("all-thread-dumps")
153+
runCmd(Redirect.to(allThreadsFile), "jcmd", "0", "Thread.print", "-l")
147154
}
148155
} catch (e: Throwable) {
149-
t.logger.warn("Taking dumps failed with error: ${e.message}, for ${t.path}")
156+
t.logger.warn("Taking dumps failed with error: ${e.message ?: e.javaClass.name}, for ${t.path}")
150157
}
151158
}
152159

@@ -175,4 +182,26 @@ class DumpHangedTestPlugin : Plugin<Project> {
175182
throw IOException("Process failed: ${args.joinToString(" ")}, exit code: $exitCode")
176183
}
177184
}
185+
186+
private fun isIbm8Run(file: File): Boolean =
187+
file.readLines().any { it.contains("-PtestJvm=ibm8") }
188+
189+
private fun extractPids(file: File): List<String> =
190+
file.readLines()
191+
.filter { it.contains("Gradle Test Executor") }
192+
.map { it.substringBefore(' ') }
193+
194+
private val ibmMarkers: List<String> = listOf("ibm", "openj9", "semeru")
195+
196+
private fun extractPidsIbm8(file: File): List<String> =
197+
file.useLines { lines ->
198+
lines.filter { it.contains("Gradle Test Executor") }
199+
.filter { line -> ibmMarkers.any { marker -> line.contains(marker, ignoreCase = true) } }
200+
.mapNotNull(::extractPid)
201+
.toList()
202+
}
203+
204+
// ps -ef format starts with: UID PID PPID ...
205+
private fun extractPid(line: String): String? =
206+
line.trim().split(Regex("\\s+")).getOrNull(1)
178207
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package datadog.smoketest;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import java.util.Random;
6+
import org.junit.jupiter.api.Test;
7+
8+
public class IbmDumpTest {
9+
private static final Random rnd = new Random();
10+
11+
@Test
12+
void testIbmDump() throws InterruptedException {
13+
// Emulate hanged process for 21 minute.
14+
Thread.sleep(1_000 * 60 * 21);
15+
16+
int a = rnd.nextInt(10) + 10;
17+
assertTrue(a > 1);
18+
}
19+
}

0 commit comments

Comments
 (0)