Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMassimiliano Mantione <massi@mono-cvs.ximian.com>2008-12-01 21:23:27 +0300
committerMassimiliano Mantione <massi@mono-cvs.ximian.com>2008-12-01 21:23:27 +0300
commit48df9f88661bae8fd2f5645da40a797ad86616ee (patch)
tree82236d685d742bb71a7ab48ffab596eef7555172 /Mono.Profiler
parent5597aebf54503c7ff6293a1688424cc6263c9edc (diff)
Handle object allocator method and call stack in heap profiling.
svn path=/trunk/mono-tools/; revision=120368
Diffstat (limited to 'Mono.Profiler')
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/ChangeLog11
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/HeapExplorerTreeModel.cs46
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/HeapSnapshotExplorer.cs237
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/LoadedClassChooser.cs37
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.HeapSnapshotExplorer.cs1
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.LoadedClassChooser.cs2
-rw-r--r--Mono.Profiler/heap-snapshot-explorer/gtk-gui/gui.stetic3
-rw-r--r--Mono.Profiler/profiler-decoder-library/ChangeLog17
-rw-r--r--Mono.Profiler/profiler-decoder-library/ObjectModel.cs445
9 files changed, 688 insertions, 111 deletions
diff --git a/Mono.Profiler/heap-snapshot-explorer/ChangeLog b/Mono.Profiler/heap-snapshot-explorer/ChangeLog
index 9a720d31..86224c01 100644
--- a/Mono.Profiler/heap-snapshot-explorer/ChangeLog
+++ b/Mono.Profiler/heap-snapshot-explorer/ChangeLog
@@ -1,3 +1,14 @@
+2008-12-01 Massimiliano Mantione <massi@ximian.com>
+ * HeapExplorerTreeModel.cs: Linked all root nodes n a list, so that it
+ is possible to find the allocation event of a given heap object (now
+ IRootNode implements the ProviderOfPreviousAllocationsSets interface).
+ * HeapSnapshotExplorer.cs: Created class StatisticsNodeMenuHandler
+ (implemented for classes, methods and call stacks) to rationalize the
+ hadling of menus), and turned ClassStatisticsNode into a more general
+ StatisticsNode because now it works with all the three abov concepts.
+ * LoadedClassChooser.cs: Make the dialog work with methods and call
+ stacks instead of just classes.
+
2008-11-03 Massimiliano Mantione <massi@ximian.com>
* HeapExplorerTreeModel.cs: Massive refactory of "Node" class, making
it generic in terms of the node contents (HeapObject-AllocatedObject).
diff --git a/Mono.Profiler/heap-snapshot-explorer/HeapExplorerTreeModel.cs b/Mono.Profiler/heap-snapshot-explorer/HeapExplorerTreeModel.cs
index 64277c9c..8455be24 100644
--- a/Mono.Profiler/heap-snapshot-explorer/HeapExplorerTreeModel.cs
+++ b/Mono.Profiler/heap-snapshot-explorer/HeapExplorerTreeModel.cs
@@ -37,12 +37,13 @@ namespace Mono.Profiler
string Description {get;}
TreeIter TreeIter {get;}
INode Parent {get;}
- INode Root {get;}
+ IRootNode Root {get;}
string Count {get;}
string AllocatedBytes {get;}
Menu ContextMenu {get;}
}
- public interface IRootNode : INode {
+ public interface IRootNode : INode, ProviderOfPreviousAllocationsSets {
+ AllocationsNode PreviousAllocationsNode {get;}
}
public abstract class Node<HI> : INode where HI : IHeapItem {
@@ -90,9 +91,26 @@ namespace Mono.Profiler
}
}
}
- INode INode.Root {
+ IRootNode INode.Root {
get {
- return Root;
+ return (IRootNode) Root;
+ }
+ }
+
+ AllocationsNode previousAllocationsNode;
+ public AllocationsNode PreviousAllocationsNode {
+ get {
+ return previousAllocationsNode;
+ }
+ }
+ public IEnumerable<HeapItemSet<AllocatedObject>> PreviousAllocationsSets () {
+ AllocationsNode currentNode = this.PreviousAllocationsNode;
+ while (currentNode != null) {
+ if (currentNode.Items == null) {
+ currentNode.ReadEvents ();
+ }
+ yield return currentNode.Items;
+ currentNode = currentNode.PreviousAllocationsNode;
}
}
@@ -153,9 +171,10 @@ namespace Mono.Profiler
public abstract Menu ContextMenu {get;}
- protected Node (HeapExplorerTreeModel model, Node<HI> parent) {
+ protected Node (HeapExplorerTreeModel model, Node<HI> parent, AllocationsNode previousAllocationsNode) {
this.model = model;
this.parent = parent;
+ this.previousAllocationsNode = previousAllocationsNode;
this.treeIter = HandleNodeCreation ();
}
}
@@ -221,7 +240,7 @@ namespace Mono.Profiler
}
}
- public SnapshotNode (HeapExplorerTreeModel model, SeekableLogFileReader.Block heapBlock) : base (model, null) {
+ public SnapshotNode (HeapExplorerTreeModel model, SeekableLogFileReader.Block heapBlock, AllocationsNode previousAllocationsNode) : base (model, null, previousAllocationsNode) {
this.heapBlock = heapBlock;
this.items = null;
this.snapshot = null;
@@ -283,7 +302,7 @@ namespace Mono.Profiler
}
}
- public AllocationsNode (HeapExplorerTreeModel model, SeekableLogFileReader.Block[] eventBlocks) : base (model, null) {
+ public AllocationsNode (HeapExplorerTreeModel model, SeekableLogFileReader.Block[] eventBlocks, AllocationsNode previousAllocationsNode) : base (model, null, previousAllocationsNode) {
this.eventBlocks = eventBlocks;
this.items = null;
}
@@ -297,7 +316,7 @@ namespace Mono.Profiler
}
}
- protected SubSetNode (HeapExplorerTreeModel model, Node<HI> parent, HeapItemSet<HI> items) : base (model, parent) {
+ protected SubSetNode (HeapExplorerTreeModel model, Node<HI> parent, HeapItemSet<HI> items) : base (model, parent, null) {
this.items = items;
}
}
@@ -402,10 +421,10 @@ namespace Mono.Profiler
}
}
- AllocationsNode CreateAllocationsNode (List<SeekableLogFileReader.Block> eventBlocks) {
+ AllocationsNode CreateAllocationsNode (List<SeekableLogFileReader.Block> eventBlocks, AllocationsNode previousAllocationsNode) {
AllocationsNode node;
if (eventBlocks.Count > 0) {
- node = new AllocationsNode (this, eventBlocks.ToArray ());
+ node = new AllocationsNode (this, eventBlocks.ToArray (), previousAllocationsNode);
rootNodes.Add (node);
} else {
node = null;
@@ -416,12 +435,13 @@ namespace Mono.Profiler
public void Initialize () {
List<SeekableLogFileReader.Block> eventBlocks = new List<SeekableLogFileReader.Block> ();
+ AllocationsNode previousAllocationsNode = null;
Reset ();
foreach (SeekableLogFileReader.Block block in reader.Blocks) {
if (block.Code == BlockCode.HEAP_DATA) {
- CreateAllocationsNode (eventBlocks);
- SnapshotNode node = new SnapshotNode (this, block);
+ previousAllocationsNode = CreateAllocationsNode (eventBlocks, previousAllocationsNode);
+ SnapshotNode node = new SnapshotNode (this, block, previousAllocationsNode);
rootNodes.Add (node);
} else if (block.Code == BlockCode.EVENTS) {
eventBlocks.Add (block);
@@ -435,7 +455,7 @@ namespace Mono.Profiler
reader.ReadBlock (block).Decode (heapEventProcessor, reader);
}
}
- CreateAllocationsNode (eventBlocks);
+ CreateAllocationsNode (eventBlocks, previousAllocationsNode);
}
public void Reset () {
diff --git a/Mono.Profiler/heap-snapshot-explorer/HeapSnapshotExplorer.cs b/Mono.Profiler/heap-snapshot-explorer/HeapSnapshotExplorer.cs
index 6d0ff0eb..3f935742 100644
--- a/Mono.Profiler/heap-snapshot-explorer/HeapSnapshotExplorer.cs
+++ b/Mono.Profiler/heap-snapshot-explorer/HeapSnapshotExplorer.cs
@@ -29,47 +29,220 @@ namespace Mono.Profiler
}
}
+ StatisticsNode currentListSelection;
+ public StatisticsNode CurrentListSelection {
+ get {
+ return currentListSelection;
+ }
+ }
+
+ abstract class StatisticsNodeMenuHandler {
+ HeapSnapshotExplorer explorer;
+ public HeapSnapshotExplorer Explorer {
+ get {
+ return explorer;
+ }
+ }
+ protected abstract Menu GetContextMenu ();
+ public void ShowContextMenu () {
+ if ((explorer.CurrentSelection != null) && (explorer.CurrentListSelection != null)) {
+ Menu contextMenu = GetContextMenu ();
+ if (contextMenu != null) {
+ contextMenu.Popup ();
+ }
+ }
+ }
+ protected void FilterCurrentSet<HI> (IHeapItemFilter<HI> filter) where HI : IHeapItem {
+ HeapExplorerTreeModel.Node<HI> node = (HeapExplorerTreeModel.Node<HI>) Explorer.CurrentSelection;
+ node.Filter (filter);
+ }
+ protected StatisticsNodeMenuHandler (HeapSnapshotExplorer explorer) {
+ this.explorer = explorer;
+ }
+ }
+ class StatisticsNodeMenuHandlerForClasses : StatisticsNodeMenuHandler {
+ void FilterCurrentSetByCurrentClass () {
+ LoadedClass currentClass = (LoadedClass) Explorer.CurrentListSelection.Statistics.Subject;
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<HeapObject>) {
+ FilterCurrentSet<HeapObject> (new HeapItemIsOfClass<HeapObject> (currentClass));
+ }
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<AllocatedObject>) {
+ FilterCurrentSet<AllocatedObject> (new HeapItemIsOfClass<AllocatedObject> (currentClass));
+ }
+ }
+
+ Menu menu;
+ protected override Menu GetContextMenu () {
+ return menu;
+ }
+ public StatisticsNodeMenuHandlerForClasses (HeapSnapshotExplorer explorer) : base (explorer) {
+ menu = new Menu ();
+ MenuItem menuItem;
+ menuItem = new MenuItem ("Filter current set by this class");
+ menuItem.Activated += delegate {
+ FilterCurrentSetByCurrentClass ();
+ };
+ menu.Add (menuItem);
+ menuItem = new MenuItem ("Show statistics by caller method");
+ menuItem.Activated += delegate {
+ explorer.FillStatisticsListWithMethodData ();
+ };
+ menu.Add (menuItem);
+ menu.ShowAll ();
+ }
+ }
+ class StatisticsNodeMenuHandlerForMethods : StatisticsNodeMenuHandler {
+ void FilterCurrentSetByCurrentMethod () {
+ LoadedMethod currentMethod = (LoadedMethod) Explorer.CurrentListSelection.Statistics.Subject;
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<HeapObject>) {
+ FilterCurrentSet<HeapObject> (new HeapItemWasAllocatedByMethod<HeapObject> (currentMethod));
+ }
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<AllocatedObject>) {
+ FilterCurrentSet<AllocatedObject> (new HeapItemWasAllocatedByMethod<AllocatedObject> (currentMethod));
+ }
+ }
+
+ Menu menu;
+ protected override Menu GetContextMenu () {
+ return menu;
+ }
+ public StatisticsNodeMenuHandlerForMethods (HeapSnapshotExplorer explorer) : base (explorer) {
+ menu = new Menu ();
+ MenuItem menuItem;
+ menuItem = new MenuItem ("Filter current set by this method");
+ menuItem.Activated += delegate {
+ FilterCurrentSetByCurrentMethod ();
+ };
+ menu.Add (menuItem);
+ menuItem = new MenuItem ("Show statistics by call stack");
+ menuItem.Activated += delegate {
+ explorer.FillStatisticsListWithCallStackData ();
+ };
+ menu.Add (menuItem);
+ menu.ShowAll ();
+ }
+ }
+ class StatisticsNodeMenuHandlerForCallStacks : StatisticsNodeMenuHandler {
+ void FilterCurrentSetByCurrentCallStack () {
+ StackTrace currentCallStack = (StackTrace) Explorer.CurrentListSelection.Statistics.Subject;
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<HeapObject>) {
+ FilterCurrentSet<HeapObject> (new FilterHeapItemByAllocationCallStack<HeapObject> (currentCallStack));
+ }
+ if (Explorer.CurrentSelection is HeapExplorerTreeModel.Node<AllocatedObject>) {
+ FilterCurrentSet<AllocatedObject> (new FilterHeapItemByAllocationCallStack<AllocatedObject> (currentCallStack));
+ }
+ }
+
+ Menu menu;
+ protected override Menu GetContextMenu () {
+ return menu;
+ }
+ public StatisticsNodeMenuHandlerForCallStacks (HeapSnapshotExplorer explorer) : base (explorer) {
+ menu = new Menu ();
+ MenuItem menuItem;
+ menuItem = new MenuItem ("Filter current set by this call stack");
+ menuItem.Activated += delegate {
+ FilterCurrentSetByCurrentCallStack ();
+ };
+ menu.Add (menuItem);
+ menu.ShowAll ();
+ }
+ }
+
+ StatisticsNodeMenuHandler currentListMenuHandler;
+ StatisticsNodeMenuHandlerForClasses listMenuHandlerForClasses;
+ StatisticsNodeMenuHandlerForMethods listMenuHandlerForMethods;
+ StatisticsNodeMenuHandlerForCallStacks listMenuHandlerForCallStacks;
+ void FillStatisticsListWithClassData () {
+ currentListMenuHandler = listMenuHandlerForClasses;
+ if (currentSelection != null) {
+ if (currentSelection.Items != null) {
+ FillTreeViewWithStatistics (PerClassStatistics, currentSelection.Items.ClassStatistics);
+ } else {
+ PerClassStatistics.NodeStore.Clear ();
+ }
+ }
+ currentListSelection = null;
+ }
+ void FillStatisticsListWithMethodData () {
+ currentListMenuHandler = listMenuHandlerForMethods;
+ if (currentSelection != null) {
+ if (currentSelection.Items != null) {
+ if (! currentSelection.Items.ObjectAllocationsArePresent) {
+ currentSelection.Items.FindObjectAllocations (currentSelection.Root);
+ }
+ FillTreeViewWithStatistics (PerClassStatistics, currentSelection.Items.AllocatorMethodStatistics);
+ } else {
+ PerClassStatistics.NodeStore.Clear ();
+ }
+ }
+ currentListSelection = null;
+ }
+ void FillStatisticsListWithCallStackData () {
+ currentListMenuHandler = listMenuHandlerForCallStacks;
+ if (currentSelection != null) {
+ if (currentSelection.Items != null) {
+ if (! currentSelection.Items.ObjectAllocationsArePresent) {
+ currentSelection.Items.FindObjectAllocations (currentSelection.Root);
+ }
+ FillTreeViewWithStatistics (PerClassStatistics, currentSelection.Items.AllocationCallStackStatistics);
+ } else {
+ PerClassStatistics.NodeStore.Clear ();
+ }
+ }
+ currentListSelection = null;
+ }
+
[Gtk.TreeNode (ListOnly=true)]
- public class ClassStatisticsNode : Gtk.TreeNode {
- HeapItemSetClassStatistics classStatistics;
- public HeapItemSetClassStatistics ClassStatistics {
+ public class StatisticsNode : Gtk.TreeNode {
+ IHeapItemSetStatisticsBySubject statistics;
+ public IHeapItemSetStatisticsBySubject Statistics {
get {
- return classStatistics;
+ return statistics;
}
}
- public string Name {
+ public string Description {
get {
- return classStatistics.Class.Name;
+ return statistics.Subject.Description;
+ }
+ }
+ public uint ItemsCount {
+ get {
+ return statistics.ItemsCount;
}
}
public uint AllocatedBytes {
get {
- return classStatistics.AllocatedBytes;
+ return statistics.AllocatedBytes;
}
}
- public ClassStatisticsNode (HeapItemSetClassStatistics classStatistics) {
- this.classStatistics = classStatistics;
+ public StatisticsNode (IHeapItemSetStatisticsBySubject statistics) {
+ this.statistics = statistics;
}
}
- public static void PrepareTreeViewForClassStatistics (NodeView view) {
- view.AppendColumn ("Name", new Gtk.CellRendererText (), delegate (TreeViewColumn column, CellRenderer cell, ITreeNode node) {
- ClassStatisticsNode classNode = (ClassStatisticsNode) node;
- ((CellRendererText) cell).Markup = classNode.Name;
+ public static void PrepareTreeViewForStatisticsDisplay (NodeView view) {
+ view.AppendColumn ("Description", new Gtk.CellRendererText (), delegate (TreeViewColumn column, CellRenderer cell, ITreeNode treeNode) {
+ StatisticsNode node = (StatisticsNode) treeNode;
+ ((CellRendererText) cell).Markup = node.Description;
+ });
+ view.AppendColumn ("Object count", new Gtk.CellRendererText (), delegate (TreeViewColumn column, CellRenderer cell, ITreeNode treeNode) {
+ StatisticsNode node = (StatisticsNode) treeNode;
+ ((CellRendererText) cell).Markup = node.ItemsCount.ToString ();
});
- view.AppendColumn ("Allocated bytes", new Gtk.CellRendererText (), delegate (TreeViewColumn column, CellRenderer cell, ITreeNode node) {
- ClassStatisticsNode classNode = (ClassStatisticsNode) node;
- ((CellRendererText) cell).Markup = classNode.AllocatedBytes.ToString ();
+ view.AppendColumn ("Allocated bytes", new Gtk.CellRendererText (), delegate (TreeViewColumn column, CellRenderer cell, ITreeNode treeNode) {
+ StatisticsNode node = (StatisticsNode) treeNode;
+ ((CellRendererText) cell).Markup = node.AllocatedBytes.ToString ();
});
- view.NodeStore = new Gtk.NodeStore (typeof (ClassStatisticsNode));
+ view.NodeStore = new Gtk.NodeStore (typeof (StatisticsNode));
}
- public static void FillTreeViewWithClassStatistics (NodeView view, HeapItemSetClassStatistics[] classes) {
+ public static void FillTreeViewWithStatistics (NodeView view, IHeapItemSetStatisticsBySubject[] statistics) {
view.NodeStore.Clear ();
- foreach (HeapItemSetClassStatistics c in classes) {
- view.NodeStore.AddNode (new ClassStatisticsNode (c));
+ foreach (IHeapItemSetStatisticsBySubject s in statistics) {
+ view.NodeStore.AddNode (new StatisticsNode (s));
}
}
@@ -291,20 +464,20 @@ namespace Mono.Profiler
};
filterAllocationSetUsingSelection.Append (menuItem);
- PrepareTreeViewForClassStatistics (PerClassStatistics);
+ PrepareTreeViewForStatisticsDisplay (PerClassStatistics);
+ PerClassStatistics.NodeSelection.Changed += delegate (object o, EventArgs args) {
+ currentListSelection = (StatisticsNode) PerClassStatistics.NodeSelection.SelectedNode;
+ };
+ listMenuHandlerForClasses = new StatisticsNodeMenuHandlerForClasses (this);
+ listMenuHandlerForMethods = new StatisticsNodeMenuHandlerForMethods (this);
+ listMenuHandlerForCallStacks = new StatisticsNodeMenuHandlerForCallStacks (this);
Tree.Selection.Changed += delegate (object o, EventArgs args) {
TreeSelection selection = (TreeSelection) o;
TreeIter iter;
if (selection.GetSelected (out iter)) {
currentSelection = (HeapExplorerTreeModel.INode) Tree.Model.GetValue (iter, 0);
- if (currentSelection != null) {
- if (currentSelection.Items != null) {
- FillTreeViewWithClassStatistics (PerClassStatistics, currentSelection.Items.ClassStatistics);
- } else {
- PerClassStatistics.NodeStore.Clear ();
- }
- }
+ FillStatisticsListWithClassData ();
}
};
@@ -501,5 +674,13 @@ namespace Mono.Profiler
}
}
}
+
+ [GLib.ConnectBefore]
+ protected virtual void OnListButtonPress (object o, Gtk.ButtonPressEventArgs args)
+ {
+ if (args.Event.Button == 3) {
+ currentListMenuHandler.ShowContextMenu ();
+ }
+ }
}
}
diff --git a/Mono.Profiler/heap-snapshot-explorer/LoadedClassChooser.cs b/Mono.Profiler/heap-snapshot-explorer/LoadedClassChooser.cs
index 764885a1..5b779c3c 100644
--- a/Mono.Profiler/heap-snapshot-explorer/LoadedClassChooser.cs
+++ b/Mono.Profiler/heap-snapshot-explorer/LoadedClassChooser.cs
@@ -11,35 +11,35 @@ namespace Mono.Profiler
{
public partial class LoadedClassChooser : Gtk.Dialog
{
- LoadedClass result;
- public LoadedClass Result {
+ IHeapItemSetStatisticsSubject result;
+ public IHeapItemSetStatisticsSubject Result {
get {
return result;
}
}
- HeapItemSetClassStatistics currentSelection;
+ IHeapItemSetStatisticsBySubject currentSelection;
LoadedClassChooser()
{
this.Build();
- HeapSnapshotExplorer.PrepareTreeViewForClassStatistics (ClassList);
+ HeapSnapshotExplorer.PrepareTreeViewForStatisticsDisplay (ClassList);
ClassList.NodeSelection.Changed += new EventHandler (OnSelectionChanged);
currentSelection = null;
}
void OnSelectionChanged (object o, System.EventArgs args) {
Gtk.NodeSelection selection = (Gtk.NodeSelection) o;
- HeapSnapshotExplorer.ClassStatisticsNode node = (HeapSnapshotExplorer.ClassStatisticsNode) selection.SelectedNode;
+ HeapSnapshotExplorer.StatisticsNode node = (HeapSnapshotExplorer.StatisticsNode) selection.SelectedNode;
if (node != null) {
- currentSelection = node.ClassStatistics;
+ currentSelection = node.Statistics;
} else {
currentSelection = null;
}
}
- void FillList (HeapItemSetClassStatistics[] classes) {
- HeapSnapshotExplorer.FillTreeViewWithClassStatistics (ClassList, classes);
+ void FillList (IHeapItemSetStatisticsBySubject[] statistics) {
+ HeapSnapshotExplorer.FillTreeViewWithStatistics (ClassList, statistics);
currentSelection = null;
}
@@ -51,7 +51,7 @@ namespace Mono.Profiler
protected virtual void OnOK (object sender, System.EventArgs e)
{
if (currentSelection != null) {
- result = currentSelection.Class;
+ result = currentSelection.Subject;
} else {
result = null;
}
@@ -59,12 +59,13 @@ namespace Mono.Profiler
static LoadedClassChooser chooser;
- public static LoadedClass ChooseClass (HeapItemSetClassStatistics[] classes) {
- LoadedClass result;
+ static IHeapItemSetStatisticsSubject ChooseSubject (IHeapItemSetStatisticsBySubject[] subjects, string subjectName) {
+ IHeapItemSetStatisticsSubject result;
if (chooser == null) {
chooser = new LoadedClassChooser ();
}
- chooser.FillList (classes);
+ chooser.Title = "Choose " + subjectName;
+ chooser.FillList (subjects);
ResponseType response = (ResponseType) chooser.Run ();
if (response == ResponseType.Ok) {
result = chooser.result;
@@ -74,5 +75,17 @@ namespace Mono.Profiler
chooser.Hide ();
return result;
}
+ public static LoadedClass ChooseClass (IHeapItemSetStatisticsBySubject[] subjects) {
+ IHeapItemSetStatisticsSubject result = ChooseSubject (subjects, "class");
+ return result as LoadedClass;
+ }
+ public static LoadedMethod ChooseMethod (IHeapItemSetStatisticsBySubject[] subjects) {
+ IHeapItemSetStatisticsSubject result = ChooseSubject (subjects, "method");
+ return result as LoadedMethod;
+ }
+ public static StackTrace ChooseCallStack (IHeapItemSetStatisticsBySubject[] subjects) {
+ IHeapItemSetStatisticsSubject result = ChooseSubject (subjects, "call stack");
+ return result as StackTrace;
+ }
}
}
diff --git a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.HeapSnapshotExplorer.cs b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.HeapSnapshotExplorer.cs
index 047a8e3f..5bc2e238 100644
--- a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.HeapSnapshotExplorer.cs
+++ b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.HeapSnapshotExplorer.cs
@@ -63,6 +63,7 @@ namespace Mono.Profiler {
}
this.Show();
this.Tree.ButtonPressEvent += new Gtk.ButtonPressEventHandler(this.OnTreeButtonPress);
+ this.PerClassStatistics.ButtonPressEvent += new Gtk.ButtonPressEventHandler(this.OnListButtonPress);
}
}
}
diff --git a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.LoadedClassChooser.cs b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.LoadedClassChooser.cs
index 4e0cf4c2..00ad64f1 100644
--- a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.LoadedClassChooser.cs
+++ b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/Mono.Profiler.LoadedClassChooser.cs
@@ -25,7 +25,7 @@ namespace Mono.Profiler {
Stetic.Gui.Initialize(this);
// Widget Mono.Profiler.LoadedClassChooser
this.Name = "Mono.Profiler.LoadedClassChooser";
- this.Title = Mono.Unix.Catalog.GetString("Choose class");
+ this.Title = Mono.Unix.Catalog.GetString("Choose item");
this.WindowPosition = ((Gtk.WindowPosition)(4));
this.Modal = true;
this.HasSeparator = false;
diff --git a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/gui.stetic b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/gui.stetic
index 014db4ec..45a15c39 100644
--- a/Mono.Profiler/heap-snapshot-explorer/gtk-gui/gui.stetic
+++ b/Mono.Profiler/heap-snapshot-explorer/gtk-gui/gui.stetic
@@ -65,6 +65,7 @@
<property name="CanFocus">True</property>
<property name="ShowScrollbars">True</property>
<property name="HeadersClickable">True</property>
+ <signal name="ButtonPressEvent" handler="OnListButtonPress" />
</widget>
</child>
</widget>
@@ -74,7 +75,7 @@
</widget>
<widget class="Gtk.Dialog" id="Mono.Profiler.LoadedClassChooser" design-size="400 300">
<property name="MemberName" />
- <property name="Title" translatable="yes">Choose class</property>
+ <property name="Title" translatable="yes">Choose item</property>
<property name="WindowPosition">CenterOnParent</property>
<property name="Modal">True</property>
<property name="Buttons">2</property>
diff --git a/Mono.Profiler/profiler-decoder-library/ChangeLog b/Mono.Profiler/profiler-decoder-library/ChangeLog
index e33ea755..2c41120e 100644
--- a/Mono.Profiler/profiler-decoder-library/ChangeLog
+++ b/Mono.Profiler/profiler-decoder-library/ChangeLog
@@ -1,3 +1,20 @@
+2008-12-01 Massimiliano Mantione <massi@ximian.com>
+ * ObjectModel.cs:
+ - Added interface IHeapItemSetStatisticsSubject to represents criteria
+ by which heap item sets can be examined, implemented by LoadedClass,
+ StackTrace and LoadedMethod.
+ - Added methods to IHeapItem (and implementations) to get the item
+ allocator method and call stack.
+ - Added filter classes (FilterHeapItemByAllocatorMethod,
+ HeapItemWasAllocatedByMethod, FilterHeapItemByAllocationCallStack...)
+ to filter by those criteria.
+ - Added abstract class HeapItemSetStatisticsBySubject to factor the
+ building of statistics (implemented by HeapItemSetClassStatistics,
+ HeapItemSetMethodStatistics and HeapItemSetCallStackStatistics).
+ - Inside HeapItemSet added the BuildStatistics generic method (which
+ works with the previous classes).
+ - Inside HeapItemSet added the FindObjectAllocations functionality.
+
2008-11-03 Massimiliano Mantione <massi@ximian.com>
* BaseTypes.cs: Added "header start time" property to the event
handler, so that there is always a "context" of when the event block
diff --git a/Mono.Profiler/profiler-decoder-library/ObjectModel.cs b/Mono.Profiler/profiler-decoder-library/ObjectModel.cs
index 1a6d6b20..937ecc99 100644
--- a/Mono.Profiler/profiler-decoder-library/ObjectModel.cs
+++ b/Mono.Profiler/profiler-decoder-library/ObjectModel.cs
@@ -30,7 +30,7 @@ using System.IO;
using System.Collections.Generic;
namespace Mono.Profiler {
- public class LoadedClass : BaseLoadedClass {
+ public class LoadedClass : BaseLoadedClass, IHeapItemSetStatisticsSubject {
uint allocatedBytes;
public uint AllocatedBytes {
get {
@@ -47,6 +47,12 @@ namespace Mono.Profiler {
return a.AllocatedBytes.CompareTo (b.AllocatedBytes);
};
+ string IHeapItemSetStatisticsSubject.Description {
+ get {
+ return Name;
+ }
+ }
+
internal void InstanceCreated (uint size, LoadedMethod method, bool jitTime, StackTrace stackTrace) {
allocatedBytes += size;
currentlyAllocatedBytes += size;
@@ -211,6 +217,8 @@ namespace Mono.Profiler {
}
}
+ public static readonly LoadedClass LoadedClassUnavailable = new LoadedClass (0, "(CLASS UNAVAILABLE)", 0);
+
public LoadedClass (uint id, string name, uint size): base (id, name, size) {
allocatedBytes = 0;
currentlyAllocatedBytes = 0;
@@ -218,7 +226,7 @@ namespace Mono.Profiler {
}
}
- public class StackTrace {
+ public class StackTrace : IHeapItemSetStatisticsSubject {
LoadedMethod topMethod;
public LoadedMethod TopMethod {
get {
@@ -250,7 +258,32 @@ namespace Mono.Profiler {
}
}
- static uint nextFreeId = 1;
+ public string FullDescription {
+ get {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder ();
+ sb.Append ("CallStack of id ");
+ sb.Append (id);
+ sb.Append ('\n');
+
+ StackTrace currentFrame = this;
+ while (currentFrame != null) {
+ StackTrace nextFrame = currentFrame.Caller;
+ sb.Append (" ");
+ sb.Append (currentFrame.TopMethod.Name);
+ if (nextFrame != null) {
+ sb.Append ('\n');
+ }
+ currentFrame = nextFrame;
+ }
+
+ return sb.ToString ();
+ }
+ }
+ string IHeapItemSetStatisticsSubject.Description {
+ get {
+ return FullDescription;
+ }
+ }
StackTrace (LoadedMethod topMethod, StackTrace caller, bool methodIsBeingJitted) {
this.topMethod = topMethod;
@@ -286,6 +319,15 @@ namespace Mono.Profiler {
return NewStackTrace (stack.StackTop);
}
+ static uint nextFreeId;
+ static Dictionary<uint,List<StackTrace>> [] tracesByLevel;
+ public static readonly StackTrace StackTraceUnavailable;
+ static StackTrace () {
+ nextFreeId = 0;
+ tracesByLevel = new Dictionary<uint,List<StackTrace>> [64];
+ StackTraceUnavailable = NewStackTrace (CallStack.StackFrame.StackFrameUnavailable);
+ }
+
static StackTrace NewStackTrace (CallStack.StackFrame frame) {
if (frame == null) {
return null;
@@ -322,8 +364,6 @@ namespace Mono.Profiler {
traces.Add (result);
return result;
}
-
- static Dictionary<uint,List<StackTrace>> [] tracesByLevel = new Dictionary<uint,List<StackTrace>> [64];
}
class CallStack {
@@ -375,6 +415,8 @@ namespace Mono.Profiler {
level = (caller != null) ? (caller.Level + 1) : 1;
}
+ public static readonly StackFrame StackFrameUnavailable = new StackFrame (LoadedMethod.LoadedMethodForStackTraceUnavailable, 0, false, null);
+
internal StackFrame (LoadedMethod method, ulong startCounter, bool isBeingJitted, StackFrame caller) {
this.method = method;
this.startCounter = startCounter;
@@ -587,7 +629,7 @@ namespace Mono.Profiler {
StatisticalHitItemCallCounts CallCounts {get;}
}
- public class LoadedMethod : BaseLoadedMethod<LoadedClass>, IStatisticalHitItem {
+ public class LoadedMethod : BaseLoadedMethod<LoadedClass>, IStatisticalHitItem, IHeapItemSetStatisticsSubject {
ulong clicks;
public ulong Clicks {
get {
@@ -604,6 +646,12 @@ namespace Mono.Profiler {
return (a.Clicks - a.CalledClicks).CompareTo (b.Clicks - b.CalledClicks);
};
+ string IHeapItemSetStatisticsSubject.Description {
+ get {
+ return Name;
+ }
+ }
+
ulong calledClicks;
public ulong CalledClicks {
get {
@@ -785,6 +833,9 @@ namespace Mono.Profiler {
calledClicks += clicks;
}
+ public static readonly LoadedMethod LoadedMethodUnavailable = new LoadedMethod (0, LoadedClass.LoadedClassUnavailable, "(METHOD UNAVAILABLE)");
+ public static readonly LoadedMethod LoadedMethodForStackTraceUnavailable = new LoadedMethod (0, LoadedClass.LoadedClassUnavailable, "(CALL STACK UNAVAILABLE)");
+
public LoadedMethod (uint id, LoadedClass c, string name): base (id, c, name) {
clicks = 0;
calledClicks = 0;
@@ -909,9 +960,47 @@ namespace Mono.Profiler {
}
public interface IHeapItem : IAllocatedObject<LoadedClass> {
+ LoadedMethod AllocatorMethod {get;}
+ StackTrace AllocationCallStack {get;}
+ bool AllocationHappenedAtJitTime {get;}
}
public class HeapObject : BaseHeapObject<HeapObject,LoadedClass>, IHeapItem {
+ AllocatedObject allocation;
+ public AllocatedObject Allocation {
+ get {
+ return allocation;
+ }
+ set {
+ allocation = value;
+ if ((allocation.Class != Class) || (allocation.ID != ID)) {
+ throw new Exception (String.Format ("Cannot accept allocation of class {0} and ID {1} for object of class {2} and ID {3}", allocation.Class, allocation.ID, Class, ID));
+ }
+ }
+ }
+ public void FindAllocation (ProviderOfPreviousAllocationsSets previousSetsProvider) {
+ foreach (HeapItemSet<AllocatedObject> allocations in previousSetsProvider.PreviousAllocationsSets ()) {
+ allocation = allocations [ID];
+ if (allocation != null) {
+ return;
+ }
+ }
+ }
+ public LoadedMethod AllocatorMethod {
+ get {
+ return allocation != null ? allocation.AllocatorMethod : null;
+ }
+ }
+ public StackTrace AllocationCallStack {
+ get {
+ return allocation != null ? allocation.Trace : null;
+ }
+ }
+ public bool AllocationHappenedAtJitTime {
+ get {
+ return allocation != null ? allocation.AllocationHappenedAtJitTime : false;
+ }
+ }
public HeapObject (ulong ID) : base (ID) {}
}
@@ -940,18 +1029,33 @@ namespace Mono.Profiler {
return caller;
}
}
+ public LoadedMethod AllocatorMethod {
+ get {
+ return caller;
+ }
+ }
bool jitTime;
public bool JitTime {
get {
return jitTime;
}
}
+ public bool AllocationHappenedAtJitTime {
+ get {
+ return jitTime;
+ }
+ }
StackTrace trace;
public StackTrace Trace {
get {
return trace;
}
}
+ public StackTrace AllocationCallStack {
+ get {
+ return trace;
+ }
+ }
public AllocatedObject (ulong id, LoadedClass c, uint size, LoadedMethod caller, bool jitTime, StackTrace trace) {
this.id = id;
@@ -1072,12 +1176,69 @@ namespace Mono.Profiler {
}
}
- protected FilterHeapItemByClass (LoadedClass c, string description) {
+ public FilterHeapItemByClass (LoadedClass c, string description) {
this.c = c;
this.description = description;
}
}
+ public abstract class FilterHeapItemByAllocatorMethod<HI> : IHeapItemFilter<HI> where HI : IHeapItem {
+ protected LoadedMethod allocatorMethod;
+ public LoadedMethod AllocatorMethod {
+ get {
+ return allocatorMethod;
+ }
+ }
+
+ public abstract bool Filter (HI heapItem);
+
+ string description;
+ public string Description {
+ get {
+ return description;
+ }
+ }
+
+ protected FilterHeapItemByAllocatorMethod (LoadedMethod allocatorMethod, string description) {
+ this.allocatorMethod = allocatorMethod;
+ this.description = description;
+ }
+ }
+
+ public class HeapItemWasAllocatedByMethod<HI> : FilterHeapItemByAllocatorMethod<HI> where HI : IHeapItem {
+ public override bool Filter (HI heapItem) {
+ return heapItem.AllocatorMethod == AllocatorMethod;
+ }
+
+ public HeapItemWasAllocatedByMethod (LoadedMethod allocatorMethod) : base (allocatorMethod, String.Format ("Object was allocated by {0}", allocatorMethod.Name)) {
+ }
+ }
+
+ public class FilterHeapItemByAllocationCallStack<HI> : IHeapItemFilter<HI> where HI : IHeapItem {
+ protected StackTrace allocationCallStack;
+ public StackTrace AllocationCallStack {
+ get {
+ return allocationCallStack;
+ }
+ }
+
+ public bool Filter (HI heapItem) {
+ return heapItem.AllocationCallStack == allocationCallStack;
+ }
+
+ string description;
+ public string Description {
+ get {
+ return description;
+ }
+ }
+
+ public FilterHeapItemByAllocationCallStack (StackTrace allocationCallStack) {
+ this.allocationCallStack = allocationCallStack;
+ this.description = String.Format ("Allocation has call stack:\n{0}", allocationCallStack.FullDescription);
+ }
+ }
+
public class HeapItemIsOfClass<HI> : FilterHeapItemByClass<HI> where HI : IHeapItem {
protected static string BuildDescription (LoadedClass c) {
return String.Format ("Object has class {0}", c.Name);
@@ -1142,39 +1303,118 @@ namespace Mono.Profiler {
}
}
- public class HeapItemSetClassStatistics {
- LoadedClass c;
- public LoadedClass Class {
+ public interface IHeapItemSetStatisticsSubject {
+ string Description {get;}
+ uint ID {get;}
+ }
+ public delegate HISSS GetHeapItemStatisticsSubject<HI,HISSS> (HI item) where HI : IHeapItem where HISSS : IHeapItemSetStatisticsSubject;
+ public delegate HISSBS NewHeapItemStatisticsBySubject<HISSBS,HISSS> (HISSS subject) where HISSS : IHeapItemSetStatisticsSubject where HISSBS : HeapItemSetStatisticsBySubject<HISSS>;
+
+ public interface IHeapItemSetStatisticsBySubject {
+ IHeapItemSetStatisticsSubject Subject {get;}
+ uint ItemsCount {get;}
+ uint AllocatedBytes {get;}
+ }
+
+ public abstract class HeapItemSetStatisticsBySubject<HISSS> : IHeapItemSetStatisticsBySubject where HISSS : IHeapItemSetStatisticsSubject {
+ HISSS subject;
+ protected HISSS Subject {
get {
- return c;
+ return subject;
}
}
+ IHeapItemSetStatisticsSubject IHeapItemSetStatisticsBySubject.Subject {
+ get {
+ return subject;
+ }
+ }
+
+ uint itemsCount;
+ public uint ItemsCount {
+ get {
+ return itemsCount;
+ }
+ }
+
uint allocatedBytes;
public uint AllocatedBytes {
get {
return allocatedBytes;
}
- internal set {
- allocatedBytes = value;
- }
}
- public HeapItemSetClassStatistics (LoadedClass c, uint allocatedBytes) {
- this.c = c;
- this.allocatedBytes = allocatedBytes;
+
+ internal void AddItem (IHeapItem item) {
+ itemsCount ++;
+ allocatedBytes += item.Size;
+ }
+
+ protected abstract HISSS GetUnavailableSubject ();
+
+ public HeapItemSetStatisticsBySubject (HISSS subject) {
+ this.subject = subject != null ? subject : GetUnavailableSubject ();
+ this.itemsCount = 0;
+ this.allocatedBytes = 0;
}
- public static Comparison<HeapItemSetClassStatistics> CompareByAllocatedBytes = delegate (HeapItemSetClassStatistics a, HeapItemSetClassStatistics b) {
+ public static Comparison<HeapItemSetStatisticsBySubject<HISSS>> CompareByAllocatedBytes = delegate (HeapItemSetStatisticsBySubject<HISSS> a, HeapItemSetStatisticsBySubject<HISSS> b) {
return a.AllocatedBytes.CompareTo (b.AllocatedBytes);
};
}
+ public class HeapItemSetClassStatistics : HeapItemSetStatisticsBySubject<LoadedClass> {
+ public LoadedClass Class {
+ get {
+ return Subject;
+ }
+ }
+ protected override LoadedClass GetUnavailableSubject () {
+ return LoadedClass.LoadedClassUnavailable;
+ }
+ public HeapItemSetClassStatistics (LoadedClass c) : base (c) {
+ }
+ }
+
+ public class HeapItemSetMethodStatistics : HeapItemSetStatisticsBySubject<LoadedMethod> {
+ public LoadedMethod Method {
+ get {
+ return Subject;
+ }
+ }
+ protected override LoadedMethod GetUnavailableSubject () {
+ return LoadedMethod.LoadedMethodUnavailable;
+ }
+ public HeapItemSetMethodStatistics (LoadedMethod method) : base (method) {
+ }
+ }
+
+ public class HeapItemSetCallStackStatistics : HeapItemSetStatisticsBySubject<StackTrace> {
+ public StackTrace CallStack {
+ get {
+ return Subject;
+ }
+ }
+ protected override StackTrace GetUnavailableSubject () {
+ return StackTrace.StackTraceUnavailable;
+ }
+ public HeapItemSetCallStackStatistics (StackTrace callStack) : base (callStack) {
+ }
+ }
+
public interface IHeapItemSet {
bool ContainsItem (ulong id);
string ShortDescription {get;}
string LongDescription {get;}
IHeapItem[] Elements {get;}
HeapItemSetClassStatistics[] ClassStatistics {get;}
+ HeapItemSetMethodStatistics[] AllocatorMethodStatistics {get;}
+ HeapItemSetCallStackStatistics[] AllocationCallStackStatistics {get;}
uint AllocatedBytes {get;}
+ bool ObjectAllocationsArePresent {get;}
+ void FindObjectAllocations (ProviderOfPreviousAllocationsSets previousSetsProvider);
+ }
+
+ public interface ProviderOfPreviousAllocationsSets {
+ IEnumerable<HeapItemSet<AllocatedObject>> PreviousAllocationsSets ();
}
public abstract class HeapItemSet<HI> : IHeapItemSet where HI : IHeapItem {
@@ -1220,6 +1460,73 @@ namespace Mono.Profiler {
}
}
+ protected HISSBS[] BuildStatistics<HISSS,HISSBS> (GetHeapItemStatisticsSubject<HI,HISSS> getSubject, NewHeapItemStatisticsBySubject<HISSBS,HISSS> newStatistics) where HISSS : IHeapItemSetStatisticsSubject where HISSBS : HeapItemSetStatisticsBySubject<HISSS> {
+ Dictionary<uint,HISSBS> statistics = new Dictionary<uint,HISSBS> ();
+
+ foreach (HI hi in elements) {
+ HISSS subject = getSubject (hi);
+ HISSBS s;
+ uint id;
+ if (subject != null) {
+ id = subject.ID;
+ } else {
+ id = 0;;
+ }
+ if (statistics.ContainsKey (id)) {
+ s = statistics [id];
+ } else {
+ s = newStatistics (subject);
+ statistics [id] = s;
+ }
+ s.AddItem (hi);
+ }
+ HISSBS[] result = new HISSBS [statistics.Values.Count];
+ statistics.Values.CopyTo (result, 0);
+ Array.Sort (result, HeapItemSetStatisticsBySubject<HISSS>.CompareByAllocatedBytes);
+ Array.Reverse (result);
+
+ return result;
+ }
+
+ HeapItemSetMethodStatistics[] allocatorMethodStatistics;
+ public HeapItemSetMethodStatistics[] AllocatorMethodStatistics {
+ get {
+ if ((allocatorMethodStatistics == null) && ObjectAllocationsArePresent) {
+ allocatorMethodStatistics = BuildStatistics<LoadedMethod,HeapItemSetMethodStatistics> (delegate (HI item) {
+ return item.AllocatorMethod;
+ }, delegate (LoadedMethod m) {
+ return new HeapItemSetMethodStatistics (m);
+ });
+ }
+ return allocatorMethodStatistics;
+ }
+ }
+ public bool HasAllocatorMethodStatistics {
+ get {
+ return allocatorMethodStatistics != null;
+ }
+ }
+
+ HeapItemSetCallStackStatistics[] allocationCallStackStatistics;
+ public HeapItemSetCallStackStatistics[] AllocationCallStackStatistics {
+ get {
+ if ((allocationCallStackStatistics == null) && ObjectAllocationsArePresent) {
+ allocationCallStackStatistics = BuildStatistics<StackTrace,HeapItemSetCallStackStatistics> (delegate (HI item) {
+ return item.AllocationCallStack;
+ }, delegate (StackTrace s) {
+ return new HeapItemSetCallStackStatistics (s);
+ });
+ }
+ return allocationCallStackStatistics;
+ }
+ }
+ public bool HasAllocationCallStackStatistics {
+ get {
+ return allocationCallStackStatistics != null;
+ }
+ }
+
+
public void CompareWithSet<OHI> (HeapItemSet<OHI> otherSet, out HeapItemSet<HI> onlyInThisSet, out HeapItemSet<OHI> onlyInOtherSet) where OHI : IHeapItem {
HeapItemSetFromComparison<HI,OHI>.PerformComparison<HI,OHI> (this, otherSet, out onlyInThisSet, out onlyInOtherSet);
}
@@ -1228,29 +1535,40 @@ namespace Mono.Profiler {
return HeapItemSetFromComparison<HI,OHI>.PerformIntersection<HI,OHI> (this, otherSet);
}
- public bool ContainsItem (ulong id) {
- int lowIndex = -1;
- int highIndex = elements.Length;
-
- while (true) {
- int span = (highIndex - lowIndex) / 2;
+ public HI this [ulong id] {
+ get {
+ int lowIndex = -1;
+ int highIndex = elements.Length;
- if (span > 0) {
- int middleIndex = lowIndex + span;
- HI middleElement = elements [middleIndex];
- ulong middleID = middleElement.ID;
- if (middleID > id) {
- highIndex = middleIndex;
- } else if (middleID < id) {
- lowIndex = middleIndex;
+ while (true) {
+ int span = (highIndex - lowIndex) / 2;
+
+ if (span > 0) {
+ int middleIndex = lowIndex + span;
+ HI middleElement = elements [middleIndex];
+ ulong middleID = middleElement.ID;
+ if (middleID > id) {
+ highIndex = middleIndex;
+ } else if (middleID < id) {
+ lowIndex = middleIndex;
+ } else {
+ return middleElement;
+ }
} else {
- return true;
+ return default (HI);
}
- } else {
- return false;
}
}
}
+ public HI this [HI item] {
+ get {
+ return this [item.ID];
+ }
+ }
+
+ public bool ContainsItem (ulong id) {
+ return this [id] != null;
+ }
public HeapItemSet<HeapObject> ObjectsReferencingItemInSet (HeapItemSet<HeapObject> objectSet) {
return Mono.Profiler.HeapItemSetFromComparison<HI,HeapObject>.ObjectsReferencingItemInSet (this, objectSet);
@@ -1259,30 +1577,45 @@ namespace Mono.Profiler {
return Mono.Profiler.HeapItemSetFromComparison<HI,HeapObject>.ObjectsReferencedByItemInSet (this, objectSet);
}
- protected HeapItemSet (string shortDescription, string longDescription, HI[] elements) {
+ static void FindObjectAllocations (HeapItemSet<HeapObject> baseSet, ProviderOfPreviousAllocationsSets previousSetsProvider) {
+ foreach (HeapObject heapObject in baseSet.Elements) {
+ if (heapObject.Allocation == null) {
+ heapObject.FindAllocation (previousSetsProvider);
+ }
+ }
+ }
+
+ bool objectAllocationsArePresent;
+ public bool ObjectAllocationsArePresent {
+ get {
+ return objectAllocationsArePresent;
+ }
+ }
+ public void FindObjectAllocations (ProviderOfPreviousAllocationsSets previousSetsProvider) {
+ if ((! objectAllocationsArePresent)) {
+ HeapItemSet<HeapObject> baseSet = this as HeapItemSet<HeapObject>;
+ if (baseSet != null) {
+ FindObjectAllocations (baseSet, previousSetsProvider);
+ objectAllocationsArePresent = true;
+ }
+ }
+ }
+
+ protected HeapItemSet (string shortDescription, string longDescription, HI[] elements, bool objectAllocationsArePresent) {
this.shortDescription = shortDescription;
this.longDescription = longDescription;
this.elements = elements;
+ this.objectAllocationsArePresent = objectAllocationsArePresent;
allocatedBytes = 0;
Array.Sort (this.elements, CompareHeapItemsByID);
- Dictionary<ulong,HeapItemSetClassStatistics> statistics = new Dictionary<ulong,HeapItemSetClassStatistics> ();
- foreach (HI hi in elements) {
- HeapItemSetClassStatistics cs;
- if (statistics.ContainsKey (hi.Class.ID)) {
- cs = statistics [hi.Class.ID];
- cs.AllocatedBytes += hi.Size;
- allocatedBytes += hi.Size;
- } else {
- cs = new HeapItemSetClassStatistics (hi.Class, hi.Size);
- statistics [hi.Class.ID] = cs;
- }
- }
- classStatistics = new HeapItemSetClassStatistics [statistics.Values.Count];
- statistics.Values.CopyTo (classStatistics, 0);
- Array.Sort (classStatistics, HeapItemSetClassStatistics.CompareByAllocatedBytes);
- Array.Reverse (classStatistics);
+ classStatistics = BuildStatistics<LoadedClass,HeapItemSetClassStatistics> (delegate (HI item) {
+ allocatedBytes += item.Size;
+ return item.Class;
+ }, delegate (LoadedClass c) {
+ return new HeapItemSetClassStatistics (c);
+ });
}
}
@@ -1297,7 +1630,7 @@ namespace Mono.Profiler {
public HeapObjectSetFromSnapshot (HeapSnapshot heapSnapshot):
base (String.Format ("Heap at {0}.{1:000}s", heapSnapshot.HeaderStartTime.Seconds, heapSnapshot.HeaderStartTime.Milliseconds),
String.Format ("Heap snapshot taken at {0}.{1:000}s", heapSnapshot.HeaderStartTime.Seconds, heapSnapshot.HeaderStartTime.Milliseconds),
- heapSnapshot.HeapObjects) {
+ heapSnapshot.HeapObjects, false) {
this.heapSnapshot = heapSnapshot;
}
}
@@ -1306,7 +1639,7 @@ namespace Mono.Profiler {
public AllocatedObjectSetFromEvents (TimeSpan timeFromStart, AllocatedObject[] allocations):
base (String.Format ("Allocations {0}.{1:000}s", timeFromStart.Seconds, timeFromStart.Milliseconds),
String.Format ("Allocations taken from {0}.{1:000}s", timeFromStart.Seconds, timeFromStart.Milliseconds),
- allocations) {
+ allocations, true) {
}
}
@@ -1337,7 +1670,7 @@ namespace Mono.Profiler {
return result;
}
- public HeapItemSetFromFilter (HeapItemSet<HI> baseSet, IHeapItemFilter<HI> filter): base (filter.Description, String.Format ("{0} and {1}", filter.Description, baseSet.LongDescription), filterSet (baseSet, filter)) {
+ public HeapItemSetFromFilter (HeapItemSet<HI> baseSet, IHeapItemFilter<HI> filter): base (filter.Description, String.Format ("{0} and {1}", filter.Description, baseSet.LongDescription), filterSet (baseSet, filter), baseSet.ObjectAllocationsArePresent) {
this.baseSet = baseSet;
this.filter = filter;
}
@@ -1475,7 +1808,7 @@ namespace Mono.Profiler {
return new HeapItemSetFromComparison<HeapObject,HI>(objectSet, itemSet, result.ToArray (), "references item");
}
- HeapItemSetFromComparison (HeapItemSet<HI> baseSet, HeapItemSet<OHI> otherSet, HI[] heapItems, string relation): base (buildShortDescription (otherSet, relation), buildLongDescription (otherSet, relation), heapItems) {
+ HeapItemSetFromComparison (HeapItemSet<HI> baseSet, HeapItemSet<OHI> otherSet, HI[] heapItems, string relation): base (buildShortDescription (otherSet, relation), buildLongDescription (otherSet, relation), heapItems, baseSet.ObjectAllocationsArePresent) {
this.baseSet = baseSet;
this.otherSet = otherSet;
}