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 string MethodName;
public string MethodArguments;
public uint IlOffset;
}

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

@ -38,7 +38,9 @@ namespace HeapBuddy {
public DateTime Timestamp;
public long PreGcLiveBytes;
public int PreGcLiveObjects;
public long PostGcLiveBytes;
public int PostGcLiveObjects;
private GcData [] gc_data;
OutfileReader reader;
@ -56,8 +58,16 @@ namespace HeapBuddy {
get { return PreGcLiveBytes - PostGcLiveBytes; }
}
public double FreedPercentage {
get { return 100.0 * FreedBytes / PreGcLiveBytes; }
public int FreedObjects {
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 {

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

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

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

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

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

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

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

@ -39,6 +39,15 @@ namespace HeapBuddy {
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.
public void Read (BinaryReader reader, int generation)
{

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

@ -39,13 +39,15 @@ namespace HeapBuddy {
table.AddRow ("", "");
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 ("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 ("Allocated Types:", reader.Types.Length);
table.AddRow ("Distinct Types:", reader.Types.Length);
table.AddRow ("Backtraces:", reader.Backtraces.Length);
table.SetAlignment (1, Alignment.Left);

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

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

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

@ -34,9 +34,8 @@ namespace HeapBuddy {
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.Substring (0, max_length/2 - 2) + "..." + str.Substring (str.Length - max_length/2 + 2);
}

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

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

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

@ -44,6 +44,8 @@ struct _MonoProfiler {
GHashTable *accountant_hash;
gint64 total_allocated_bytes;
gint64 total_live_bytes;
gint32 total_allocated_objects;
gint32 total_live_objects;
gint32 n_dirty_accountants;
OutfileWriter *outfile_writer;
};
@ -86,6 +88,8 @@ heap_buddy_alloc_func (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
accountant_register_object (acct, obj, size);
p->total_allocated_bytes += size;
p->total_live_bytes += size;
p->total_allocated_objects++;
p->total_live_objects++;
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);
p->total_live_bytes += acct->n_live_bytes;
p->total_live_objects += acct->n_live_objects;
if (acct->dirty)
++p->n_dirty_accountants;
}
@ -120,6 +125,7 @@ static void
heap_buddy_gc_func (MonoProfiler *p, MonoGCEvent e, int gen)
{
gint64 prev_total_live_bytes;
gint32 prev_total_live_objects;
if (e != MONO_GC_EVENT_MARK_END)
return;
@ -127,16 +133,24 @@ heap_buddy_gc_func (MonoProfiler *p, MonoGCEvent e, int gen)
mono_mutex_lock (&p->lock);
prev_total_live_bytes = p->total_live_bytes;
prev_total_live_objects = p->total_live_objects;
p->total_live_bytes = 0;
p->total_live_objects = 0;
p->n_dirty_accountants = 0;
g_hash_table_foreach (p->accountant_hash, post_gc_tallying_fn, p);
outfile_writer_gc_begin (p->outfile_writer,
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);
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);
}

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

@ -29,7 +29,7 @@
#include "outfile-writer.h"
#define MAGIC_NUMBER 0x4eabbdd1
#define FILE_FORMAT_VERSION 4
#define FILE_FORMAT_VERSION 5
#define FILE_LABEL "heap-buddy logfile"
#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 contexts/backtraces
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;
}
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
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->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
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
// before the GC
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 (&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_int64 (ofw->out, (gint64) timestamp);
write_int64 (ofw->out, total_live_bytes);
write_int32 (ofw->out, total_live_objects);
write_int32 (ofw->out, n_accountants);
++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
// after the GC is finished
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);
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);
}
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 (&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, total_live_bytes);
++ofw->resize_count;
outfile_writer_update_totals (ofw);
outfile_writer_update_totals (ofw, -1, -1);
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_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_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);

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

@ -20,7 +20,7 @@ ALL_OUTFILES = $(ALL_CSFILES:%.cs=%.outfile)
%.outfile: %.exe
@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)