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:
Родитель
4a454b5010
Коммит
d293ab81e0
|
@ -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 (×tamp);
|
time (×tamp);
|
||||||
|
@ -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 (×tamp);
|
time (×tamp);
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче