[debugger] IDEA-385233 Show a placeholder for throttled frames

GitOrigin-RevId: bc35301dd0795092a0581609e68f5c4f76d58a80
This commit is contained in:
Maksim Zuev
2026-01-29 20:31:29 +00:00
committed by intellij-monorepo-bot
parent 3cb27850fd
commit 02b310af9e
10 changed files with 113 additions and 25 deletions
@@ -7,19 +7,19 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library name="debugger-agent" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps:debugger-agent:1.131">
<properties include-transitive-deps="false" maven-id="org.jetbrains.intellij.deps:debugger-agent:1.133">
<verification>
<artifact url="file://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.131/debugger-agent-1.131.jar">
<sha256sum>b425c8604b860f7febe09809a7256f5f6209ac8f778ac27cc5ec1de328b3d1cb</sha256sum>
<artifact url="file://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.133/debugger-agent-1.133.jar">
<sha256sum>d08d14bf727e3a393dc9e0f95b86b3483d32c15027673324558a13d4eee3756e</sha256sum>
</artifact>
</verification>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.131/debugger-agent-1.131.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.133/debugger-agent-1.133.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.131/debugger-agent-1.131-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/intellij/deps/debugger-agent/1.133/debugger-agent-1.133-sources.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -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.JavaDebuggerBundle;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
@@ -38,10 +39,16 @@ import com.intellij.platform.eel.EelDescriptor;
import com.intellij.platform.eel.provider.EelProviderUtil;
import com.intellij.platform.eel.provider.LocalEelDescriptor;
import com.intellij.platform.eel.provider.utils.EelPathUtils;
import com.intellij.ui.ColoredTextContainer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.BazelEnvironmentUtil;
import com.intellij.util.SlowOperations;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xdebugger.frame.XCompositeNode;
import com.intellij.xdebugger.frame.XStackFrame;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.frame.XStackFrameWithSeparatorAbove;
import com.sun.jdi.*;
import com.sun.jdi.event.LocatableEvent;
import org.jetbrains.annotations.ApiStatus;
@@ -189,8 +196,13 @@ public final class AsyncStacksUtils {
String className = dis.readUTF();
String methodName = dis.readUTF();
int line = dis.readInt();
Location location = DebuggerUtilsEx.findOrCreateLocation(vm.getVirtualMachine(), className, methodName, line);
item = new StackFrameItem(location, null);
if ("< Unknown".equals(className) && "Stack > ".equals(methodName)) {
item = new ThrottledStackFrameItem(vm.getVirtualMachine());
}
else {
Location location = DebuggerUtilsEx.findOrCreateLocation(vm.getVirtualMachine(), className, methodName, line);
item = new StackFrameItem(location, null);
}
}
res.add(item);
}
@@ -497,6 +509,8 @@ public final class AsyncStacksUtils {
if (isSuspendHelperEnabled()) {
properties.setProperty("suspendHelper", "true");
}
boolean throttling = DebuggerSettings.getInstance().AGENT_THROTTLING;
properties.setProperty("throttling", Boolean.toString(throttling));
double overhead = Registry.doubleValue("debugger.async.stack.trace.overhead.percent");
properties.setProperty("overheadPercent", Double.toString(overhead));
if (JavaCollectionBreakpointType.isEnabled()) {
@@ -532,4 +546,60 @@ public final class AsyncStacksUtils {
breakpoint.setSuspendPolicy(DebuggerSettings.SUSPEND_THREAD);
breakpoint.createRequest(process);
}
private static class ThrottledStackFrameItem extends StackFrameItem {
ThrottledStackFrameItem(VirtualMachine vm) {
super(createSyntheticLocation(vm), Collections.emptyList());
}
private static Location createSyntheticLocation(VirtualMachine vm) {
return DebuggerUtilsEx.findOrCreateLocation(vm, "", "", -1);
}
@Override
public XStackFrame createFrame(@NotNull DebugProcessImpl debugProcess, @Nullable SourcePosition sourcePosition) {
return new ThrottledFrame();
}
}
private static class ThrottledFrame extends XStackFrame implements XStackFrameWithSeparatorAbove, JVMStackFrameInfoProvider {
private boolean myWithSeparator;
@Override
public void customizePresentation(@NotNull ColoredTextContainer component) {
component.append(JavaDebuggerBundle.message("async.stack.throttled.frame.label"), SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
}
@Override
public void computeChildren(@NotNull XCompositeNode node) {
node.setMessage(JavaDebuggerBundle.message("async.stack.throttled.frame.info"), null,
SimpleTextAttributes.REGULAR_ATTRIBUTES, StackFrameItem.CAPTURE_SETTINGS_OPENER);
node.addChildren(XValueChildrenList.EMPTY, true);
}
@Override
public String getCaptionAboveOf() {
return StackFrameItem.getAsyncStacktraceMessage();
}
@Override
public boolean hasSeparatorAbove() {
return myWithSeparator;
}
@Override
public void setWithSeparator(boolean withSeparator) {
myWithSeparator = withSeparator;
}
@Override
public boolean isSynthetic() {
return true;
}
@Override
public boolean isInLibraryContent() {
return false;
}
}
}
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.settings.CaptureConfigurable">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
@@ -29,9 +29,17 @@
<text resource-bundle="messages/JavaDebuggerBundle" key="label.capture.configurable.annotations.configure"/>
</properties>
</component>
<component id="b7f21" class="com.intellij.ui.components.JBCheckBox" binding="myThrottling">
<constraints>
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="1" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/JavaDebuggerBundle" key="label.capture.configurable.throttling"/>
</properties>
</component>
<grid id="5f9b3" binding="myCapturePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -66,6 +66,7 @@ public final class CaptureConfigurable implements SearchableConfigurable, NoScro
private final Project myProject;
private JCheckBox myDebuggerAgent;
private JCheckBox myThrottling;
private JButton myConfigureAnnotationsButton;
private JPanel myCapturePanel;
private MyTableModel myTableModel;
@@ -444,6 +445,7 @@ public final class CaptureConfigurable implements SearchableConfigurable, NoScro
public boolean isModified() {
return DebuggerSettings.getInstance().CAPTURE_VARIABLES != myCaptureVariables.isSelected() ||
DebuggerSettings.getInstance().INSTRUMENTING_AGENT != myDebuggerAgent.isSelected() ||
DebuggerSettings.getInstance().AGENT_THROTTLING != myThrottling.isSelected() ||
!DebuggerSettings.getInstance().getCapturePoints().equals(myTableModel.myCapturePoints);
}
@@ -452,12 +454,14 @@ public final class CaptureConfigurable implements SearchableConfigurable, NoScro
DebuggerSettings.getInstance().setCapturePoints(myTableModel.myCapturePoints);
DebuggerSettings.getInstance().CAPTURE_VARIABLES = myCaptureVariables.isSelected();
DebuggerSettings.getInstance().INSTRUMENTING_AGENT = myDebuggerAgent.isSelected();
DebuggerSettings.getInstance().AGENT_THROTTLING = myThrottling.isSelected();
}
@Override
public void reset() {
myCaptureVariables.setSelected(DebuggerSettings.getInstance().CAPTURE_VARIABLES);
myDebuggerAgent.setSelected(DebuggerSettings.getInstance().INSTRUMENTING_AGENT);
myThrottling.setSelected(DebuggerSettings.getInstance().AGENT_THROTTLING);
myTableModel.myCapturePoints = DebuggerSettings.getInstance().cloneCapturePoints();
myTableModel.fireTableDataChanged();
}
@@ -14,7 +14,7 @@ import java.util.Set;
import static com.intellij.internal.statistic.beans.MetricEventUtilKt.addBoolIfDiffers;
public final class DebuggerSettingsStatisticsCollector extends ApplicationUsagesCollector {
private static final EventLogGroup GROUP = new EventLogGroup("debugger.settings.ide", 7);
private static final EventLogGroup GROUP = new EventLogGroup("debugger.settings.ide", 8);
private static final VarargEventId SHOW_ALTERNATIVE_SOURCE = GROUP.registerVarargEvent("showAlternativeSource", EventFields.Enabled);
private static final VarargEventId HOTSWAP_IN_BACKROUND = GROUP.registerVarargEvent("hotswapInBackround", EventFields.Enabled);
@@ -32,6 +32,7 @@ public final class DebuggerSettingsStatisticsCollector extends ApplicationUsages
private static final VarargEventId RESUME_ONLY_CURRENT_THREAD = GROUP.registerVarargEvent("resumeOnlyCurrentThread", EventFields.Enabled);
private static final VarargEventId HIDE_STACK_FRAMES_USING_STEPPING_FILTER = GROUP.registerVarargEvent("hideStackFramesUsingSteppingFilter", EventFields.Enabled);
private static final VarargEventId INSTRUMENTING_AGENT = GROUP.registerVarargEvent("instrumentingAgent", EventFields.Enabled);
private static final VarargEventId AGENT_THROTTLING = GROUP.registerVarargEvent("agentThrottling", EventFields.Enabled);
@Override
public EventLogGroup getGroup() {
@@ -60,6 +61,7 @@ public final class DebuggerSettingsStatisticsCollector extends ApplicationUsages
addBoolIfDiffers(set, settings, sDefault, s -> s.RESUME_ONLY_CURRENT_THREAD, RESUME_ONLY_CURRENT_THREAD);
addBoolIfDiffers(set, settings, sDefault, s -> s.HIDE_STACK_FRAMES_USING_STEPPING_FILTER, HIDE_STACK_FRAMES_USING_STEPPING_FILTER);
addBoolIfDiffers(set, settings, sDefault, s -> s.INSTRUMENTING_AGENT, INSTRUMENTING_AGENT);
addBoolIfDiffers(set, settings, sDefault, s -> s.AGENT_THROTTLING, AGENT_THROTTLING);
return set;
}
@@ -555,6 +555,9 @@ column.name.shallow.size=Shallow Size
column.name.retained.size=Retained Size
stepping.filter.real.thread.name=thread {0}
debugger.variables.not.available.in.async=Variables are not available for async stack frames
async.stack.throttled.frame.label=Async frames are omitted
async.stack.throttled.frame.info=Async stack trace was not collected due to performance overhead. You can disable throttling in
label.capture.configurable.throttling=Throttling
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.
@@ -107,6 +107,7 @@ public final class DebuggerSettings implements Cloneable, PersistentStateCompone
private ClassFilter[] mySteppingFilters = DEFAULT_STEPPING_FILTERS;
public boolean INSTRUMENTING_AGENT = true;
public boolean AGENT_THROTTLING = true;
private List<CapturePoint> myCapturePoints = new ArrayList<>();
public boolean CAPTURE_VARIABLES;
private final EventDispatcher<CapturePointsSettingsListener> myDispatcher = EventDispatcher.create(CapturePointsSettingsListener.class);