mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
Implement method to get relevant threads from freeze
GitOrigin-RevId: 5ece9d8606b7677409ea66e55d28b68fa4893492
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5077d2c7a2
commit
0e565a1b23
13
platform/diagnostic/freezeAnalyzer/api-dump-experimental.txt
Normal file
13
platform/diagnostic/freezeAnalyzer/api-dump-experimental.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
f:com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- <init>(java.lang.String,java.util.List,java.lang.String):V
|
||||
- b:<init>(java.lang.String,java.util.List,java.lang.String,I,kotlin.jvm.internal.DefaultConstructorMarker):V
|
||||
- f:component1():java.lang.String
|
||||
- f:component2():java.util.List
|
||||
- f:component3():java.lang.String
|
||||
- f:copy(java.lang.String,java.util.List,java.lang.String):com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- bs:copy$default(com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult,java.lang.String,java.util.List,java.lang.String,I,java.lang.Object):com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- equals(java.lang.Object):Z
|
||||
- f:getAdditionalMessage():java.lang.String
|
||||
- f:getMessage():java.lang.String
|
||||
- f:getThreads():java.util.List
|
||||
- hashCode():I
|
||||
@@ -1,10 +0,0 @@
|
||||
f:com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- <init>(java.lang.String,java.lang.String):V
|
||||
- f:component1():java.lang.String
|
||||
- f:component2():java.lang.String
|
||||
- f:copy(java.lang.String,java.lang.String):com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- bs:copy$default(com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult,java.lang.String,java.lang.String,I,java.lang.Object):com.intellij.platform.diagnostic.freezeAnalyzer.FreezeAnalysisResult
|
||||
- equals(java.lang.Object):Z
|
||||
- f:getMessage():java.lang.String
|
||||
- f:getStackTrace():java.lang.String
|
||||
- hashCode():I
|
||||
@@ -14,5 +14,6 @@
|
||||
<orderEntry type="library" scope="TEST" name="kotlin-test-assertions-core-jvm" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
|
||||
<orderEntry type="library" name="jetbrains-annotations" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.base" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -1,13 +1,17 @@
|
||||
package com.intellij.platform.diagnostic.freezeAnalyzer
|
||||
|
||||
import com.intellij.diagnostic.ThreadDump
|
||||
import com.intellij.threadDumpParser.ThreadDumpParser
|
||||
import com.intellij.threadDumpParser.ThreadState
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.text.contains
|
||||
import kotlin.text.lineSequence
|
||||
|
||||
@ApiStatus.Experimental
|
||||
object FreezeAnalyzer {
|
||||
|
||||
fun getRelevantThreads(threadDump: ThreadDump): List<ThreadState> {
|
||||
return analyzeFreeze(threadDump.rawDump, null)?.threads ?: emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze freeze based on the IJ Platform knowledge and try to infer the relevant message.
|
||||
* If analysis fails, it returns `null`.
|
||||
@@ -20,9 +24,9 @@ object FreezeAnalyzer {
|
||||
|
||||
private fun analyzeEDThread(edt: ThreadState, threadDumpParsed: List<ThreadState>, testName: String?): FreezeAnalysisResult? =
|
||||
when {
|
||||
!edt.isWaiting && !edt.isSleeping -> findFirstRelevantMethod(edt.stackTrace)?.let { FreezeAnalysisResult("EDT is busy with $it", edt.stackTrace) }
|
||||
edt.isWaiting && isWriteLockWait(edt) -> findThreadThatTookReadWriteLock(threadDumpParsed)?.let { FreezeAnalysisResult(it.message, it.stackTrace + "\n\n" + edt.stackTrace) }
|
||||
edt.isWaiting && !isEDTFreezed(edt) -> FreezeAnalysisResult("${testName ?: ""}: EDT is not blocked/busy (freeze can be the result of extensive GC)", edt.stackTrace)
|
||||
!edt.isWaiting && !edt.isSleeping -> findFirstRelevantMethod(edt.stackTrace)?.let { FreezeAnalysisResult("EDT is busy with $it", listOf(edt)) }
|
||||
edt.isWaiting && isWriteLockWait(edt) -> findThreadThatTookReadWriteLock(threadDumpParsed)?.let { FreezeAnalysisResult(it.message, it.threads + listOf(edt), it.additionalMessage) }
|
||||
edt.isWaiting && !isEDTFreezed(edt) -> FreezeAnalysisResult("${testName ?: ""}: EDT is not blocked/busy (freeze can be the result of extensive GC)", listOf(edt))
|
||||
edt.isWaiting -> analyzeLock(edt, threadDumpParsed)
|
||||
else -> null
|
||||
}
|
||||
@@ -47,7 +51,7 @@ object FreezeAnalyzer {
|
||||
if (possibleThreadWithLock == null) return null
|
||||
val methodFromThreadWithLock = findFirstRelevantMethod(possibleThreadWithLock.stackTrace)
|
||||
if (methodFromThreadWithLock != null) {
|
||||
return FreezeAnalysisResult("EDT is blocked on $relevantMethodFromEdt", "Possibly locked by $methodFromThreadWithLock in ${possibleThreadWithLock.name} \n\n" + edt.stackTrace + "\n\n" + possibleThreadWithLock.stackTrace)
|
||||
return FreezeAnalysisResult("EDT is blocked on $relevantMethodFromEdt", listOf(edt, possibleThreadWithLock), additionalMessage = "Possibly locked by $methodFromThreadWithLock in ${possibleThreadWithLock.name}")
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -75,17 +79,13 @@ object FreezeAnalyzer {
|
||||
threadDumpParsed.firstOrNull { it.isAwaitedBy(threadState) }?.let {
|
||||
if (isWaitingOnReadWriteLock(it)) {
|
||||
FreezeAnalysisResult("Possible deadlock. Read lock is taken by ${findFirstRelevantMethod(threadState.stackTrace)}, but the thread is blocked by ${findFirstRelevantMethod(it.stackTrace)} which is waiting on RWLock",
|
||||
"${threadState.name} took RWLock but it's blocked by ${it.name} which waits on RWLock" +
|
||||
"\n\n" +
|
||||
threadState.stackTrace + "\n\n" + it.stackTrace)
|
||||
listOf(threadState, it), additionalMessage = "${threadState.name} took RWLock but it's blocked by ${it.name} which waits on RWLock")
|
||||
}
|
||||
else {
|
||||
FreezeAnalysisResult("Read lock is taken by ${findFirstRelevantMethod(threadState.stackTrace)}, but this thread is blocked by ${findFirstRelevantMethod(it.stackTrace)}",
|
||||
"${threadState.name} took RWLock but it's blocked by ${it.name}" +
|
||||
"\n\n" +
|
||||
threadState.stackTrace + "\n\n" + it.stackTrace)
|
||||
listOf(threadState, it), additionalMessage = "${threadState.name} took RWLock but it's blocked by ${it.name}")
|
||||
}
|
||||
} ?: FreezeAnalysisResult("Long read action in ${findFirstRelevantMethod(threadState.stackTrace)}", threadState.stackTrace)
|
||||
} ?: FreezeAnalysisResult("Long read action in ${findFirstRelevantMethod(threadState.stackTrace)}", listOf(threadState))
|
||||
}
|
||||
|
||||
private fun isWaitingOnReadWriteLock(threadState: ThreadState): Boolean =
|
||||
@@ -165,4 +165,4 @@ object FreezeAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
data class FreezeAnalysisResult(val message: String, val stackTrace: String)
|
||||
data class FreezeAnalysisResult(val message: String, val threads: List<ThreadState>, val additionalMessage: String? = null)
|
||||
@@ -14,7 +14,7 @@ class FreezeAnalyzerTest {
|
||||
fun testAWTFreeze1() {
|
||||
val threadDump = File(this::class.java.classLoader.getResource("freezes/awtFreeze/IDEA-344485.txt")!!.path).toPath().readText()
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.message.shouldBe("EDT is busy with com.intellij.vcs.log.data.VcsLogUserResolverBase.resolveCurrentUser")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.stackTrace?.lineSequence()?.first().shouldBe("\"AWT-EventQueue-0\" prio=0 tid=0x0 nid=0x0 runnable")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.threads?.first()?.stackTrace?.lineSequence()?.first().shouldBe("\"AWT-EventQueue-0\" prio=0 tid=0x0 nid=0x0 runnable")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -51,7 +51,7 @@ class FreezeAnalyzerTest {
|
||||
fun testLockFreeze1() {
|
||||
val threadDump = File(this::class.java.classLoader.getResource("freezes/readWriteLock/ML-2562.txt")!!.path).toPath().readText()
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.message.shouldBe("Long read action in org.jetbrains.completion.full.line.local.generation.SimilarContextRetriever.getSimilarity")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.stackTrace?.shouldContain("\"DefaultDispatcher-worker-27\" prio=0 tid=0x0 nid=0x0 runnable")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.threads?.joinToString { it -> it.stackTrace }.shouldContain("\"DefaultDispatcher-worker-27\" prio=0 tid=0x0 nid=0x0 runnable")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,14 +82,14 @@ class FreezeAnalyzerTest {
|
||||
fun testGeneralLockFreeze() {
|
||||
val threadDump = File(this::class.java.classLoader.getResource("freezes/generalLock/generalLock.txt")!!.path).toPath().readText()
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.message.shouldBe("EDT is blocked on com.intellij.codeInsight.completion.CompletionProgressIndicator.blockingWaitForFinish")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.stackTrace?.shouldStartWith("Possibly locked by com.intellij.codeInsight.completion.JavaMethodCallElement.<init> in DefaultDispatcher-worker-55")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.threads?.joinToString { it -> it.stackTrace }.shouldStartWith("Possibly locked by com.intellij.codeInsight.completion.JavaMethodCallElement.<init> in DefaultDispatcher-worker-55")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGeneralLock2Freeze() {
|
||||
val threadDump = File(this::class.java.classLoader.getResource("freezes/generalLock/generalLock2.txt")!!.path).toPath().readText()
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.message.shouldBe("EDT is blocked on org.jetbrains.kotlin.idea.base.projectStructure.KotlinProjectStructureUtils\$hasKotlinJvmRuntime\$1.invoke")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.stackTrace?.shouldStartWith("Possibly locked by com.intellij.lang.javascript.psi.stubs.JSUsedRemoteModulesIndex.getUsedModules in ApplicationImpl pooled thread 10")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.additionalMessage.shouldBe("Possibly locked by com.intellij.lang.javascript.psi.stubs.JSUsedRemoteModulesIndex.getUsedModules in ApplicationImpl pooled thread 10")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -110,7 +110,7 @@ class FreezeAnalyzerTest {
|
||||
withClue("") {
|
||||
assertSoftly {
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.message.shouldBe("Long read action in com.intellij.openapi.roots.impl.PackageDirectoryCacheImpl\$PackageInfo.lambda\$new\$0")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.stackTrace.shouldStartWith("\"DefaultDispatcher-worker-22\" prio=0 tid=0x0 nid=0x0 waiting on condition")
|
||||
FreezeAnalyzer.analyzeFreeze(threadDump)?.threads?.joinToString { it -> it.stackTrace }.shouldStartWith("\"DefaultDispatcher-worker-22\" prio=0 tid=0x0 nid=0x0 waiting on condition")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user