Merge "[572596]: Add maximum retained heap of locals to stack frame row"
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadInfoImpl.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadInfoImpl.java
index 4d2f348..694e58e 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadInfoImpl.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadInfoImpl.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008, 2020 SAP AG & IBM Corporation.
+ * Copyright (c) 2008, 2021 SAP AG & IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -45,13 +45,14 @@
// column meta-data
// //////////////////////////////////////////////////////////////
- private static final Column COL_CLASSNAME = new Column(Messages.Column_ClassName);
- private static final Column COL_NAME = new Column(Messages.ThreadInfoImpl_Column_Name);
- private static final Column COL_INSTANCE = new Column(Messages.ThreadStackQuery_Column_ObjectStackFrame);
- private static final Column COL_SHALLOW = new Column(Messages.Column_ShallowHeap, Bytes.class);
- private static final Column COL_RETAINED = new Column(Messages.Column_RetainedHeap, Bytes.class);
- private static final Column COL_CONTEXTCL = new Column(Messages.ThreadInfoImpl_Column_ContextClassLoader);
- private static final Column COL_ISDAEMON = new Column(Messages.ThreadInfoImpl_Column_IsDaemon, Boolean.class);
+ public static final Column COL_CLASSNAME = new Column(Messages.Column_ClassName);
+ public static final Column COL_NAME = new Column(Messages.ThreadInfoImpl_Column_Name);
+ public static final Column COL_INSTANCE = new Column(Messages.ThreadStackQuery_Column_ObjectStackFrame);
+ public static final Column COL_SHALLOW = new Column(Messages.Column_ShallowHeap, Bytes.class);
+ public static final Column COL_RETAINED = new Column(Messages.Column_RetainedHeap, Bytes.class);
+ public static final Column COL_CONTEXTCL = new Column(Messages.ThreadInfoImpl_Column_ContextClassLoader);
+ public static final Column COL_ISDAEMON = new Column(Messages.ThreadInfoImpl_Column_IsDaemon, Boolean.class);
+ public static final Column COL_MAXLOCALRETAINED = new Column(Messages.ThreadInfoImpl_Column_MaxLocalRetainedHeap, Bytes.class).noTotals();
private static final List<Column> defaultColumns = Arrays.asList(new Column[] {
//COL_CLASSNAME, //
@@ -59,6 +60,7 @@
COL_NAME, //
COL_SHALLOW, //
COL_RETAINED, //
+ COL_MAXLOCALRETAINED, //
COL_CONTEXTCL,
COL_ISDAEMON});
@@ -187,13 +189,7 @@
/* package */List<Column> getUsedColumns()
{
- List<Column> answer = new ArrayList<Column>();
- // Return copy of columns so independent and columns don't permanently retain decorators
- for (Column col : defaultColumns)
- {
- Column col2 = new Column(col.getLabel(), col.getType());
- answer.add(col2);
- }
+ List<Column> answer = getDefaultColumnsCopy();
for (IThreadDetailsResolver resolver : ThreadDetailResolverRegistry.instance().delegates())
{
Column[] cols = resolver.getColumns();
@@ -211,13 +207,7 @@
/* package */static List<Column> getUsedColumns(List<ThreadInfoImpl> threads)
{
- List<Column> answer = new ArrayList<Column>();
- // Return copy of columns so independent and columns don't permanently retain decorators
- for (Column col : defaultColumns)
- {
- Column col2 = new Column(col.getLabel(), col.getType());
- answer.add(col2);
- }
+ List<Column> answer = getDefaultColumnsCopy();
for (IThreadDetailsResolver resolver : ThreadDetailResolverRegistry.instance().delegates())
{
Column[] cols = resolver.getColumns();
@@ -239,6 +229,25 @@
return answer;
}
+ private static List<Column> getDefaultColumnsCopy()
+ {
+ List<Column> answer = new ArrayList<Column>();
+ // Return copy of columns so independent and columns don't permanently
+ // retain decorators
+ for (Column col : defaultColumns)
+ {
+ // Copy everything that's used in Column.equals
+ Column col2 = new Column(col.getLabel(), col.getType(), col.getAlign(), col.getSortDirection(),
+ col.getFormatter(), col.getComparator());
+ if (!col.getCalculateTotals())
+ {
+ col2.noTotals();
+ }
+ answer.add(col2);
+ }
+ return answer;
+ }
+
// //////////////////////////////////////////////////////////////
// instance
// //////////////////////////////////////////////////////////////
@@ -370,6 +379,8 @@
return getContextClassLoader();
else if (COL_ISDAEMON.equals(column))
return isDaemon();
+ else if (COL_MAXLOCALRETAINED.equals(column))
+ return null;
else
return properties.get(column);
}
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
index 3edc0bf..e322fc9 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/inspections/threads/ThreadOverviewQuery.java
@@ -22,6 +22,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
+import java.util.logging.Logger;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.collect.ArrayInt;
@@ -29,6 +30,7 @@
import org.eclipse.mat.collect.SetInt;
import org.eclipse.mat.inspections.InspectionAssert;
import org.eclipse.mat.internal.Messages;
+import org.eclipse.mat.query.Bytes;
import org.eclipse.mat.query.Column;
import org.eclipse.mat.query.DetailResultProvider;
import org.eclipse.mat.query.IContextObject;
@@ -57,6 +59,7 @@
import org.eclipse.mat.snapshot.query.ObjectListResult;
import org.eclipse.mat.snapshot.query.SnapshotQuery;
import org.eclipse.mat.util.IProgressListener;
+import org.eclipse.mat.util.MessageUtil;
@CommandName("thread_overview")
@Icon("/META-INF/icons/threads.gif")
@@ -265,6 +268,8 @@
private int depth;
private boolean firstNonNativeFrame;
private int objectId;
+ private boolean extraColumnsCalculated;
+ private Bytes maxLocalRetainedHeapSize;
}
private static class ThreadStackFrameLocalNode
@@ -418,13 +423,25 @@
} else {
if (row instanceof ThreadStackFrameNode)
{
- switch (columnIndex)
+ ThreadStackFrameNode info = (ThreadStackFrameNode) row;
+ Column column = columns[columnIndex];
+ try
{
- case 0:
- IStackFrame frame = ((ThreadStackFrameNode) row).stackFrame;
+ if (ThreadInfoImpl.COL_INSTANCE.equals(column))
+ {
+ IStackFrame frame = info.stackFrame;
return frame.getText();
- default:
- break;
+ }
+ else if (ThreadInfoImpl.COL_MAXLOCALRETAINED.equals(column))
+ {
+ calculateStackFrameNodeColumnsIfNeeded(info);
+ return info.maxLocalRetainedHeapSize;
+ }
+ }
+ catch (SnapshotException se)
+ {
+ Logger.getLogger(getClass().getCanonicalName()).warning(MessageUtil.format(
+ Messages.ThreadOverviewQuery_StackFrameLocalIssue, se.getLocalizedMessage()));
}
}
else
@@ -443,6 +460,35 @@
}
}
+ private void calculateStackFrameNodeColumnsIfNeeded(ThreadStackFrameNode info) throws SnapshotException
+ {
+ if (!info.extraColumnsCalculated)
+ {
+ try
+ {
+ @SuppressWarnings("unchecked")
+ List<ThreadStackFrameLocalNode> locals = (List<ThreadStackFrameLocalNode>) getChildren(info);
+ if (locals != null && locals.size() > 0)
+ {
+ long maxLocalRetainedHeapSize = 0, localRetainedHeapSize;
+ for (ThreadStackFrameLocalNode local : locals)
+ {
+ localRetainedHeapSize = snapshot.getRetainedHeapSize(local.objectId);
+ if (localRetainedHeapSize > maxLocalRetainedHeapSize)
+ {
+ maxLocalRetainedHeapSize = localRetainedHeapSize;
+ }
+ }
+ info.maxLocalRetainedHeapSize = new Bytes(maxLocalRetainedHeapSize);
+ }
+ }
+ finally
+ {
+ info.extraColumnsCalculated = true;
+ }
+ }
+ }
+
public IContextObject getContext(final Object row)
{
if (row instanceof ThreadOverviewNode) {
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/Messages.java b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/Messages.java
index c6bd61d..a1ed347 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/Messages.java
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/Messages.java
@@ -595,6 +595,7 @@
public static String ThreadInfoImpl_Column_ContextClassLoader;
public static String ThreadInfoImpl_Column_IsDaemon;
public static String ThreadInfoImpl_Column_Instance;
+ public static String ThreadInfoImpl_Column_MaxLocalRetainedHeap;
public static String ThreadInfoImpl_Column_Name;
public static String ThreadInfoQuery_Requests;
@@ -604,6 +605,7 @@
public static String ThreadInfoQuery_ThreadStack;
public static String ThreadOverviewQuery_SearchingThreads;
+ public static String ThreadOverviewQuery_StackFrameLocalIssue;
public static String ThreadOverviewQuery_ThreadDetails;
public static String ThreadStackQuery_Column_ObjectStackFrame;
diff --git a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/messages.properties b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/messages.properties
index 906ad49..310a221 100644
--- a/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/messages.properties
+++ b/plugins/org.eclipse.mat.api/src/org/eclipse/mat/internal/messages.properties
@@ -526,6 +526,7 @@
ThreadInfoImpl_Column_ContextClassLoader=Context Class Loader
ThreadInfoImpl_Column_IsDaemon=Is Daemon
ThreadInfoImpl_Column_Instance=Instance
+ThreadInfoImpl_Column_MaxLocalRetainedHeap=Max. Local Retained Heap
ThreadInfoImpl_Column_Name=Name
ThreadInfoQuery_Requests=Requests
ThreadInfoQuery_ThreadDetails=Thread Details
@@ -533,6 +534,7 @@
ThreadInfoQuery_ThreadProperties=Thread Properties
ThreadInfoQuery_ThreadStack=Thread Stack
ThreadOverviewQuery_SearchingThreads=Searching Threads...
+ThreadOverviewQuery_StackFrameLocalIssue=Could not evaluate stack frame local: {0}
ThreadOverviewQuery_ThreadDetails=Thread Details
ThreadStackQuery_Column_ObjectStackFrame=Object / Stack Frame
ThreadStackQuery_Label_Local=<local>