From df16183fee081520b2cbf8b4453e78fdf32131e1 Mon Sep 17 00:00:00 2001 From: "Vitaliy.Bibaev" Date: Wed, 6 Feb 2019 19:40:41 +0300 Subject: [PATCH] [memory-agent] Add retained sizes into for objects in instances tree if memory agent enabled --- .../memory/agent/MemoryAgentUtil.java | 24 ++++++++++++ .../memory/filtering/FilteringTask.java | 15 ++++---- .../filtering/FilteringTaskCallback.java | 8 ++-- .../debugger/memory/ui/InstancesView.java | 33 ++++++++--------- .../debugger/memory/ui/JavaReferenceInfo.java | 7 ++++ .../memory/ui/SizedReferenceInfo.java | 37 +++++++++++++++++++ 6 files changed, 95 insertions(+), 29 deletions(-) create mode 100644 java/debugger/impl/src/com/intellij/debugger/memory/ui/SizedReferenceInfo.java diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentUtil.java b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentUtil.java index a2533e708828..f19db69f0177 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/agent/MemoryAgentUtil.java @@ -4,19 +4,26 @@ package com.intellij.debugger.memory.agent; import com.intellij.debugger.engine.DebugProcessAdapterImpl; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.SuspendContextImpl; +import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.memory.agent.extractor.AgentExtractor; +import com.intellij.debugger.memory.ui.JavaReferenceInfo; +import com.intellij.debugger.memory.ui.SizedReferenceInfo; import com.intellij.execution.JavaExecutionUtil; import com.intellij.execution.configurations.JavaParameters; import com.intellij.execution.configurations.ParametersList; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.registry.Registry; +import com.intellij.util.containers.ContainerUtil; +import one.util.streamex.IntStreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.Comparator; +import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -64,6 +71,23 @@ public class MemoryAgentUtil { parametersList.add("-agentpath:" + path); } + public static List tryCalculateSizes(@NotNull List objects, @Nullable MemoryAgent agent) { + if (agent == null || !agent.canEvaluateObjectsSizes()) return objects; + try { + long[] sizes = agent.evaluateObjectsSizes(ContainerUtil.map(objects, x -> x.getObjectReference())); + return IntStreamEx.range(0, objects.size()) + .mapToObj(i -> new SizedReferenceInfo(objects.get(i).getObjectReference(), sizes[i])) + .reverseSorted(Comparator.comparing(x -> x.size())) + .map(x -> (JavaReferenceInfo)x) + .toList(); + } + catch (EvaluateException e) { + LOG.error("Could not estimate objects sizes"); + } + + return objects; + } + public static void loadAgentProxy(@NotNull DebugProcessImpl debugProcess, @NotNull Consumer agentLoaded) { debugProcess.addDebugProcessListener(new DebugProcessAdapterImpl() { @Override diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTask.java b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTask.java index 39cb8e2c5041..1aff9ea8486f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTask.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTask.java @@ -16,9 +16,9 @@ package com.intellij.debugger.memory.filtering; import com.intellij.debugger.engine.DebugProcessImpl; +import com.intellij.debugger.memory.ui.JavaReferenceInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.xdebugger.XExpression; -import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; /** @@ -54,18 +54,18 @@ public class FilteringTask implements Runnable { myCallback.started(myValues.size()); int proceedCount; for (proceedCount = 0; proceedCount < myValues.size() && !myIsCancelled; proceedCount++) { - Value value = myValues.get(proceedCount); - CheckingResult result = myChecker.check(value); + JavaReferenceInfo info = myValues.get(proceedCount); + CheckingResult result = myChecker.check(info.getObjectReference()); FilteringTaskCallback.Action action = FilteringTaskCallback.Action.CONTINUE; switch (result.getResult()) { case MATCH: - action = myCallback.matched(value); + action = myCallback.matched(info); break; case NO_MATCH: - action = myCallback.notMatched(value); + action = myCallback.notMatched(info); break; case ERROR: - action = myCallback.error(value, result.getFailureDescription()); + action = myCallback.error(info, result.getFailureDescription()); break; } @@ -85,6 +85,7 @@ public class FilteringTask implements Runnable { public interface ValuesList { int size(); - Value get(int index); + + JavaReferenceInfo get(int index); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTaskCallback.java b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTaskCallback.java index 71035287cc4e..c9ddbb9cbe00 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTaskCallback.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/filtering/FilteringTaskCallback.java @@ -15,7 +15,7 @@ */ package com.intellij.debugger.memory.filtering; -import com.sun.jdi.Value; +import com.intellij.debugger.memory.ui.JavaReferenceInfo; import org.jetbrains.annotations.NotNull; /** @@ -25,13 +25,13 @@ public interface FilteringTaskCallback { void started(int totalCount); @NotNull - Action matched(@NotNull Value ref); + Action matched(@NotNull JavaReferenceInfo ref); @NotNull - Action notMatched(@NotNull Value ref); + Action notMatched(@NotNull JavaReferenceInfo ref); @NotNull - Action error(@NotNull Value ref, @NotNull String description); + Action error(@NotNull JavaReferenceInfo ref, @NotNull String description); void completed(@NotNull FilteringResult reason); diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesView.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesView.java index c3e10baea443..b10f51cffa32 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesView.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/InstancesView.java @@ -9,13 +9,13 @@ import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.engine.evaluation.EvaluationContext; import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; +import com.intellij.debugger.memory.agent.MemoryAgentUtil; import com.intellij.debugger.memory.filtering.FilteringResult; import com.intellij.debugger.memory.filtering.FilteringTask; import com.intellij.debugger.memory.filtering.FilteringTaskCallback; import com.intellij.debugger.memory.utils.AndroidUtil; import com.intellij.debugger.memory.utils.ErrorsValueGroup; import com.intellij.debugger.memory.utils.InstanceJavaValue; -import com.intellij.debugger.memory.utils.InstanceValueDescriptor; import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; import com.intellij.debugger.ui.impl.watch.MessageDescriptor; import com.intellij.debugger.ui.impl.watch.NodeManagerImpl; @@ -41,8 +41,6 @@ import com.intellij.xdebugger.impl.ui.XDebuggerExpressionEditor; import com.intellij.xdebugger.memory.ui.InstancesTree; import com.intellij.xdebugger.memory.ui.InstancesViewBase; import com.intellij.xdebugger.memory.utils.InstancesProvider; -import com.sun.jdi.ObjectReference; -import com.sun.jdi.Value; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -184,8 +182,8 @@ class InstancesView extends InstancesViewBase { final int limit = myIsAndroidVM ? AndroidUtil.ANDROID_INSTANCES_LIMIT : DEFAULT_INSTANCES_LIMIT; - List instances = ContainerUtil - .map(getInstancesProvider().getInstances(limit + 1), referenceInfo -> ((JavaReferenceInfo)referenceInfo).getObjectReference()); + List instances = ContainerUtil + .map(getInstancesProvider().getInstances(limit + 1), referenceInfo -> ((JavaReferenceInfo)referenceInfo)); final EvaluationContextImpl evaluationContext = myDebugProcess .getDebuggerContext().createEvaluationContext(); @@ -195,9 +193,11 @@ class InstancesView extends InstancesViewBase { instances = instances.subList(0, limit); } + instances = MemoryAgentUtil.tryCalculateSizes(instances, myDebugProcess.getMemoryAgent()); + if (evaluationContext != null) { synchronized (myFilteringTaskLock) { - List finalInstances = instances; + List finalInstances = instances; ApplicationManager.getApplication().runReadAction(() -> { myFilteringTask = new MyFilteringWorker(finalInstances, myFilterConditionEditor.getExpression(), evaluationContext); myFilteringTask.execute(); @@ -252,9 +252,6 @@ class InstancesView extends InstancesViewBase { } - - - private class MyFilteringCallback implements FilteringTaskCallback { private final ErrorsValueGroup myErrorsGroup = new ErrorsValueGroup(); private final EvaluationContextImpl myEvaluationContext; @@ -284,8 +281,8 @@ class InstancesView extends InstancesViewBase { @NotNull @Override - public Action matched(@NotNull Value ref) { - final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myDebugProcess.getProject(), ref), + public Action matched(@NotNull JavaReferenceInfo ref) { + final JavaValue val = new InstanceJavaValue(ref.createDescriptor(myDebugProcess.getProject()), myEvaluationContext, myNodeManager); myMatchedCount++; myProceedCount++; @@ -298,7 +295,7 @@ class InstancesView extends InstancesViewBase { @NotNull @Override - public Action notMatched(@NotNull Value ref) { + public Action notMatched(@NotNull JavaReferenceInfo ref) { myProceedCount++; updateProgress(); @@ -307,8 +304,8 @@ class InstancesView extends InstancesViewBase { @NotNull @Override - public Action error(@NotNull Value ref, @NotNull String description) { - final JavaValue val = new InstanceJavaValue(new InstanceValueDescriptor(myDebugProcess.getProject(), ref), + public Action error(@NotNull JavaReferenceInfo ref, @NotNull String description) { + final JavaValue val = new InstanceJavaValue(ref.createDescriptor(myDebugProcess.getProject()), myEvaluationContext, myNodeManager); myErrorsGroup.addErrorValue(description, val); myProceedCount++; @@ -364,9 +361,9 @@ class InstancesView extends InstancesViewBase { } } private static class MyValuesList implements FilteringTask.ValuesList { - private final List myRefs; + private final List myRefs; - MyValuesList(List refs) { + MyValuesList(List refs) { myRefs = refs; } @@ -376,14 +373,14 @@ class InstancesView extends InstancesViewBase { } @Override - public ObjectReference get(int index) { + public JavaReferenceInfo get(int index) { return myRefs.get(index); } } private class MyFilteringWorker extends SwingWorker { private final FilteringTask myTask; - MyFilteringWorker(@NotNull List refs, + MyFilteringWorker(@NotNull List refs, @NotNull XExpression expression, @NotNull EvaluationContextImpl evaluationContext) { myTask = new FilteringTask(myClassName, myDebugProcess, expression, new MyValuesList(refs), diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/JavaReferenceInfo.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/JavaReferenceInfo.java index 2f5c847621a3..94b5067ee62d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/memory/ui/JavaReferenceInfo.java +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/JavaReferenceInfo.java @@ -1,6 +1,9 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.debugger.memory.ui; +import com.intellij.debugger.memory.utils.InstanceValueDescriptor; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; +import com.intellij.openapi.project.Project; import com.intellij.xdebugger.memory.ui.ReferenceInfo; import com.sun.jdi.ObjectReference; import org.jetbrains.annotations.NotNull; @@ -12,6 +15,10 @@ public class JavaReferenceInfo implements ReferenceInfo { this.objectReference = objectReference; } + public ValueDescriptorImpl createDescriptor(@NotNull Project project) { + return new InstanceValueDescriptor(project, objectReference); + } + @NotNull public ObjectReference getObjectReference() { return objectReference; diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/ui/SizedReferenceInfo.java b/java/debugger/impl/src/com/intellij/debugger/memory/ui/SizedReferenceInfo.java new file mode 100644 index 000000000000..0a92092022dc --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/memory/ui/SizedReferenceInfo.java @@ -0,0 +1,37 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.debugger.memory.ui; + +import com.intellij.debugger.memory.utils.InstanceValueDescriptor; +import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; +import com.intellij.openapi.project.Project; +import com.sun.jdi.ObjectReference; +import org.jetbrains.annotations.NotNull; + +public class SizedReferenceInfo extends JavaReferenceInfo { + private final long mySize; + + public SizedReferenceInfo(@NotNull ObjectReference objectReference, long size) { + super(objectReference); + mySize = size; + } + + @Override + public ValueDescriptorImpl createDescriptor(@NotNull Project project) { + return new SizedValueDescriptor(project, getObjectReference()); + } + + public long size() { + return mySize; + } + + private class SizedValueDescriptor extends InstanceValueDescriptor { + protected SizedValueDescriptor(@NotNull Project project, @NotNull ObjectReference value) { + super(project, value); + } + + @Override + public String calcValueName() { + return " [" + mySize + "] " + super.calcValueName(); + } + } +}