Skip to content

Commit d25685a

Browse files
Added support to collect dumps for child processes (#10665)
Refactored dumping hanged tests by collecting child processes too. Reverted test code. Merge branch 'master' into alexeyk/collect-dumps-for-child-processes Fixed review comments. One more run of VT Reverted test code. Co-authored-by: alexey.kuznetsov <alexey.kuznetsov@datadoghq.com>
1 parent a350b02 commit d25685a

1 file changed

Lines changed: 33 additions & 47 deletions

File tree

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

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledExecutorService
2020
import java.util.concurrent.ScheduledFuture
2121
import java.util.concurrent.TimeUnit
2222
import javax.inject.Inject
23+
import kotlin.jvm.optionals.getOrElse
2324

2425
/**
2526
* Plugin to collect thread and heap dumps for hanged tests.
@@ -120,43 +121,27 @@ class DumpHangedTestPlugin : Plugin<Project> {
120121

121122
dumpsDir.mkdirs()
122123

123-
fun file(name: String, ext: String = "log") =
124-
File(dumpsDir, "$name-${System.currentTimeMillis()}.$ext")
124+
ProcessHandle.current().children()
125+
.filter { it.info().commandLine().getOrElse { "" }.contains("Gradle Test Executor") }
126+
.forEach { process ->
127+
collectDump(dumpsDir, process)
125128

126-
// Collect all JVMs pids.
127-
val allJavaProcessesFile = file("all-java-processes")
128-
runCmd(Redirect.to(allJavaProcessesFile), "jcmd", "-l")
129-
130-
// On IBM JDK thread dump 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 (isIbm8(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)
140-
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)
145-
146-
// Collect thread dump by pid.
147-
val threadDumpFile = file("${pid}-thread-dump")
148-
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
129+
process.children().forEach { child ->
130+
collectDump(dumpsDir, child)
131+
}
149132
}
150133

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")
154-
}
134+
// Just in case collect all thread dumps by using special PID `0`.
135+
val allThreadsFile = file(dumpsDir, "all-thread-dumps")
136+
runCmd(Redirect.to(allThreadsFile), "jcmd", "0", "Thread.print", "-l")
155137
} catch (e: Throwable) {
156138
t.logger.warn("Taking dumps failed with error: ${e.message ?: e.javaClass.name}, for ${t.path}")
157139
}
158140
}
159141

142+
private fun file(baseDir: File, name: String, ext: String = "log") =
143+
File(baseDir, "$name-${System.currentTimeMillis()}.$ext")
144+
160145
private fun cleanup(t: Task) {
161146
val future = t.extra
162147
.takeIf { it.has(DUMP_FUTURE_KEY) }
@@ -183,23 +168,24 @@ class DumpHangedTestPlugin : Plugin<Project> {
183168
}
184169
}
185170

186-
private fun isIbm8(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 fun extractPidsIbm8(file: File): List<String> =
195-
file.readLines()
196-
.filter { it.contains("Gradle Test Executor") }
197-
.filter { it.contains("ibm", ignoreCase = true) }
198-
.mapNotNull(::extractPid)
199-
200-
private val whitespaceRegex = Regex("\\s+")
171+
private fun collectDump(
172+
baseDir: File,
173+
process: ProcessHandle
174+
) {
175+
val pid = process.pid().toString()
201176

202-
// ps -ef format produce output like: UID PID PPID ...
203-
private fun extractPid(line: String): String? =
204-
line.trimStart().split(whitespaceRegex, limit = 3).getOrNull(1)
177+
if (process.info().command().getOrElse { "" }.contains("/ibm8")) {
178+
// On IBM JDK thread dump can be collected by signaling process with `kill -3`.
179+
// It will be writen into `/tmp/javacore.YYYYMMDD.HHMMSS.PID.SEQ.txt
180+
runCmd(Redirect.INHERIT, "kill", "-3", pid)
181+
} else {
182+
// Collect heap dump by pid.
183+
val heapDumpPath = file(baseDir, "$pid-heap-dump", "hprof").absolutePath
184+
runCmd(Redirect.INHERIT, "jcmd", pid, "GC.heap_dump", heapDumpPath)
185+
186+
// Collect thread dump by pid.
187+
val threadDumpFile = file(baseDir, "$pid-thread-dump", "log")
188+
runCmd(Redirect.to(threadDumpFile), "jcmd", pid, "Thread.print", "-l")
189+
}
190+
}
205191
}

0 commit comments

Comments
 (0)