mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
[debugger] IDEA-385233 Do not show notification
GitOrigin-RevId: 4c6fbc0269369fcede26bc8944816cff2a495b81
This commit is contained in:
committed by
intellij-monorepo-bot
parent
b1356651f6
commit
3cb27850fd
@@ -169,8 +169,6 @@
|
||||
|
||||
<notificationGroup id="HotSwap" displayType="TOOL_WINDOW" toolWindowId="Debug" bundle="messages.JavaDebuggerBundle"
|
||||
key="notification.group.hotswap"/>
|
||||
<notificationGroup id="AsyncStackTraces" displayType="BALLOON" bundle="messages.JavaDebuggerBundle"
|
||||
key="async.stack.traces.notification.group"/>
|
||||
|
||||
<debugger.dfaAssistProvider language="JAVA" implementationClass="com.intellij.debugger.engine.dfaassist.java.JavaDfaAssistProvider"/>
|
||||
|
||||
|
||||
+14
-95
@@ -1,109 +1,28 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.debugger.engine
|
||||
|
||||
import com.intellij.debugger.JavaDebuggerBundle
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx
|
||||
import com.intellij.debugger.statistics.DebuggerStatistics
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.notification.NotificationsManager
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.xdebugger.XDebugSessionListener
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||
import com.sun.jdi.ObjectReference
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
private class LastSessionPauseListener : XDebugSessionListener {
|
||||
private val isPaused = MutableStateFlow(false)
|
||||
private val startNs = System.nanoTime()
|
||||
private val sessionStartTimestampKey = Key.create<Long>("debuggerSessionStartTimestamp")
|
||||
|
||||
override fun sessionPaused() {
|
||||
isPaused.value = true
|
||||
}
|
||||
|
||||
override fun sessionResumed() {
|
||||
isPaused.value = false
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
suspend fun awaitNoPauseFor(duration: Duration) {
|
||||
isPaused.debounce(duration).first { !it }
|
||||
}
|
||||
|
||||
fun passedSinceSessionStartMs(): Long {
|
||||
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs)
|
||||
}
|
||||
}
|
||||
|
||||
private val lastSessionPauseListenerKey = Key.create<LastSessionPauseListener>("lastSessionPauseListenerKey")
|
||||
|
||||
internal fun initializeLastSessionPauseListener(process: DebugProcessImpl) {
|
||||
val xDebugSession = process.session.xDebugSession ?: return
|
||||
val listener = LastSessionPauseListener()
|
||||
process.putUserData(lastSessionPauseListenerKey, listener)
|
||||
xDebugSession.addSessionListener(listener)
|
||||
internal fun initializeOverheadListener(process: DebugProcessImpl) {
|
||||
val startNs = System.nanoTime()
|
||||
process.putUserData(sessionStartTimestampKey, startNs)
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
internal fun showOverheadNotification(process: DebugProcessImpl, overhead: ObjectReference) {
|
||||
val xDebugSession = process.session.xDebugSession as? XDebugSessionImpl ?: return
|
||||
val cs = xDebugSession.coroutineScope
|
||||
val managerThread = DebuggerManagerThreadImpl.getCurrentThread()
|
||||
cs.launch(Dispatchers.EDT) {
|
||||
val project = xDebugSession.project
|
||||
val listener = process.getUserData(lastSessionPauseListenerKey)
|
||||
val passedSinceSessionStartMs = listener?.passedSinceSessionStartMs() ?: -1
|
||||
DebuggerStatistics.logAgentOverheadDetected(project, passedSinceSessionStartMs)
|
||||
if (listener != null) {
|
||||
// we don't want to show notification if user is actively debugging
|
||||
listener.awaitNoPauseFor(3.seconds)
|
||||
}
|
||||
|
||||
if (process.isDetached) return@launch
|
||||
val title = JavaDebuggerBundle.message("async.stack.traces.overhead.title")
|
||||
val content = JavaDebuggerBundle.message("async.stack.traces.overhead.description")
|
||||
val notification = Notification("AsyncStackTraces", title, content, NotificationType.WARNING)
|
||||
notification.addAction(DumbAwareAction.create(JavaDebuggerBundle.message("async.stack.traces.overhead.throttle.button")) {
|
||||
notification.expire()
|
||||
DebuggerStatistics.logAgentOverheadNotificationThrottlingEnabled(project)
|
||||
executeOnDMT(managerThread) {
|
||||
val field = DebuggerUtils.findField(overhead.referenceType(), "throttleWhenOverhead")
|
||||
if (field != null) {
|
||||
overhead.setValue(field, overhead.virtualMachine().mirrorOf(true))
|
||||
}
|
||||
}
|
||||
})
|
||||
notification.addAction(DumbAwareAction.create(JavaDebuggerBundle.message("async.stack.traces.overhead.disable.button")) {
|
||||
notification.expire()
|
||||
DebuggerStatistics.logAgentOverheadNotificationAgentDisabled(project)
|
||||
executeOnDMT(managerThread) {
|
||||
DebuggerUtilsEx.setStaticBooleanField(process, AsyncStacksUtils.CAPTURE_STORAGE_CLASS_NAME, "ENABLED", false)
|
||||
}
|
||||
})
|
||||
notification.addAction(DumbAwareAction.create(JavaDebuggerBundle.message("async.stack.traces.overhead.ignore.button")) {
|
||||
notification.expire()
|
||||
DebuggerStatistics.logAgentOverheadNotificationDismissed(project)
|
||||
})
|
||||
val processListener = object : DebugProcessListener {
|
||||
override fun processDetached(process: DebugProcess, closedByUser: Boolean) {
|
||||
notification.expire()
|
||||
}
|
||||
}
|
||||
process.addDebugProcessListener(processListener)
|
||||
notification.whenExpired {
|
||||
process.removeDebugProcessListener(processListener)
|
||||
}
|
||||
NotificationsManager.getNotificationsManager().showNotification(notification, process.project)
|
||||
DebuggerStatistics.logAgentOverheadNotificationShown(project)
|
||||
internal fun onOverheadDetected(process: DebugProcessImpl) {
|
||||
val project = process.project
|
||||
val sessionStartNs = process.getUserData(sessionStartTimestampKey)
|
||||
val sessionLengthMs = if (sessionStartNs != null) {
|
||||
val durationNs = System.nanoTime() - sessionStartNs
|
||||
TimeUnit.NANOSECONDS.toMillis(durationNs)
|
||||
}
|
||||
else {
|
||||
-1
|
||||
}
|
||||
DebuggerStatistics.logAgentOverheadDetected(project, sessionLengthMs)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.debugger.engine;
|
||||
|
||||
import com.intellij.debugger.SourcePosition;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
@@ -517,24 +518,14 @@ public final class AsyncStacksUtils {
|
||||
}
|
||||
|
||||
private static void initializeOverheadDetector(DebugProcessImpl process) {
|
||||
AsyncStackTracesOverheadUtilsKt.initializeLastSessionPauseListener(process);
|
||||
AsyncStackTracesOverheadUtilsKt.initializeOverheadListener(process);
|
||||
|
||||
String className = "com.intellij.rt.debugger.agent.OverheadDetector";
|
||||
String methodName = "overheadDetected";
|
||||
var breakpoint = new SyntheticMethodBreakpoint(className, methodName, null, process.getProject()) {
|
||||
@Override
|
||||
public boolean processLocatableEvent(@NotNull SuspendContextCommandImpl action, LocatableEvent event) {
|
||||
if (event == null) return false;
|
||||
try {
|
||||
List<Value> args = DebuggerUtilsEx.getArgumentValues(event.thread().frame(0));
|
||||
Value overheadValue = ContainerUtil.getFirstItem(args);
|
||||
if (overheadValue instanceof ObjectReference overhead) {
|
||||
AsyncStackTracesOverheadUtilsKt.showOverheadNotification(process, overhead);
|
||||
}
|
||||
}
|
||||
catch (IncompatibleThreadStateException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
AsyncStackTracesOverheadUtilsKt.onOverheadDetected(process);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.jetbrains.annotations.ApiStatus
|
||||
object DebuggerStatistics : CounterUsagesCollector() {
|
||||
override fun getGroup(): EventLogGroup = GROUP
|
||||
|
||||
private val GROUP = EventLogGroup("java.debugger", 15)
|
||||
private val GROUP = EventLogGroup("java.debugger", 16)
|
||||
|
||||
// fields
|
||||
|
||||
@@ -76,14 +76,6 @@ object DebuggerStatistics : CounterUsagesCollector() {
|
||||
private val agentOverheadDetected = GROUP.registerEvent("debugger.agent.overhead.detected",
|
||||
EventFields.Long("passed_since_session_start_ms"),
|
||||
"Detected noticeable overhead of the debugger agent due to async stack traces collection")
|
||||
private val agentOverheadNotificationShown = GROUP.registerEvent("debugger.agent.overhead.notification.shown",
|
||||
"Debugger agent overhead notification was shown (happens after overhead detected in 3 seconds)")
|
||||
private val agentOverheadNotificationDismissed = GROUP.registerEvent("debugger.agent.overhead.notification.dismissed",
|
||||
"Debugger agent overhead notification was dismissed")
|
||||
private val agentOverheadNotificationAgentDisabled = GROUP.registerEvent("debugger.agent.overhead.notification.agent.disabled",
|
||||
"Debugger agent was disabled on overhead detected")
|
||||
private val agentOverheadNotificationThrottlingEnabled = GROUP.registerEvent("debugger.agent.overhead.notification.throttling.enabled",
|
||||
"Throttling of debugger agent was enabled on overhead detected")
|
||||
|
||||
@JvmStatic
|
||||
fun logProcessStatistics(debugProcess: DebugProcess) {
|
||||
@@ -193,22 +185,6 @@ object DebuggerStatistics : CounterUsagesCollector() {
|
||||
agentOverheadDetected.log(project, passedSinceSessionStartMs)
|
||||
}
|
||||
|
||||
fun logAgentOverheadNotificationShown(project: Project) {
|
||||
agentOverheadNotificationShown.log(project)
|
||||
}
|
||||
|
||||
fun logAgentOverheadNotificationDismissed(project: Project) {
|
||||
agentOverheadNotificationDismissed.log(project)
|
||||
}
|
||||
|
||||
fun logAgentOverheadNotificationAgentDisabled(project: Project) {
|
||||
agentOverheadNotificationAgentDisabled.log(project)
|
||||
}
|
||||
|
||||
fun logAgentOverheadNotificationThrottlingEnabled(project: Project) {
|
||||
agentOverheadNotificationThrottlingEnabled.log(project)
|
||||
}
|
||||
|
||||
|
||||
private val Breakpoint<*>.type: String? get() = xBreakpoint?.type?.id
|
||||
}
|
||||
|
||||
@@ -558,10 +558,3 @@ debugger.variables.not.available.in.async=Variables are not available for async
|
||||
exception=Exception
|
||||
ref=Ref
|
||||
thread.dump.during.previous.dump.evaluation.warning=Evaluation of the previous dump is still in progress. Java platform thread dump is taken.
|
||||
|
||||
async.stack.traces.notification.group=Async Stack Traces
|
||||
async.stack.traces.overhead.title=Async stack traces overhead detected
|
||||
async.stack.traces.overhead.description=Collecting async stack traces may significantly impact your application's performance
|
||||
async.stack.traces.overhead.throttle.button=Throttle
|
||||
async.stack.traces.overhead.ignore.button=Ignore
|
||||
async.stack.traces.overhead.disable.button=Disable
|
||||
|
||||
Reference in New Issue
Block a user