Lots of hacking: file format tweaks, new reports,

better formatting, saner behavior, bug fixes, etc. etc.


svn path=/trunk/heap-buddy/; revision=51500
This commit is contained in:
Jon Trowbridge 2005-10-10 05:12:41 +00:00
Родитель 4a454b5010
Коммит d293ab81e0
16 изменённых файлов: 429 добавлений и 83 удалений

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

@ -0,0 +1,159 @@
//
// BacktracesReport.cs
//
// Copyright (C) 2005 Novell, Inc.
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
using System;
using System.Collections;
using System.IO;
using System.Text;
namespace HeapBuddy {
public class BacktracesReport : Report {
public BacktracesReport () : base ("Backtraces") { }
enum SortOrder {
Unsorted,
ByCount,
ByTotalBytes,
ByAverageBytes,
ByAverageAge
}
static string BacktraceStringifier (Backtrace bt, int max_width)
{
StringBuilder sb = new StringBuilder ();
sb.Append ("type=");
sb.Append (Util.Ellipsize (max_width-5, bt.Type.Name));
foreach (Frame frame in bt.Frames) {
if (! frame.MethodName.StartsWith ("(wrapper")) {
sb.Append ('\n');
sb.Append (Util.Ellipsize (max_width, frame.MethodName));
}
}
return sb.ToString ();
}
static string BacktraceStringifier_Full (object obj)
{
return BacktraceStringifier ((Backtrace) obj, -1);
}
static string BacktraceStringifier_Ellipsize (object obj)
{
const int max_width = 51;
return BacktraceStringifier ((Backtrace) obj, max_width);
}
override public void Run (OutfileReader reader, string [] args)
{
SortOrder order = SortOrder.ByTotalBytes;
int max_rows = 25;
bool ellipsize_names = true;
// Hacky free-form arg parser
int i = 0;
while (i < args.Length) {
string arg = args [i].ToLower ();
if (arg == "count")
order = SortOrder.ByCount;
else if (arg == "total")
order = SortOrder.ByTotalBytes;
else if (arg == "average")
order = SortOrder.ByAverageBytes;
else if (arg == "age")
order = SortOrder.ByAverageAge;
else if (arg == "all")
max_rows = -1;
else if (arg == "full" || arg == "long" || arg == "unellipsized")
ellipsize_names = false;
else {
int n = -1;
try {
n = Int32.Parse (arg);
} catch { }
if (n > 0)
max_rows = n;
}
++i;
}
// Generate the table
Table table;
table = new Table ();
table.AddHeaders ("Backtrace",
"#",
"Total",
"AvSz",
"AvAge");
if (ellipsize_names)
table.SetStringify (0, BacktraceStringifier_Ellipsize);
else
table.SetStringify (0, BacktraceStringifier_Full);
table.SetStringify (2, Util.PrettySize_Obj);
table.SetStringify (3, "0.0");
table.SetStringify (4, "0.0");
foreach (Backtrace bt in reader.Backtraces) {
table.AddRow (bt,
bt.LastObjectStats.AllocatedCount,
bt.LastObjectStats.AllocatedTotalBytes,
bt.LastObjectStats.AllocatedAverageBytes,
bt.LastObjectStats.AllocatedAverageAge);
}
switch (order) {
case SortOrder.ByCount:
table.Sort (1, false);
break;
case SortOrder.ByTotalBytes:
table.Sort (2, false);
break;
case SortOrder.ByAverageBytes:
table.Sort (3, false);
break;
case SortOrder.ByAverageAge:
table.Sort (4, false);
break;
}
table.SkipLines = true;
if (max_rows > 0)
table.MaxRows = max_rows;
Console.WriteLine (table);
if (table.RowCount > table.MaxRows) {
Console.WriteLine ();
Console.WriteLine ("(skipped {0} backtraces)", table.RowCount - table.MaxRows);
}
}
}
}

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

@ -29,6 +29,7 @@ namespace HeapBuddy {
public uint MethodCode; public uint MethodCode;
public string MethodName; public string MethodName;
public string MethodArguments;
public uint IlOffset; public uint IlOffset;
} }

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

@ -38,7 +38,9 @@ namespace HeapBuddy {
public DateTime Timestamp; public DateTime Timestamp;
public long PreGcLiveBytes; public long PreGcLiveBytes;
public int PreGcLiveObjects;
public long PostGcLiveBytes; public long PostGcLiveBytes;
public int PostGcLiveObjects;
private GcData [] gc_data; private GcData [] gc_data;
OutfileReader reader; OutfileReader reader;
@ -56,8 +58,16 @@ namespace HeapBuddy {
get { return PreGcLiveBytes - PostGcLiveBytes; } get { return PreGcLiveBytes - PostGcLiveBytes; }
} }
public double FreedPercentage { public int FreedObjects {
get { return 100.0 * FreedBytes / PreGcLiveBytes; } get { return PreGcLiveObjects - PostGcLiveObjects; }
}
public double FreedBytesPercentage {
get { return PreGcLiveBytes == 0 ? 0 : 100.0 * FreedBytes / PreGcLiveBytes; }
}
public double FreedObjectsPercentage {
get { return PreGcLiveObjects == 0 ? 0 : 100.0 * FreedObjects / PreGcLiveObjects; }
} }
public GcData [] GcData { public GcData [] GcData {

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

@ -38,6 +38,11 @@ namespace HeapBuddy {
++args_i; ++args_i;
} }
if (! File.Exists (outfile_name)) {
Console.WriteLine ("Can't find outfile '{0}'", outfile_name);
return;
}
string report_name = "summary"; string report_name = "summary";
if (args_i < args.Length && Report.Exists (args [args_i])) { if (args_i < args.Length && Report.Exists (args [args_i])) {
report_name = args [args_i]; report_name = args [args_i];

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

@ -32,6 +32,10 @@ namespace HeapBuddy {
override public void Run (OutfileReader reader, string [] args) override public void Run (OutfileReader reader, string [] args)
{ {
Table table;
table = new Table ();
table.Separator = " | ";
Resize [] resizes; Resize [] resizes;
resizes = reader.Resizes; resizes = reader.Resizes;
@ -40,6 +44,7 @@ namespace HeapBuddy {
int i_resize = 0; int i_resize = 0;
int i_gc = 0; int i_gc = 0;
long heap_size = 0;
while (i_resize < resizes.Length || i_gc < gcs.Length) { while (i_resize < resizes.Length || i_gc < gcs.Length) {
@ -51,26 +56,63 @@ namespace HeapBuddy {
if (i_gc < gcs.Length) if (i_gc < gcs.Length)
gc = gcs [i_gc]; gc = gcs [i_gc];
if (i_resize != 0 || i_gc != 0)
table.AddRow ("", "", "");
string timestamp, tag, message;
if (r != null && (gc == null || r.Generation <= gc.Generation)) { if (r != null && (gc == null || r.Generation <= gc.Generation)) {
Console.WriteLine ("{0:HH:mm:ss} | Resize | {1} -> {2}, {3} in live objects", timestamp = string.Format ("{0:HH:mm:ss}", r.Timestamp);
r.Timestamp,
Util.PrettySize (r.PreviousSize), if (r.PreviousSize == 0) {
Util.PrettySize (r.NewSize), tag = "Init";
Util.PrettySize (r.TotalLiveBytes)); message = String.Format ("Initialized heap to {0}",
Util.PrettySize (r.NewSize));
} else {
tag = "Resize";
message = String.Format ("Grew heap from {0} to {1}\n" +
"{2} in live objects\n" +
"Heap went from {3:0.0}% to {4:0.0}% capacity",
Util.PrettySize (r.PreviousSize),
Util.PrettySize (r.NewSize),
Util.PrettySize (r.TotalLiveBytes),
r.PreResizeCapacity, r.PostResizeCapacity);
}
heap_size = r.NewSize;
++i_resize; ++i_resize;
} else if (gc != null) {
} else {
timestamp = String.Format ("{0:HH:mm:ss}", gc.Timestamp);
if (gc.Generation >= 0) { if (gc.Generation >= 0) {
Console.WriteLine ("{0:HH:mm:ss} | GC {1:000} | {2} -> {3}, freed {4} ({5:0.0}%)", tag = "GC " + gc.Generation;
gc.Timestamp, message = String.Format ("Collected {0} of {1} objects ({2:0.0}%)\n" +
gc.Generation, "Collected {3} of {4} ({5:0.0}%)\n" +
Util.PrettySize (gc.PreGcLiveBytes), "Heap went from {6:0.0}% to {7:0.0}% capacity",
Util.PrettySize (gc.PostGcLiveBytes), gc.FreedObjects,
Util.PrettySize (gc.FreedBytes), gc.PreGcLiveObjects,
gc.FreedPercentage); gc.FreedObjectsPercentage,
Util.PrettySize (gc.FreedBytes),
Util.PrettySize (gc.PreGcLiveBytes),
gc.FreedBytesPercentage,
100.0 * gc.PreGcLiveBytes / heap_size,
100.0 * gc.PostGcLiveBytes / heap_size);
} else {
tag = "Exit";
message = String.Format ("{0} live objects using {1}",
gc.PreGcLiveObjects,
Util.PrettySize (gc.PreGcLiveBytes));
} }
++i_gc; ++i_gc;
} }
table.AddRow (timestamp, tag, message);
} }
table.SetAlignment (1, Alignment.Left);
table.SetAlignment (2, Alignment.Left);
Console.WriteLine (table);
} }
} }
} }

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

@ -6,6 +6,7 @@ TARGET = HeapBuddy.exe
WRAPPER = heap-buddy WRAPPER = heap-buddy
REPORT_CSFILES = \ REPORT_CSFILES = \
BacktracesReport.cs \
HistoryReport.cs \ HistoryReport.cs \
SummaryReport.cs \ SummaryReport.cs \
TypesReport.cs TypesReport.cs

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

@ -32,8 +32,8 @@ namespace HeapBuddy {
public bool Debug = false; public bool Debug = false;
const uint magic_number = 0x4eabbdd1; const uint magic_number = 0x4eabbdd1;
const int expected_log_version = 4; const int expected_log_version = 5;
const int expected_summary_version = 1; const int expected_summary_version = 2;
const string log_file_label = "heap-buddy logfile"; const string log_file_label = "heap-buddy logfile";
const string summary_file_label = "heap-buddy summary"; const string summary_file_label = "heap-buddy summary";
@ -50,6 +50,9 @@ namespace HeapBuddy {
int n_backtraces; int n_backtraces;
int n_resizes; int n_resizes;
public long TotalAllocatedBytes;
public int TotalAllocatedObjects;
// Offsets in the summary file // Offsets in the summary file
long type_name_data_offset = -1; long type_name_data_offset = -1;
long method_name_data_offset = -1; long method_name_data_offset = -1;
@ -68,6 +71,7 @@ namespace HeapBuddy {
private struct Method { private struct Method {
public string Name; public string Name;
public string Arguments;
public long Position; // of the name in the summary file public long Position; // of the name in the summary file
} }
@ -177,8 +181,12 @@ namespace HeapBuddy {
{ {
uint this_magic; uint this_magic;
this_magic = reader.ReadUInt32 (); this_magic = reader.ReadUInt32 ();
if (this_magic != magic_number) if (this_magic != magic_number) {
throw new Exception ("Bad magic number in heap-buddy outfile"); string msg;
msg = String.Format ("Bad magic number: expected {0}, found {1}",
magic_number, this_magic);
throw new Exception (msg);
}
int this_version; int this_version;
this_version = reader.ReadInt32 (); this_version = reader.ReadInt32 ();
@ -235,6 +243,9 @@ namespace HeapBuddy {
n_backtraces = reader.ReadInt32 (); n_backtraces = reader.ReadInt32 ();
n_resizes = reader.ReadInt32 (); n_resizes = reader.ReadInt32 ();
TotalAllocatedBytes = reader.ReadInt64 ();
TotalAllocatedObjects = reader.ReadInt32 ();
Spew ("GCs = {0}", n_gcs); Spew ("GCs = {0}", n_gcs);
Spew ("Types = {0}", n_types); Spew ("Types = {0}", n_types);
Spew ("Methods = {0}", n_methods); Spew ("Methods = {0}", n_methods);
@ -265,6 +276,8 @@ namespace HeapBuddy {
writer.Write (n_methods); writer.Write (n_methods);
writer.Write (n_backtraces); writer.Write (n_backtraces);
writer.Write (n_resizes); writer.Write (n_resizes);
writer.Write (TotalAllocatedBytes);
writer.Write (TotalAllocatedObjects);
Spew ("Finished writing header"); Spew ("Finished writing header");
} }
@ -447,6 +460,7 @@ namespace HeapBuddy {
gc.TimeT = reader.ReadInt64 (); gc.TimeT = reader.ReadInt64 ();
gc.Timestamp = Util.ConvertTimeT (gc.TimeT); gc.Timestamp = Util.ConvertTimeT (gc.TimeT);
gc.PreGcLiveBytes = reader.ReadInt64 (); gc.PreGcLiveBytes = reader.ReadInt64 ();
gc.PreGcLiveObjects = reader.ReadInt32 ();
int n; int n;
n = reader.ReadInt32 (); n = reader.ReadInt32 ();
@ -460,6 +474,7 @@ namespace HeapBuddy {
combsort_raw_gc_data (raw); combsort_raw_gc_data (raw);
gc.PostGcLiveBytes = reader.ReadInt64 (); gc.PostGcLiveBytes = reader.ReadInt64 ();
gc.PostGcLiveObjects = reader.ReadInt32 ();
gcs [i_gc] = gc; gcs [i_gc] = gc;
raw_gc_data [i_gc] = raw; raw_gc_data [i_gc] = raw;
@ -746,11 +761,15 @@ namespace HeapBuddy {
// and replace the backtrace codes. // and replace the backtrace codes.
for (int i = 0; i < backtraces.Length; ++i) { for (int i = 0; i < backtraces.Length; ++i) {
backtrace_type_codes [i] = TranslateTypeCode (backtrace_type_codes [i]); backtrace_type_codes [i] = TranslateTypeCode (backtrace_type_codes [i]);
backtraces [i].Type = types [backtrace_type_codes [i]];
for (int j = 0; j < backtraces [i].Frames.Length; ++j) { for (int j = 0; j < backtraces [i].Frames.Length; ++j) {
uint code; uint code;
code = backtraces [i].Frames [j].MethodCode; code = backtraces [i].Frames [j].MethodCode;
code = TranslateMethodCode (code); code = TranslateMethodCode (code);
backtraces [i].Frames [j].MethodCode = code; backtraces [i].Frames [j].MethodCode = code;
GetMethod (code,
out backtraces [i].Frames [j].MethodName,
out backtraces [i].Frames [j].MethodArguments);
} }
} }
@ -928,7 +947,9 @@ namespace HeapBuddy {
gc.TimeT = reader.ReadInt64 (); gc.TimeT = reader.ReadInt64 ();
gc.Timestamp = Util.ConvertTimeT (gc.TimeT); gc.Timestamp = Util.ConvertTimeT (gc.TimeT);
gc.PreGcLiveBytes = reader.ReadInt64 (); gc.PreGcLiveBytes = reader.ReadInt64 ();
gc.PreGcLiveObjects = reader.ReadInt32 ();
gc.PostGcLiveBytes = reader.ReadInt64 (); gc.PostGcLiveBytes = reader.ReadInt64 ();
gc.PostGcLiveObjects = reader.ReadInt32 ();
gcs [i] = gc; gcs [i] = gc;
gc_pos [i] = reader.ReadInt64 (); gc_pos [i] = reader.ReadInt64 ();
@ -1031,7 +1052,9 @@ namespace HeapBuddy {
writer.Write (gcs [i].Generation); writer.Write (gcs [i].Generation);
writer.Write (gcs [i].TimeT); writer.Write (gcs [i].TimeT);
writer.Write (gcs [i].PreGcLiveBytes); writer.Write (gcs [i].PreGcLiveBytes);
writer.Write (gcs [i].PreGcLiveObjects);
writer.Write (gcs [i].PostGcLiveBytes); writer.Write (gcs [i].PostGcLiveBytes);
writer.Write (gcs [i].PostGcLiveObjects);
writer.Write (gc_pos [i]); writer.Write (gc_pos [i]);
} }
} }
@ -1054,10 +1077,18 @@ namespace HeapBuddy {
get { return resizes; } get { return resizes; }
} }
public Resize LastResize {
get { return resizes [resizes.Length-1]; }
}
public Gc [] Gcs { public Gc [] Gcs {
get { return gcs; } get { return gcs; }
} }
public Gc LastGc {
get { return gcs [gcs.Length-1]; }
}
public Backtrace [] Backtraces { public Backtrace [] Backtraces {
get { return backtraces; } get { return backtraces; }
} }
@ -1091,14 +1122,21 @@ namespace HeapBuddy {
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
private string GetMethodName (uint code) private void GetMethod (uint code, out string name, out string args)
{ {
if (methods [code].Name == null) { if (methods [code].Name == null) {
lazy_reader.BaseStream.Seek (methods [code].Position, SeekOrigin.Begin); lazy_reader.BaseStream.Seek (methods [code].Position, SeekOrigin.Begin);
methods [code].Name = lazy_reader.ReadString ();
string method;
method = lazy_reader.ReadString ();
int i = method.IndexOf (" (");
methods [code].Name = method.Substring (0, i);
methods [code].Arguments = method.Substring (i+1);
} }
return methods [code].Name; name = methods [code].Name;
args = methods [code].Arguments;
} }
public Frame [] GetFrames (uint backtrace_code) public Frame [] GetFrames (uint backtrace_code)
@ -1116,7 +1154,10 @@ namespace HeapBuddy {
} }
for (int i = 0; i < length; ++i) for (int i = 0; i < length; ++i)
frames [i].MethodName = GetMethodName (frames [i].MethodCode); GetMethod (frames [i].MethodCode,
out frames [i].MethodName,
out frames [i].MethodArguments);
return frames; return frames;
} }

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

@ -39,6 +39,15 @@ namespace HeapBuddy {
public long TotalLiveBytes; public long TotalLiveBytes;
public double PreResizeCapacity {
get { return PreviousSize == 0 ? 0 : 100.0 * TotalLiveBytes / PreviousSize; }
}
public double PostResizeCapacity {
get { return PreviousSize == 0 ? 0 : 100.0 * TotalLiveBytes / NewSize; }
}
// You need to set PreviousSize by hand. // You need to set PreviousSize by hand.
public void Read (BinaryReader reader, int generation) public void Read (BinaryReader reader, int generation)
{ {

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

@ -39,13 +39,15 @@ namespace HeapBuddy {
table.AddRow ("", ""); table.AddRow ("", "");
table.AddRow ("Filename:", reader.Filename); table.AddRow ("Filename:", reader.Filename);
table.AddRow ("Allocated Bytes:", Util.PrettySize (reader.TotalAllocatedBytes));
table.AddRow ("Allocated Objects:", reader.TotalAllocatedObjects);
table.AddRow ("GCs:", reader.Gcs.Length); table.AddRow ("GCs:", reader.Gcs.Length);
table.AddRow ("Resizes:", reader.Resizes.Length); table.AddRow ("Resizes:", reader.Resizes.Length);
table.AddRow ("Final heap size:", Util.PrettySize (reader.Resizes [reader.Resizes.Length-1].NewSize)); table.AddRow ("Final heap size:", Util.PrettySize (reader.LastResize.NewSize));
table.AddRow ("", ""); table.AddRow ("", "");
table.AddRow ("Allocated Types:", reader.Types.Length); table.AddRow ("Distinct Types:", reader.Types.Length);
table.AddRow ("Backtraces:", reader.Backtraces.Length); table.AddRow ("Backtraces:", reader.Backtraces.Length);
table.SetAlignment (1, Alignment.Left); table.SetAlignment (1, Alignment.Left);

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

@ -36,14 +36,15 @@ namespace HeapBuddy {
public class Table { public class Table {
private int cols = -1; private int n_cols = -1;
private string [] headers; private string [] headers;
private Alignment [] alignment; private Alignment [] alignment;
private int [] max_length;
private Stringify [] stringify; private Stringify [] stringify;
private ArrayList rows = new ArrayList (); private ArrayList rows = new ArrayList ();
public int MaxRows = int.MaxValue; public int MaxRows = int.MaxValue;
public bool SkipLines = false;
public string Separator = " ";
public int RowCount { public int RowCount {
get { return rows.Count; } get { return rows.Count; }
@ -51,22 +52,20 @@ namespace HeapBuddy {
private void CheckColumns (ICollection whatever) private void CheckColumns (ICollection whatever)
{ {
if (cols == -1) { if (n_cols == -1) {
cols = whatever.Count; n_cols = whatever.Count;
if (cols == 0) if (n_cols == 0)
throw new Exception ("Can't have zero columns!"); throw new Exception ("Can't have zero columns!");
alignment = new Alignment [cols]; alignment = new Alignment [n_cols];
for (int i = 0; i < cols; ++i) for (int i = 0; i < n_cols; ++i)
alignment [i] = Alignment.Right; alignment [i] = Alignment.Right;
max_length = new int [cols]; stringify = new Stringify [n_cols];
stringify = new Stringify [cols];
} else if (cols != whatever.Count) { } else if (n_cols != whatever.Count) {
throw new Exception (String.Format ("Expected {0} columns, got {1}", cols, whatever.Count)); throw new Exception (String.Format ("Expected {0} columns, got {1}", n_cols, whatever.Count));
} }
} }
@ -74,24 +73,12 @@ namespace HeapBuddy {
{ {
CheckColumns (args); CheckColumns (args);
headers = args; headers = args;
for (int i = 0; i < cols; ++i) {
int len = args [i].Length;
if (len > max_length [i])
max_length [i] = len;
}
} }
public void AddRow (params object [] row) public void AddRow (params object [] row)
{ {
CheckColumns (row); CheckColumns (row);
rows.Add (row); rows.Add (row);
for (int i = 0; i < cols; ++i) {
string str;
str = stringify [i] != null ? stringify [i] (row [i]) : row [i].ToString ();
int len = str.Length;
if (len > max_length [i])
max_length [i] = len;
}
} }
public void SetAlignment (int i, Alignment align) public void SetAlignment (int i, Alignment align)
@ -178,8 +165,8 @@ namespace HeapBuddy {
private string GetColumnSeparator (int i) private string GetColumnSeparator (int i)
{ {
if (0 <= i && i < cols-1) if (0 <= i && i < n_cols-1)
return " "; return Separator;
return ""; return "";
} }
@ -201,33 +188,79 @@ namespace HeapBuddy {
override public string ToString () override public string ToString ()
{ {
StringBuilder sb; int n_rows;
n_rows = rows.Count;
if (n_rows > MaxRows)
n_rows = MaxRows;
int [] max_width;
max_width = new int [n_cols];
if (headers != null)
for (int i = 0; i < headers.Length; ++i)
max_width [i] = headers [i].Length;
string [][][] grid;
grid = new string [n_rows] [][];
for (int r = 0; r < n_rows; ++r) {
object [] row = (object []) rows [r];
grid [r] = new string [n_cols] [];
for (int c = 0; c < n_cols; ++c) {
string str;
str = stringify [c] != null ? stringify [c] (row [c]) : row [c].ToString ();
grid [r] [c] = str.Split ('\n');
foreach (string part in grid [r] [c])
if (part.Length > max_width [c])
max_width [c] = part.Length;
}
}
StringBuilder sb, line;
sb = new StringBuilder (); sb = new StringBuilder ();
line = new StringBuilder ();
if (headers != null) { if (headers != null) {
sb.Append (GetColumnSeparator (-1)); sb.Append (GetColumnSeparator (-1));
for (int i = 0; i < cols; ++i) { for (int i = 0; i < n_cols; ++i) {
sb.Append (Pad (max_length [i], Alignment.Center, headers [i])); sb.Append (Pad (max_width [i], Alignment.Center, headers [i]));
sb.Append (GetColumnSeparator (i)); sb.Append (GetColumnSeparator (i));
} }
sb.Append ('\n'); sb.Append ('\n');
} }
int count = 0; for (int r = 0; r < n_rows; ++r) {
foreach (object [] row in rows) {
if (count != 0) bool did_something = true;
sb.Append ('\n'); int i = 0;
sb.Append (GetColumnSeparator (-1));
for (int i = 0; i < cols; ++i) { if (SkipLines && (r != 0 || headers != null))
string str; sb.Append ('\n');
str = stringify [i] != null ? stringify [i] (row [i]) : row [i].ToString ();
str = Pad (max_length [i], alignment [i], str); while (did_something) {
sb.Append (str); did_something = false;
sb.Append (GetColumnSeparator (i));
line.Length = 0;
line.Append (GetColumnSeparator (-1));
for (int c = 0; c < n_cols; ++c) {
string str = "";
if (i < grid [r] [c].Length) {
str = grid [r][c][i];
did_something = true;
}
str = Pad (max_width [c], alignment [c], str);
line.Append (str);
line.Append (GetColumnSeparator (c));
}
if (did_something) {
if (r != 0 || i != 0)
sb.Append ('\n');
sb.Append (line);
}
++i;
} }
++count;
if (count >= MaxRows)
break;
} }
return sb.ToString (); return sb.ToString ();

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

@ -34,9 +34,8 @@ namespace HeapBuddy {
static public string Ellipsize (int max_length, string str) static public string Ellipsize (int max_length, string str)
{ {
if (str.Length < max_length) if (str.Length < max_length || max_length < 0)
return str; return str;
return str.Substring (0, max_length/2 - 2) + "..." + str.Substring (str.Length - max_length/2 + 2); return str.Substring (0, max_length/2 - 2) + "..." + str.Substring (str.Length - max_length/2 + 2);
} }

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

@ -23,6 +23,7 @@
* USA. * USA.
*/ */
#include <mono/metadata/mono-debug.h>
#include "backtrace.h" #include "backtrace.h"
struct HashAndCountInfo { struct HashAndCountInfo {
@ -64,7 +65,7 @@ stack_walk_build_frame_vector_fn (MonoMethod *method, gint32 native_offset, gint
StackFrame *frame; StackFrame *frame;
frame = g_new0 (StackFrame, 1); frame = g_new0 (StackFrame, 1);
frame->method = method; frame->method = method;
frame->native_offset = native_offset; frame->native_offset = native_offset;
frame->il_offset = il_offset; frame->il_offset = il_offset;

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

@ -44,6 +44,8 @@ struct _MonoProfiler {
GHashTable *accountant_hash; GHashTable *accountant_hash;
gint64 total_allocated_bytes; gint64 total_allocated_bytes;
gint64 total_live_bytes; gint64 total_live_bytes;
gint32 total_allocated_objects;
gint32 total_live_objects;
gint32 n_dirty_accountants; gint32 n_dirty_accountants;
OutfileWriter *outfile_writer; OutfileWriter *outfile_writer;
}; };
@ -86,6 +88,8 @@ heap_buddy_alloc_func (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
accountant_register_object (acct, obj, size); accountant_register_object (acct, obj, size);
p->total_allocated_bytes += size; p->total_allocated_bytes += size;
p->total_live_bytes += size; p->total_live_bytes += size;
p->total_allocated_objects++;
p->total_live_objects++;
mono_mutex_unlock (&p->lock); mono_mutex_unlock (&p->lock);
} }
@ -98,6 +102,7 @@ post_gc_tallying_fn (gpointer key, gpointer value, gpointer user_data)
accountant_post_gc_processing (acct); accountant_post_gc_processing (acct);
p->total_live_bytes += acct->n_live_bytes; p->total_live_bytes += acct->n_live_bytes;
p->total_live_objects += acct->n_live_objects;
if (acct->dirty) if (acct->dirty)
++p->n_dirty_accountants; ++p->n_dirty_accountants;
} }
@ -120,6 +125,7 @@ static void
heap_buddy_gc_func (MonoProfiler *p, MonoGCEvent e, int gen) heap_buddy_gc_func (MonoProfiler *p, MonoGCEvent e, int gen)
{ {
gint64 prev_total_live_bytes; gint64 prev_total_live_bytes;
gint32 prev_total_live_objects;
if (e != MONO_GC_EVENT_MARK_END) if (e != MONO_GC_EVENT_MARK_END)
return; return;
@ -127,16 +133,24 @@ heap_buddy_gc_func (MonoProfiler *p, MonoGCEvent e, int gen)
mono_mutex_lock (&p->lock); mono_mutex_lock (&p->lock);
prev_total_live_bytes = p->total_live_bytes; prev_total_live_bytes = p->total_live_bytes;
prev_total_live_objects = p->total_live_objects;
p->total_live_bytes = 0; p->total_live_bytes = 0;
p->total_live_objects = 0;
p->n_dirty_accountants = 0; p->n_dirty_accountants = 0;
g_hash_table_foreach (p->accountant_hash, post_gc_tallying_fn, p); g_hash_table_foreach (p->accountant_hash, post_gc_tallying_fn, p);
outfile_writer_gc_begin (p->outfile_writer, outfile_writer_gc_begin (p->outfile_writer,
gen < 0, // negative gen == this is final gen < 0, // negative gen == this is final
prev_total_live_bytes, p->n_dirty_accountants); prev_total_live_bytes,
prev_total_live_objects,
p->n_dirty_accountants);
g_hash_table_foreach (p->accountant_hash, post_gc_logging_fn, p); g_hash_table_foreach (p->accountant_hash, post_gc_logging_fn, p);
outfile_writer_gc_end (p->outfile_writer, p->total_live_bytes); outfile_writer_gc_end (p->outfile_writer,
p->total_allocated_bytes,
p->total_allocated_objects,
p->total_live_bytes,
p->total_live_objects);
mono_mutex_unlock (&p->lock); mono_mutex_unlock (&p->lock);
} }

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

@ -29,7 +29,7 @@
#include "outfile-writer.h" #include "outfile-writer.h"
#define MAGIC_NUMBER 0x4eabbdd1 #define MAGIC_NUMBER 0x4eabbdd1
#define FILE_FORMAT_VERSION 4 #define FILE_FORMAT_VERSION 5
#define FILE_LABEL "heap-buddy logfile" #define FILE_LABEL "heap-buddy logfile"
#define TAG_TYPE 0x01 #define TAG_TYPE 0x01
@ -127,12 +127,16 @@ outfile_writer_open (const char *filename)
write_int32 (ofw->out, -1); // total # of methods write_int32 (ofw->out, -1); // total # of methods
write_int32 (ofw->out, -1); // total # of contexts/backtraces write_int32 (ofw->out, -1); // total # of contexts/backtraces
write_int32 (ofw->out, -1); // total # of resizes write_int32 (ofw->out, -1); // total # of resizes
write_int64 (ofw->out, -1); // total # of allocated bytes
write_int32 (ofw->out, -1); // total # of allocated objects
return ofw; return ofw;
} }
static void static void
outfile_writer_update_totals (OutfileWriter *ofw) outfile_writer_update_totals (OutfileWriter *ofw,
gint64 total_allocated_bytes,
gint32 total_allocated_objects)
{ {
// Seek back up to the right place in the header // Seek back up to the right place in the header
fseek (ofw->out, ofw->saved_outfile_offset, SEEK_SET); fseek (ofw->out, ofw->saved_outfile_offset, SEEK_SET);
@ -145,6 +149,11 @@ outfile_writer_update_totals (OutfileWriter *ofw)
write_int32 (ofw->out, ofw->context_count); write_int32 (ofw->out, ofw->context_count);
write_int32 (ofw->out, ofw->resize_count); write_int32 (ofw->out, ofw->resize_count);
if (total_allocated_bytes >= 0) {
write_int64 (ofw->out, total_allocated_bytes);
write_int32 (ofw->out, total_allocated_objects);
}
// Seek back to the end of the outfile // Seek back to the end of the outfile
fseek (ofw->out, 0, SEEK_END); fseek (ofw->out, 0, SEEK_END);
} }
@ -216,7 +225,11 @@ outfile_writer_add_accountant (OutfileWriter *ofw,
// total_live_bytes is the total size of all of the live objects // total_live_bytes is the total size of all of the live objects
// before the GC // before the GC
void void
outfile_writer_gc_begin (OutfileWriter *ofw, gboolean is_final, gint64 total_live_bytes, gint32 n_accountants) outfile_writer_gc_begin (OutfileWriter *ofw,
gboolean is_final,
gint64 total_live_bytes,
gint32 total_live_objects,
gint32 n_accountants)
{ {
time_t timestamp; time_t timestamp;
time (&timestamp); time (&timestamp);
@ -225,6 +238,7 @@ outfile_writer_gc_begin (OutfileWriter *ofw, gboolean is_final, gint64 total_liv
write_int32 (ofw->out, is_final ? -1 : ofw->gc_count); write_int32 (ofw->out, is_final ? -1 : ofw->gc_count);
write_int64 (ofw->out, (gint64) timestamp); write_int64 (ofw->out, (gint64) timestamp);
write_int64 (ofw->out, total_live_bytes); write_int64 (ofw->out, total_live_bytes);
write_int32 (ofw->out, total_live_objects);
write_int32 (ofw->out, n_accountants); write_int32 (ofw->out, n_accountants);
++ofw->gc_count; ++ofw->gc_count;
@ -248,15 +262,22 @@ outfile_writer_gc_log_stats (OutfileWriter *ofw,
// total_live_bytes is the total size of all live objects // total_live_bytes is the total size of all live objects
// after the GC is finished // after the GC is finished
void void
outfile_writer_gc_end (OutfileWriter *ofw, gint64 total_live_bytes) outfile_writer_gc_end (OutfileWriter *ofw,
gint64 total_allocated_bytes,
gint32 total_allocated_objects,
gint64 total_live_bytes,
gint32 total_live_objects)
{ {
write_int64 (ofw->out, total_live_bytes); write_int64 (ofw->out, total_live_bytes);
outfile_writer_update_totals (ofw); write_int32 (ofw->out, total_live_objects);
outfile_writer_update_totals (ofw, total_allocated_bytes, total_allocated_objects);
fflush (ofw->out); fflush (ofw->out);
} }
void void
outfile_writer_resize (OutfileWriter *ofw, gint64 new_size, gint64 total_live_bytes) outfile_writer_resize (OutfileWriter *ofw,
gint64 new_size,
gint64 total_live_bytes)
{ {
time_t timestamp; time_t timestamp;
time (&timestamp); time (&timestamp);
@ -266,7 +287,7 @@ outfile_writer_resize (OutfileWriter *ofw, gint64 new_size, gint64 total_live_by
write_int64 (ofw->out, new_size); write_int64 (ofw->out, new_size);
write_int64 (ofw->out, total_live_bytes); write_int64 (ofw->out, total_live_bytes);
++ofw->resize_count; ++ofw->resize_count;
outfile_writer_update_totals (ofw); outfile_writer_update_totals (ofw, -1, -1);
fflush (ofw->out); fflush (ofw->out);
} }

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

@ -47,11 +47,19 @@ void outfile_writer_close (OutfileWriter *ofw);
void outfile_writer_add_accountant (OutfileWriter *ofw, Accountant *acct); void outfile_writer_add_accountant (OutfileWriter *ofw, Accountant *acct);
void outfile_writer_gc_begin (OutfileWriter *ofw, gboolean is_final, gint64 total_live_bytes, gint32 n_accountants); void outfile_writer_gc_begin (OutfileWriter *ofw,
gboolean is_final,
gint64 total_live_bytes,
gint32 total_live_objects,
gint32 n_accountants);
void outfile_writer_gc_log_stats (OutfileWriter *ofw, Accountant *acct); void outfile_writer_gc_log_stats (OutfileWriter *ofw, Accountant *acct);
void outfile_writer_gc_end (OutfileWriter *ofw, gint64 total_live_bytes); void outfile_writer_gc_end (OutfileWriter *ofw,
gint64 total_allocated_bytes,
gint32 total_allocated_objects,
gint64 total_live_bytes,
gint32 total_live_objects);
void outfile_writer_resize (OutfileWriter *ofw, gint64 new_size, gint64 total_live_bytes); void outfile_writer_resize (OutfileWriter *ofw, gint64 new_size, gint64 total_live_bytes);

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

@ -20,7 +20,7 @@ ALL_OUTFILES = $(ALL_CSFILES:%.cs=%.outfile)
%.outfile: %.exe %.outfile: %.exe
@echo "generating $@" @echo "generating $@"
LD_LIBRARY_PATH=../profiler/.libs:$LD_LIBRARY_PATH $(RUNTIME) --profile=heap-buddy:$@ $^ LD_LIBRARY_PATH=../profiler/.libs:$LD_LIBRARY_PATH $(RUNTIME) --debug --profile=heap-buddy:$@ $^
test: $(ALL_OUTFILES) test: $(ALL_OUTFILES)