@@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledExecutorService
2020import java.util.concurrent.ScheduledFuture
2121import java.util.concurrent.TimeUnit
2222import 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