2006-11-13 Lluis Sanchez Gual <lluis@novell.com>

* profiler/outfile-writer.h:
	* profiler/outfile-writer.c: Removed unused constants. Added some
	  totals in the file headers.
	
	* HeapShot.Gui.Widgets/ReferenceTreeViewer.cs: Track api changes.
	  Load the tree in the background.
	* HeapShot.Gui.Widgets/gtk-gui/gui.stetic,
	  HeapShot.Gui.Widgets/gtk-gui/objects.xml: Updated.
	* HeapShot.Gui.Widgets/gtk-gui/library.dat: Removed from build.
	* HeapShot.Gui.Widgets/ObjectMapViewer.cs: Track api changes.
	* configure.in: Fix directory name.
	* HeapShot/ReferenceTreeReport.cs: Track api changes.
	
	* HeapShot.Reader/TypeInfo.cs:
	* HeapShot.Reader/FieldInfo.cs:
	* HeapShot.Reader/ObjectInfo.cs:
	* HeapShot.Reader/ReferenceNode.cs:
	* HeapShot.Reader/ObjectMapFileReader.cs: Redesigned the way object
	  information is loaded in memory. It's now using big arrays of structs,
	  which is much more efficient that reference objects.


svn path=/trunk/heap-shot/; revision=67764
This commit is contained in:
Lluis Sanchez 2006-11-13 16:14:48 +00:00
Родитель 243b00ea73
Коммит b17c3cad5c
16 изменённых файлов: 610 добавлений и 381 удалений

Просмотреть файл

@ -1,3 +1,26 @@
2006-11-13 Lluis Sanchez Gual <lluis@novell.com>
* profiler/outfile-writer.h:
* profiler/outfile-writer.c: Removed unused constants. Added some
totals in the file headers.
* HeapShot.Gui.Widgets/ReferenceTreeViewer.cs: Track api changes.
Load the tree in the background.
* HeapShot.Gui.Widgets/gtk-gui/gui.stetic,
HeapShot.Gui.Widgets/gtk-gui/objects.xml: Updated.
* HeapShot.Gui.Widgets/gtk-gui/library.dat: Removed from build.
* HeapShot.Gui.Widgets/ObjectMapViewer.cs: Track api changes.
* configure.in: Fix directory name.
* HeapShot/ReferenceTreeReport.cs: Track api changes.
* HeapShot.Reader/TypeInfo.cs:
* HeapShot.Reader/FieldInfo.cs:
* HeapShot.Reader/ObjectInfo.cs:
* HeapShot.Reader/ReferenceNode.cs:
* HeapShot.Reader/ObjectMapFileReader.cs: Redesigned the way object
information is loaded in memory. It's now using big arrays of structs,
which is much more efficient that reference objects.
2006-11-06 Raja R Harinath <rharinath@novell.com>
* configure.in (HeapShot/heap-shot): Separate out output command.

Просмотреть файл

@ -50,6 +50,11 @@ namespace HeapShot.Gui.Widgets
labelName.Text = "";
}
public event ProgressEventHandler ProgressEvent {
add { allObjectsTree.ProgressEvent += value; }
remove { allObjectsTree.ProgressEvent -= value; }
}
public void AddFile (string fileName)
{
ObjectMapReader map = new ObjectMapReader (fileName);
@ -78,14 +83,8 @@ namespace HeapShot.Gui.Widgets
else
labelName.Text = System.IO.Path.GetFileName (map.Name);
int ni = 0;
uint mem = 0;
foreach (TypeInfo t in map.GetTypes ()) {
ni += t.Objects.Count;
mem += t.TotalSize;
}
labelCount.Text = ni.ToString ("n0");
labelMemory.Text = mem.ToString ("n0") + " bytes";
labelCount.Text = map.NumObjects.ToString ("n0");
labelMemory.Text = map.TotalMemory.ToString ("n0") + " bytes";
}
}
@ -183,8 +182,7 @@ namespace HeapShot.Gui.Widgets
return dif[2];
}
ObjectMapReader res = new ObjectMapReader (m2.Name);
res.RemoveData (m1);
ObjectMapReader res = ObjectMapReader.GetDiff (m1, m2);
difs.Add (new ObjectMapReader[] { m1, m2, res });
return res;
}

Просмотреть файл

@ -5,6 +5,8 @@ using HeapShot.Reader;
namespace HeapShot.Gui.Widgets
{
public delegate void ProgressEventHandler (int current, int max, string message);
public class ReferenceTreeViewer : Gtk.Bin
{
protected Gtk.TreeView treeview;
@ -21,10 +23,14 @@ namespace HeapShot.Gui.Widgets
const int InstancesCol = 6;
const int RefsCol = 7;
int TreeColRefs;
bool reloadRequested;
bool loading;
ObjectMapReader file;
string typeName;
protected Gtk.HBox boxFilter;
public event ProgressEventHandler ProgressEvent;
public ReferenceTreeViewer()
{
@ -111,10 +117,35 @@ namespace HeapShot.Gui.Widgets
boxFilter.Visible = true;
treeview.Columns [TreeColRefs].Visible = InverseReferences;
store.Clear ();
foreach (TypeInfo t in file.GetTypes ()) {
InternalFillType (file, t.Name);
if (loading) {
// If the tree is already being loaded, notify that loading
// has to start again, since the file has changed.
reloadRequested = true;
return;
}
loading = true;
store.Clear ();
int n=0;
foreach (int t in file.GetTypes ()) {
if (++n == 20) {
if (ProgressEvent != null) {
ProgressEvent (n, file.GetTypeCount (), null);
}
while (Gtk.Application.EventsPending ())
Gtk.Application.RunIteration ();
if (reloadRequested) {
loading = false;
reloadRequested = false;
FillAllTypes (this.file);
return;
}
n = 0;
}
if (file.GetObjectCountForType (t) > 0)
InternalFillType (file, t);
}
loading = false;
}
public void FillType (ObjectMapReader file, string typeName)
@ -124,13 +155,13 @@ namespace HeapShot.Gui.Widgets
store.Clear ();
boxFilter.Visible = false;
treeview.Columns [TreeColRefs].Visible = InverseReferences;
TreeIter iter = InternalFillType (file, typeName);
TreeIter iter = InternalFillType (file, file.GetTypeFromName (typeName));
treeview.ExpandRow (store.GetPath (iter), false);
}
TreeIter InternalFillType (ObjectMapReader file, string typeName)
TreeIter InternalFillType (ObjectMapReader file, int type)
{
ReferenceNode node = file.GetReferenceTree (typeName, checkInverse.Active);
ReferenceNode node = file.GetReferenceTree (type, checkInverse.Active);
return AddNode (TreeIter.Zero, node);
}
@ -221,23 +252,34 @@ namespace HeapShot.Gui.Widgets
SortType type;
store.GetSortColumnId (out col, out type);
ReferenceNode nod1 = (ReferenceNode) model.GetValue (a, ReferenceCol);
ReferenceNode nod2 = (ReferenceNode) model.GetValue (b, ReferenceCol);
switch (col) {
case 0:
return string.Compare (nod1.TypeName, nod2.TypeName);
case 1:
return nod1.RefCount.CompareTo (nod2.RefCount);
case 2:
return nod1.RefsToParent.CompareTo (nod2.RefsToParent);
case 3:
return nod1.TotalMemory.CompareTo (nod2.TotalMemory);
case 4:
return nod1.AverageSize.CompareTo (nod2.AverageSize);
default:
Console.WriteLine ("PPP: " + col);
return 1;
// throw new InvalidOperationException ();
object o1 = model.GetValue (a, ReferenceCol);
object o2 = model.GetValue (b, ReferenceCol);
if (o1 is ReferenceNode && o2 is ReferenceNode) {
ReferenceNode nod1 = (ReferenceNode) o1;
ReferenceNode nod2 = (ReferenceNode) o2;
switch (col) {
case 0:
return string.Compare (nod1.TypeName, nod2.TypeName);
case 1:
return nod1.RefCount.CompareTo (nod2.RefCount);
case 2:
return nod1.RefsToParent.CompareTo (nod2.RefsToParent);
case 3:
return nod1.TotalMemory.CompareTo (nod2.TotalMemory);
case 4:
return nod1.AverageSize.CompareTo (nod2.AverageSize);
default:
Console.WriteLine ("PPP: " + col);
return 1;
// throw new InvalidOperationException ();
}
} else if (o1 is FieldReference && o2 is FieldReference) {
return ((FieldReference)o1).FiledName.CompareTo (((FieldReference)o2).FiledName);
} else if (o1 is FieldReference) {
return -1;
} else {
return 1;
}
}

Просмотреть файл

@ -60,79 +60,20 @@
<property name="Events">0</property>
<property name="MemberName" />
<child>
<widget class="Gtk.Label" id="label3">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Name:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label4">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Object count:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="BottomAttach">2</property>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="TopAttach">1</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label5">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Total memory:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="BottomAttach">3</property>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="TopAttach">2</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="labelName">
<widget class="Gtk.Label" id="labelMemory">
<property name="LabelProp" />
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName">labelName</property>
<property name="MemberName">labelMemory</property>
</widget>
<packing>
<property name="BottomAttach">3</property>
<property name="LeftAttach">1</property>
<property name="YExpand">False</property>
<property name="RightAttach">2</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="TopAttach">2</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
@ -165,19 +106,38 @@
</packing>
</child>
<child>
<widget class="Gtk.Label" id="labelMemory">
<widget class="Gtk.Label" id="labelName">
<property name="LabelProp" />
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName">labelMemory</property>
<property name="MemberName">labelName</property>
</widget>
<packing>
<property name="BottomAttach">3</property>
<property name="LeftAttach">1</property>
<property name="YExpand">False</property>
<property name="RightAttach">2</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label5">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Total memory:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="BottomAttach">3</property>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="TopAttach">2</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
@ -187,6 +147,46 @@
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label4">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Object count:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="BottomAttach">2</property>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="TopAttach">1</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
<child>
<widget class="Gtk.Label" id="label3">
<property name="LabelProp" translatable="yes" context="yes" comments="">|Name:</property>
<property name="Xalign">0</property>
<property name="Events">0</property>
<property name="MemberName" />
</widget>
<packing>
<property name="YExpand">False</property>
<property name="AutoSize">True</property>
<property name="YShrink">False</property>
<property name="XShrink">False</property>
<property name="XExpand">False</property>
<property name="YFill">True</property>
<property name="XFill">True</property>
<property name="YOptions">Fill</property>
<property name="XOptions">Fill</property>
</packing>
</child>
</widget>
<packing>
<property name="TabExpand">False</property>

Двоичные данные
HeapShot.Gui.Widgets/gtk-gui/library.dat

Двоичный файл не отображается.

Просмотреть файл

@ -10,6 +10,7 @@
<itemgroup ref="Gtk.Widget" />
<itemgroup label="ReferenceTreeViewer Signals">
<signal name="TypeActivated" />
<signal name="ProgressEvent" />
</itemgroup>
</signals>
</object>
@ -19,6 +20,9 @@
</itemgroups>
<signals>
<itemgroup ref="Gtk.Widget" />
<itemgroup label="ObjectMapViewer Signals">
<signal name="ProgressEvent" />
</itemgroup>
</signals>
</object>
</objects>

Просмотреть файл

@ -27,9 +27,9 @@ using System.Text.RegularExpressions;
namespace HeapShot.Reader {
public class FieldInfo
public struct FieldInfo
{
public uint Code;
public ulong Code;
public string Name;
}
}

Просмотреть файл

@ -27,46 +27,14 @@ using System.Text.RegularExpressions;
namespace HeapShot.Reader {
public class ObjectInfo
public struct ObjectInfo
{
TypeInfo type;
uint size;
ObjectReference[] references;
uint code;
public ArrayList Referencers;
public ObjectInfo (uint code, TypeInfo type, uint size, ObjectReference[] references)
{
this.code = code;
this.type = type;
this.size = size + (uint)IntPtr.Size + (uint)IntPtr.Size; // Add MonoObject overhead
this.references = references;
}
public uint Code {
get { return code; }
}
public TypeInfo Type {
get { return type; }
}
public uint Size {
get { return size; }
}
public ObjectReference[] References {
get { return references; }
}
public string GetReferencerField (ObjectInfo referenced)
{
foreach (ObjectReference oref in References) {
if (oref.Object == referenced)
return this.Type.GetFieldName (oref.FieldCode);
}
return null;
}
public uint Code;
public int Type;
public uint Size;
public int RefsIndex;
public int RefsCount;
public int InverseRefsIndex;
public int InverseRefsCount;
}
}

Просмотреть файл

@ -30,15 +30,45 @@ namespace HeapShot.Reader {
public class ObjectMapReader
{
const uint magic_number = 0x4eabbdd1;
const int expected_log_version = 5;
const uint magic_number = 0x4eabfdd1;
const int expected_log_version = 6;
const int expected_summary_version = 2;
const string log_file_label = "heap-shot logfile";
const string summary_file_label = "heap-shot summary";
bool terminated_normally = true;
string name;
DateTime timestamp;
uint numTypes;
uint numObjects;
uint numReferences;
uint numFields;
uint totalMemory;
uint objectCount;
int curObject;
int curType;
int curField;
int curRef;
ObjectInfo[] objects;
TypeInfo[] types;
string[] fieldNames;
int[] objectIndices;
int[] typeIndices;
int[] references;
int[] inverseRefs;
int[] fieldReferences;
bool[] filteredObjects;
uint[] referenceCodes;
uint[] objectTypeCodes;
uint[] fieldCodes;
uint[] fieldReferenceCodes;
uint[] objectCodes;
internal ObjectMapReader ()
{
}
public ObjectMapReader (string filename)
{
@ -66,6 +96,14 @@ namespace HeapShot.Reader {
get { return timestamp; }
}
public uint TotalMemory {
get { return totalMemory; }
}
public uint NumObjects {
get { return objectCount; }
}
public static ObjectMapReader CreateProcessSnapshot (int pid)
{
string dumpFile = "/tmp/heap-shot-dump";
@ -108,8 +146,7 @@ namespace HeapShot.Reader {
///////////////////////////////////////////////////////////////////
// Return true if this is a summary file, false if it is a log file.
private bool ReadPreamble (BinaryReader reader)
private void ReadPreamble (BinaryReader reader)
{
uint this_magic;
this_magic = reader.ReadUInt32 ();
@ -124,16 +161,11 @@ namespace HeapShot.Reader {
this_version = reader.ReadInt32 ();
string this_label;
bool is_summary;
int expected_version;
this_label = reader.ReadString ();
if (this_label == log_file_label) {
is_summary = false;
expected_version = expected_log_version;
} else if (this_label == summary_file_label) {
is_summary = true;
expected_version = expected_summary_version;
} else
throw new Exception ("Unknown file label in heap-shot outfile");
@ -143,8 +175,11 @@ namespace HeapShot.Reader {
this_label, expected_version, this_version);
throw new Exception (msg);
}
return is_summary;
numTypes = reader.ReadUInt32 ();
numObjects = reader.ReadUInt32 ();
numReferences = reader.ReadUInt32 ();
numFields = reader.ReadUInt32 ();
objectCount = numObjects;
}
//
@ -153,12 +188,20 @@ namespace HeapShot.Reader {
// These need to agree w/ the definitions in outfile-writer.c
const byte TAG_TYPE = 0x01;
const byte TAG_OBJECT = 0x06;
const byte TAG_OBJECT = 0x02;
const byte TAG_EOS = 0xff;
private void ReadLogFile (BinaryReader reader)
{
int chunk_count = 0;
objects = new ObjectInfo [numObjects];
types = new TypeInfo [numTypes];
objectTypeCodes = new uint [numObjects];
referenceCodes = new uint [numReferences];
fieldReferenceCodes = new uint [numReferences];
fieldCodes = new uint [numFields];
fieldNames = new string [numFields];
try {
while (ReadLogFileChunk (reader))
@ -175,6 +218,11 @@ namespace HeapShot.Reader {
}
BuildMap ();
Spew ("Processed {0} chunks", chunk_count);
objectTypeCodes = null;
referenceCodes = null;
fieldReferenceCodes = null;
fieldCodes = null;
}
private bool ReadLogFileChunk (BinaryReader reader)
@ -206,174 +254,312 @@ namespace HeapShot.Reader {
private void ReadLogFileChunk_Type (BinaryReader reader)
{
uint code;
code = reader.ReadUInt32 ();
string name;
name = reader.ReadString ();
uint code = reader.ReadUInt32 ();
string name = reader.ReadString ();
ArrayList fields = new ArrayList ();
types [curType].Code = code;
types [curType].Name = name;
types [curType].FieldsIndex = curField;
int nf = 0;
uint fcode;
while ((fcode = reader.ReadUInt32 ()) != 0) {
FieldInfo f = new FieldInfo ();
f.Code = fcode;
f.Name = reader.ReadString ();
fields.Add (f);
fieldCodes [curField] = fcode;
fieldNames [curField] = reader.ReadString ();
curField++;
nf++;
}
RegisterType (code, name, (FieldInfo[]) fields.ToArray (typeof(FieldInfo)));
types [curType].FieldsCount = nf;
curType++;
}
private void ReadLogFileChunk_Object (BinaryReader reader)
{
uint code;
code = reader.ReadUInt32 ();
uint typeCode;
typeCode = reader.ReadUInt32 ();
uint size;
size = reader.ReadUInt32 ();
objects [curObject].Code = reader.ReadUInt32 ();
objectTypeCodes [curObject] = reader.ReadUInt32 ();
objects [curObject].Size = reader.ReadUInt32 ();
objects [curObject].RefsIndex = curRef;
totalMemory += objects [curObject].Size;
// Read references
// Read referenceCodes
ArrayList refs = new ArrayList ();
int nr = 0;
uint oref;
while ((oref = reader.ReadUInt32 ()) != 0) {
ObjectReference o = new ObjectReference ();
o.ObjectCode = oref;
o.FieldCode = reader.ReadUInt32 ();
refs.Add (o);
referenceCodes [curRef] = oref;
fieldReferenceCodes [curRef] = reader.ReadUInt32 ();
nr++;
curRef++;
}
ObjectReference[] array = refs.Count > 0 ? (ObjectReference[]) refs.ToArray (typeof(ObjectReference)) : null;
RegisterObject (code, typeCode, size, array);
}
Hashtable types = new Hashtable ();
Dictionary<uint,ObjectInfo> objects = new Dictionary<uint,ObjectInfo> ();
Hashtable typesByName = new Hashtable ();
void RegisterType (uint id, string name, FieldInfo[] fields)
{
TypeInfo t = new TypeInfo (id, name, fields);
types [id] = t;
typesByName [name] = t;
}
void RegisterObject (uint id, uint typeId, uint size, ObjectReference[] refs)
{
TypeInfo type = (TypeInfo) types [typeId];
if (type == null) {
Spew ("Type not found");
return;
}
ObjectInfo ob = new ObjectInfo (id, type, size, refs);
type.Objects.Add (ob);
objects [id] = ob;
objects [curObject].RefsCount = nr;
curObject++;
}
void BuildMap ()
{
foreach (ObjectInfo o in objects.Values) {
if (o.References != null) {
for (int n=0; n<o.References.Length; n++) {
ObjectInfo refo = GetObject (o.References [n].ObjectCode);
if (refo != null) {
o.References [n].Object = refo;
if (refo.Referencers == null)
refo.Referencers = new ArrayList (2);
refo.Referencers.Add (o);
// Build an array of object indices and sort it
RefComparer objectComparer = new RefComparer ();
objectComparer.objects = objects;
objectIndices = new int [numObjects];
for (int n=0; n < numObjects; n++)
objectIndices [n] = n;
Array.Sort<int> (objectIndices, objectComparer);
// Sorted array of codes needed for the binary search
objectCodes = new uint [numObjects];
for (int n=0; n < numObjects; n++)
objectCodes [n] = objects [objectIndices[n]].Code;
// Build an array of type indices and sort it
TypeComparer typeComparer = new TypeComparer ();
typeComparer.types = types;
typeIndices = new int [numTypes];
for (int n=0; n < numTypes; n++)
typeIndices [n] = n;
Array.Sort<int> (typeIndices, typeComparer);
// Sorted array of codes needed for the binary search
uint[] typeCodes = new uint [numTypes];
for (int n=0; n < numTypes; n++) {
typeCodes [n] = types [typeIndices[n]].Code;
}
Console.WriteLine ("--");
// Assign the type index to each object
for (int n=0; n<numObjects; n++) {
int i = Array.BinarySearch<uint> (typeCodes, objectTypeCodes [n]);
if (i < 0)
Console.WriteLine ("TNF: " + objectTypeCodes [n]);
else {
objects [n].Type = typeIndices [i];
types [objects [n].Type].ObjectCount++;
types [objects [n].Type].TotalSize += objects [n].Size;
}
}
// Build the array of referenceCodes, but using indexes
references = new int [numReferences];
for (int n=0; n<numReferences; n++) {
int i = Array.BinarySearch (objectCodes, referenceCodes[n]);
if (i >= 0) {
references[n] = objectIndices [i];
objects [objectIndices [i]].InverseRefsCount++;
} else
references[n] = -1;
}
// Calculate the array index of inverse referenceCodes for each object
int[] invPositions = new int [numObjects]; // Temporary array to hold reference positions
int rp = 0;
for (int n=0; n<numObjects; n++) {
objects [n].InverseRefsIndex = rp;
invPositions [n] = rp;
rp += objects [n].InverseRefsCount;
}
// Build the array of inverse referenceCodes
// Also calculate the index of each field name
inverseRefs = new int [numReferences];
fieldReferences = new int [numReferences];
for (int ob=0; ob < numObjects; ob++) {
int fi = types [objects [ob].Type].FieldsIndex;
int nf = fi + types [objects [ob].Type].FieldsCount;
int sr = objects [ob].RefsIndex;
int er = sr + objects [ob].RefsCount;
for (; sr<er; sr++) {
int i = references [sr];
if (i != -1) {
inverseRefs [invPositions [i]] = ob;
invPositions [i]++;
}
// If the reference is bound to a field, locate the field
uint fr = fieldReferenceCodes [sr];
if (fr != 0) {
for (int k=fi; k<nf; k++) {
if (fieldCodes [k] == fr) {
fieldReferences [sr] = k;
break;
}
}
}
}
}
foreach (TypeInfo t in types.Values) {
t.Objects.TrimToSize();
}
class RefComparer: IComparer <int> {
public ObjectInfo[] objects;
public int Compare (int x, int y) {
return objects [x].Code.CompareTo (objects [y].Code);
}
}
class TypeComparer: IComparer <int> {
public TypeInfo[] types;
public int Compare (int x, int y) {
return types [x].Code.CompareTo (types [y].Code);
}
}
public ReferenceNode GetReferenceTree (string typeName, bool inverse)
{
ReferenceNode nod = new ReferenceNode (typeName, inverse);
foreach (ObjectInfo obj in GetObjectsByType (typeName)) {
nod.AddReference (obj);
}
int type = GetTypeFromName (typeName);
if (type != -1)
return GetReferenceTree (type, inverse);
else
return new ReferenceNode (this, type, inverse);
}
public ReferenceNode GetReferenceTree (int type, bool inverse)
{
ReferenceNode nod = new ReferenceNode (this, type, inverse);
nod.AddGlobalReferences ();
nod.Flush ();
return nod;
}
public ObjectInfo GetObject (uint id)
public int GetTypeCount ()
{
ObjectInfo val;
if (!objects.TryGetValue (id, out val))
return null;
else
return val;
return (int) numTypes;
}
public ICollection GetObjectsByType (string typeName)
public int GetTypeFromName (string name)
{
TypeInfo t = (TypeInfo) typesByName [typeName];
if (t == null)
return new ObjectInfo [0];
else
return t.Objects;
for (int n=0; n<numTypes; n++) {
if (name == types [n].Name)
return n;
}
return -1;
}
public ICollection GetTypes ()
public IEnumerable<int> GetObjectsByType (int type)
{
ArrayList list = new ArrayList ();
list.AddRange (types.Values);
list.Sort (new TypeSorter ());
return list;
for (int n=0; n<numObjects; n++) {
if (objects [n].Type == type && (filteredObjects == null || !filteredObjects[n])) {
yield return n;
}
}
}
public static ObjectMapReader GetDiff (ObjectMapReader oldMap, ObjectMapReader newMap)
{
ObjectMapReader dif = new ObjectMapReader ();
dif.fieldNames = newMap.fieldNames;
dif.fieldReferences = newMap.fieldReferences;
dif.inverseRefs = newMap.inverseRefs;
dif.numFields = newMap.numFields;
dif.numObjects = newMap.numObjects;
dif.numReferences = newMap.numReferences;
dif.numTypes = newMap.numTypes;
dif.objectCount = newMap.objectCount;
dif.objectIndices = newMap.objectIndices;
dif.objects = newMap.objects;
dif.objectCodes = newMap.objectCodes;
dif.references = newMap.references;
dif.totalMemory = newMap.totalMemory;
dif.typeIndices = newMap.typeIndices;
dif.types = newMap.types;
dif.RemoveData (oldMap);
return dif;
}
public void RemoveData (ObjectMapReader otherReader)
{
Hashtable toDelete = new Hashtable ();
foreach (uint code in otherReader.objects.Keys) {
if (objects.ContainsKey (code)) {
ObjectInfo oi = objects [code];
toDelete [oi] = oi;
types = (TypeInfo[]) types.Clone ();
filteredObjects = new bool [numObjects];
for (int n=0; n<otherReader.numObjects; n++) {
int i = Array.BinarySearch (objectCodes, otherReader.objects[n].Code);
if (i >= 0) {
i = objectIndices [i];
filteredObjects [i] = true;
int t = objects[i].Type;
types [t].ObjectCount--;
types [t].TotalSize -= objects[i].Size;
this.objectCount--;
this.totalMemory -= objects[i].Size;
}
}
ArrayList emptyTypes = new ArrayList ();
foreach (TypeInfo t in types.Values) {
for (int n = t.Objects.Count - 1; n >= 0; n--) {
if (toDelete.Contains (t.Objects [n]))
t.Objects.RemoveAt (n);
}
if (t.Objects.Count == 0)
emptyTypes.Add (t);
}
foreach (TypeInfo t in emptyTypes) {
types.Remove (t.Code);
typesByName.Remove (t.Name);
}
// Rebuild referencers list
foreach (ObjectInfo o in objects.Values)
o.Referencers = null;
BuildMap ();
}
}
class TypeSorter: IComparer
{
public int Compare (object x, object y)
public IEnumerable<int> GetReferencers (int obj)
{
TypeInfo t1 = (TypeInfo) x;
TypeInfo t2 = (TypeInfo) y;
if (t1.Objects.Count == t2.Objects.Count)
return 0;
else if (t1.Objects.Count > t2.Objects.Count)
return -1;
else
return 1;
int n = objects [obj].InverseRefsIndex;
int end = n + objects [obj].InverseRefsCount;
for (; n<end; n++) {
int ro = inverseRefs [n];
if (filteredObjects == null || !filteredObjects [ro])
yield return ro;
}
}
public IEnumerable<int> GetReferences (int obj)
{
int n = objects [obj].RefsIndex;
int end = n + objects [obj].RefsCount;
for (; n<end; n++) {
int ro = inverseRefs [n];
if (filteredObjects == null || !filteredObjects [ro])
yield return references [n];
}
}
public string GetReferencerField (int obj, int refObj)
{
int n = objects [obj].RefsIndex;
int end = n + objects [obj].RefsCount;
for (; n<end; n++) {
if (references [n] == refObj) {
if (fieldReferences [n] != 0)
return fieldNames [fieldReferences [n]];
else
return null;
}
}
return null;
}
public string GetObjectTypeName (int obj)
{
return types [objects [obj].Type].Name;
}
public int GetObjectType (int obj)
{
return objects [obj].Type;
}
public uint GetObjectSize (int obj)
{
return objects [obj].Size;
}
public IEnumerable<int> GetTypes ()
{
for (int n=0; n<numTypes; n++)
yield return n;
}
public string GetTypeName (int type)
{
return types [type].Name;
}
public int GetObjectCountForType (int type)
{
return types [type].ObjectCount;
}
public uint GetObjectSizeForType (int type)
{
return types [type].TotalSize;
}
}
}

Просмотреть файл

@ -22,6 +22,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
@ -30,19 +31,25 @@ namespace HeapShot.Reader
public class ReferenceNode
{
bool inverse;
ObjectMapReader map;
public string TypeName;
public int RefCount;
public int RefsToParent;
public uint TotalMemory;
int type;
bool globalRefs;
public ArrayList references;
public ArrayList fieldReferences;
public Hashtable refObjects = new Hashtable ();
public Hashtable parentObjects = new Hashtable ();
public Dictionary<int,int> refObjects = new Dictionary<int,int> ();
public Dictionary<int,int> parentObjects = new Dictionary<int,int> ();
public ReferenceNode (string typeName, bool inverse)
public ReferenceNode (ObjectMapReader map, int type, bool inverse)
{
TypeName = typeName;
this.map = map;
this.type = type;
TypeName = map.GetTypeName (type);
this.inverse = inverse;
}
@ -54,19 +61,27 @@ namespace HeapShot.Reader
get { return fieldReferences != null ? fieldReferences : (ICollection) Type.EmptyTypes; }
}
public void AddReference (ObjectInfo obj)
public void AddGlobalReferences ()
{
AddReference (null, obj, null);
RefCount = map.GetObjectCountForType (type);
RefsToParent = 0;
TotalMemory = map.GetObjectSizeForType (type);
globalRefs = true;
}
public void AddReference (ObjectInfo parentObject, ObjectInfo obj)
public void AddReference (int obj)
{
AddReference (-1, obj, null);
}
public void AddReference (int parentObject, int obj)
{
AddReference (parentObject, obj, (string) null);
}
void AddReference (ObjectInfo parentObject, ObjectInfo obj, string fieldName)
void AddReference (int parentObject, int obj, string fieldName)
{
if (parentObject != null && !parentObjects.ContainsKey (parentObject)) {
if (parentObject != -1 && !parentObjects.ContainsKey (parentObject)) {
parentObjects [parentObject] = parentObject;
RefsToParent++;
}
@ -99,7 +114,7 @@ namespace HeapShot.Reader
RefCount++;
refObjects.Add (obj, obj);
TotalMemory += obj.Size;
TotalMemory += map.GetObjectSize (obj);
}
public bool HasReferences {
@ -113,25 +128,28 @@ namespace HeapShot.Reader
if (references != null)
return references;
if (globalRefs) {
RefsToParent = 0;
RefCount = 0;
TotalMemory = 0;
foreach (int obj in map.GetObjectsByType (type))
AddReference (obj);
globalRefs = false;
}
references = new ArrayList ();
foreach (ObjectInfo obj in refObjects.Keys) {
foreach (int obj in refObjects.Keys) {
if (inverse) {
if (obj.Referencers != null) {
for (int n=0; n<obj.Referencers.Count; n++) {
ObjectInfo oref = (ObjectInfo) obj.Referencers [n];
ReferenceNode cnode = GetReferenceNode (oref.Type.Name);
string fname = oref.GetReferencerField (obj);
cnode.AddReference (obj, oref, fname);
}
foreach (int oref in map.GetReferencers (obj)) {
ReferenceNode cnode = GetReferenceNode (oref);
string fname = map.GetReferencerField (oref, obj);
cnode.AddReference (obj, oref, fname);
}
} else {
if (obj.References != null) {
foreach (ObjectReference oref in obj.References) {
if (oref.Object == null) continue;
ReferenceNode cnode = GetReferenceNode (oref.Object.Type.Name);
string fname = obj.GetReferencerField (oref.Object);
cnode.AddReference (obj, oref.Object, fname);
}
foreach (int oref in map.GetReferences (obj)) {
ReferenceNode cnode = GetReferenceNode (oref);
string fname = map.GetReferencerField (obj, oref);
cnode.AddReference (obj, oref, fname);
}
}
}
@ -139,7 +157,6 @@ namespace HeapShot.Reader
r.Flush ();
refObjects = null;
references.Sort (new ReferenceSorter ());
return references;
}
}
@ -149,13 +166,14 @@ namespace HeapShot.Reader
parentObjects = null;
}
public ReferenceNode GetReferenceNode (string name)
public ReferenceNode GetReferenceNode (int obj)
{
string name = map.GetObjectTypeName (obj);
foreach (ReferenceNode cnode in references) {
if (cnode.TypeName == name)
return cnode;
}
ReferenceNode nod = new ReferenceNode (name, inverse);
ReferenceNode nod = new ReferenceNode (map, map.GetObjectType (obj), inverse);
references.Add (nod);
return nod;
}

Просмотреть файл

@ -27,48 +27,13 @@ using System.Text.RegularExpressions;
namespace HeapShot.Reader
{
public class TypeInfo
public struct TypeInfo
{
uint code;
string name;
FieldInfo[] fields;
public ArrayList Objects = new ArrayList ();
internal TypeInfo (uint id, string name, FieldInfo[] fields)
{
this.code = id;
this.name = name;
this.fields = fields;
}
public uint Code {
get { return code; }
}
public string Name {
get { return name; }
}
public FieldInfo[] Fields {
get { return fields; }
}
public uint TotalSize {
get {
uint s = 0;
foreach (ObjectInfo oi in Objects)
s += oi.Size;
return s;
}
}
public string GetFieldName (uint fieldCode)
{
foreach (FieldInfo f in Fields)
if (f.Code == fieldCode)
return f.Name;
return null;
}
public uint Code;
public string Name;
public int FieldsIndex;
public int FieldsCount;
public int ObjectCount;
public uint TotalSize;
}
}

Просмотреть файл

@ -22,6 +22,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using HeapShot.Reader;
@ -88,8 +89,8 @@ namespace HeapShot {
PrintRoots (omap, type, maxlevels);
} else {
// Show the tree for a type
ReferenceNode nod = new ReferenceNode (type, inverse);
foreach (ObjectInfo obj in omap.GetObjectsByType (type)) {
ReferenceNode nod = new ReferenceNode (omap, type, inverse);
foreach (int obj in omap.GetObjectsByType (type)) {
nod.AddReference (obj);
}
nod.Print (maxlevels);
@ -97,9 +98,10 @@ namespace HeapShot {
} else {
// Show a summary
int tot = 0;
foreach (TypeInfo t in omap.GetTypes ()) {
Console.WriteLine ("{0} {1} {2}", t.Objects.Count, t.TotalSize, t.Name);
tot += t.Objects.Count;
foreach (int t in omap.GetTypes ()) {
int no = omap.GetObjectCountForType (t);
Console.WriteLine ("{0} {1} {2}", no, omap.GetObjectSizeForType (t), omap.GetTypeName (t));
tot += no;
}
Console.WriteLine ();
Console.WriteLine ("Total: " + tot);
@ -108,19 +110,19 @@ namespace HeapShot {
void PrintRoots (ObjectMapReader omap, string typeName, int maxlevels)
{
ArrayList path = new ArrayList ();
Hashtable roots = new Hashtable ();
Hashtable visited = new Hashtable ();
List<int> path = new List<int> ();
Dictionary<int,List<int>> roots = new Dictionary<int,List<int>> ();
Dictionary<int,int> visited = new Dictionary<int,int> ();
foreach (ObjectInfo obj in omap.GetObjectsByType (typeName)) {
FindRoot (visited, path, roots, obj);
foreach (int obj in omap.GetObjectsByType (typeName)) {
FindRoot (omap, visited, path, roots, obj);
visited.Clear ();
}
foreach (ArrayList ep in roots.Values) {
foreach (List<int> ep in roots.Values) {
for (int n=0; n < ep.Count && n < maxlevels; n++) {
ObjectInfo ob = (ObjectInfo) ep [n];
Console.WriteLine (n + ". " + ob.Type.Name);
int ob = ep [n];
Console.WriteLine (n + ". " + omap.GetObjectTypeName (ob));
}
if (maxlevels < ep.Count)
Console.WriteLine ("...");
@ -130,28 +132,31 @@ namespace HeapShot {
}
}
void FindRoot (Hashtable visited, ArrayList path, Hashtable roots, ObjectInfo obj)
void FindRoot (ObjectMapReader omap, Dictionary<int,int> visited, List<int> path, Dictionary<int,List<int>> roots, int obj)
{
if (visited.Contains (obj))
if (visited.ContainsKey (obj))
return;
visited [obj] = obj;
path.Add (obj);
if (obj.Referencers != null && obj.Referencers.Count > 0) {
foreach (ObjectInfo oref in obj.Referencers) {
FindRoot (visited, path, roots, oref);
}
} else {
bool hasrefs = false;
foreach (int oref in omap.GetReferencers (obj)) {
hasrefs = true;
FindRoot (omap, visited, path, roots, oref);
}
if (!hasrefs) {
// A root
ArrayList ep = (ArrayList) roots [obj];
List<int> ep = roots [obj];
if (ep == null) {
roots [obj] = path.Clone ();
roots [obj] = new List<int> (path);
} else {
if (ep.Count > path.Count)
roots [obj] = path.Clone ();
roots [obj] = new List<int> (path);
}
Console.WriteLine ("found root" + roots.Count + " " + path.Count + " " + obj.Type.Name);
foreach (ObjectInfo o in path) {
Console.Write (o.Type.Name + " / ");
Console.WriteLine ("found root" + roots.Count + " " + path.Count + " " + omap.GetObjectTypeName (obj));
foreach (int o in path) {
Console.Write (omap.GetObjectTypeName (o) + " / ");
}
Console.WriteLine ();
}

Просмотреть файл

@ -7,7 +7,7 @@ PKG_CHECK_MODULES(PROFILER, mono glib-2.0)
AC_PATH_PROG(MCS, mcs)
AC_PATH_PROG(MONO, mono)
pkglibdir=$prefix/lib/heapshot
pkglibdir=$prefix/lib/heap-shot
AC_SUBST(pkglibdir)
AC_CONFIG_FILES([HeapShot/heap-shot],[chmod +x HeapShot/heap-shot])

Просмотреть файл

@ -28,15 +28,11 @@
#include "outfile-writer.h"
#define MAGIC_NUMBER 0x4eabbdd1
#define FILE_FORMAT_VERSION 5
#define MAGIC_NUMBER 0x4eabfdd1
#define FILE_FORMAT_VERSION 6
#define FILE_LABEL "heap-shot logfile"
#define TAG_TYPE 0x01
#define TAG_METHOD 0x02
#define TAG_CONTEXT 0x03
#define TAG_GC 0x04
#define TAG_RESIZE 0x05
#define TAG_OBJECT 0x06
#define TAG_OBJECT 0x02
#define TAG_EOS 0xff
static void
@ -98,6 +94,13 @@ outfile_writer_open_objectmap (const char *filename)
write_uint32 (ofw->out, MAGIC_NUMBER);
write_int32 (ofw->out, FILE_FORMAT_VERSION);
write_string (ofw->out, FILE_LABEL);
ofw->saved_outfile_offset = ftell (ofw->out);
// we update these after dumping all objects
write_int32 (ofw->out, 0); // total # of types
write_int32 (ofw->out, 0); // total # of objects
write_int32 (ofw->out, 0); // total # of references
write_int32 (ofw->out, 0); // total # of fields
return ofw;
}
@ -108,6 +111,13 @@ outfile_writer_close (OutfileWriter *ofw)
// Write out the end-of-stream tag.
write_byte (ofw->out, TAG_EOS);
// Seek back up to the right place in the header
fseek (ofw->out, ofw->saved_outfile_offset, SEEK_SET);
write_int32 (ofw->out, ofw->type_count);
write_int32 (ofw->out, ofw->object_count);
write_int32 (ofw->out, ofw->reference_count);
write_int32 (ofw->out, ofw->field_count);
fclose (ofw->out);
}
@ -135,6 +145,7 @@ outfile_writer_dump_object_begin (OutfileWriter *ofw,
while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
write_pointer (ofw->out, field);
write_string (ofw->out, mono_field_get_name (field));
ofw->field_count++;
}
write_pointer (ofw->out, NULL);
}
@ -149,6 +160,7 @@ outfile_writer_dump_object_begin (OutfileWriter *ofw,
write_pointer (ofw->out, klass);
write_int32 (ofw->out, (gint32)0);
}
ofw->object_count++;
}
void
@ -162,5 +174,6 @@ outfile_writer_dump_object_add_reference (OutfileWriter *ofw, gpointer ref, gpoi
{
write_pointer (ofw->out, ref);
write_pointer (ofw->out, field);
ofw->reference_count++;
}

Просмотреть файл

@ -35,6 +35,10 @@ struct _OutfileWriter {
FILE *out;
GHashTable *seen_items;
int type_count;
int object_count;
int reference_count;
int field_count;
long saved_outfile_offset;
};
OutfileWriter *outfile_writer_open_objectmap (const char *filename);

Просмотреть файл

@ -21,6 +21,9 @@ namespace Application
Aux ();
Console.WriteLine ("Ready");
Console.ReadLine ();
EndType rt2 = new EndType ();
Console.WriteLine ("Ready 2");
Console.ReadLine ();
}
static void Aux ()