* ProfileReader.cs: Update file format

	* TypeTabulator.cs: cope with changes

In runtime-profiler:
2005-01-16  Ben Maurer  <bmaurer@ximian.com>

	* gc-profiler.c: Emit dumps of the heap about every MB of
	data. This will allow the reader to do stuff faster. Also, emit
	tables of the size of the heap over time


svn path=/trunk/heap-prof/; revision=38999
This commit is contained in:
Ben Maurer 2005-01-17 01:27:04 +00:00
Родитель 0759cbeabb
Коммит 6075cc4504
5 изменённых файлов: 245 добавлений и 49 удалений

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

@ -1,3 +1,9 @@
2005-01-16 Ben Maurer <bmaurer@ximian.com>
* gc-profiler.c: Emit dumps of the heap about every MB of
data. This will allow the reader to do stuff faster. Also, emit
tables of the size of the heap over time
2005-01-15 Ben Maurer <bmaurer@ximian.com>
* gc-profiler.c: Emit heap size info. File format updates.

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

@ -14,8 +14,14 @@
#include <mono/metadata/profiler.h>
#define leu32 GUINT32_TO_LE
#define lnatu32 GUINT32_FROM_LE
#define leu64 GINT64_TO_LE
typedef enum {
HEAP_PROF_EVENT_GC = 0,
HEAP_PROF_EVENT_RESIZE_HEAP = 1,
HEAP_PROF_EVENT_CHECKPOINT = 2
} HeapProfEvent;
typedef struct AllocRec AllocRec;
@ -51,6 +57,18 @@ struct _MonoProfiler {
AllocRec* live_allocs;
guint32 t_zero;
guint64 foffset;
int context_live_objects_size;
int* context_live_objects;
int type_live_data_size;
int* type_live_data;
int total_live_bytes;
GPtrArray* timeline;
guint64 last_checkpoint;
};
@ -70,10 +88,12 @@ static const guint8 heap_prof_md_sig [] = {
0xaa, 0x93, 0xc8, 0x76, 0xf4, 0x6a, 0x95, 0x11
};
static const guint32 heap_prof_version = 3;
static const guint32 heap_prof_version = 4;
#define BT_SIZE 5
#define CHECKPOINT_SPACING (1024*1024) /* 1 MB */
typedef struct {
guint8 signature [16];
guint32 version;
@ -85,17 +105,39 @@ typedef struct {
} HeapProfAllocationRec;
typedef struct {
guint32 time;
HeapProfEvent event;
guint32 event_num;
guint32 context_size;
guint32 type_size;
} HeapProfCheckpointRec;
typedef struct {
guint32 time;
guint32 gc_num;
HeapProfEvent event;
guint32 event_num;
HeapProfGcFreedRec freed [MONO_ZERO_LEN_ARRAY];
} HeapProfGCRec;
typedef struct {
guint32 time;
guint32 new_size; /* high bit is set */
} HeapProfGCHeapResize;
HeapProfEvent event;
guint32 event_num;
guint32 new_size;
} HeapProfHeapResizeRec;
typedef struct {
guint32 time;
HeapProfEvent event;
guint32 size_high;
guint32 size_low;
guint64 file_pos;
} HeapProfTimelineRec;
static guint32
get_delta_t (MonoProfiler *p)
@ -133,7 +175,15 @@ typedef struct {
guint32 bt;
} IdxAllocationCtx;
#define resize_array(arr, old_size, new_size) do { \
gpointer __x = g_malloc0 ((new_size) * sizeof (*arr)); \
if (arr) \
memcpy (__x, arr, (old_size) * sizeof (*arr)); \
arr = __x; \
old_size = (new_size); \
} while (0)
static guint32
get_method_idx (MonoProfiler *p, MonoMethod* m)
{
@ -161,6 +211,9 @@ get_type_idx (MonoProfiler *p, MonoClass* klass)
idx_plus_one = p->klass_table->len;
g_hash_table_insert (p->klass_to_table_idx, klass, idx_plus_one);
if (idx_plus_one > p->type_live_data_size)
resize_array (p->type_live_data, p->type_live_data_size, MAX (p->type_live_data_size << 1, idx_plus_one));
}
return leu32 (idx_plus_one - 1);
@ -210,11 +263,34 @@ get_ctx_idx (MonoProfiler *p, AllocationCtx* ctx)
idx_plus_one = p->ctx_table->len;
g_hash_table_insert (p->ctx_to_table_idx, g_memdup (ctx, sizeof (*ctx)), idx_plus_one);
if (idx_plus_one > p->context_live_objects_size)
resize_array (p->context_live_objects, p->context_live_objects_size, MAX (p->context_live_objects_size << 1, idx_plus_one));
}
return leu32 (idx_plus_one - 1);
}
static void
record_obj (MonoProfiler* p, guint32 ctx_idx, gboolean is_alloc)
{
guint32 cidx = lnatu32 (ctx_idx);
IdxAllocationCtx* ctx = g_ptr_array_index (p->ctx_table, cidx);
guint32 tidx = lnatu32 (ctx->klass);
guint32 size = lnatu32 (ctx->size);
if (is_alloc) {
p->total_live_bytes += size;
p->type_live_data [tidx] += size;
p->context_live_objects [cidx] ++;
} else {
p->total_live_bytes -= size;
p->type_live_data [tidx] -= size;
p->context_live_objects [cidx] --;
}
}
typedef struct {
AllocationCtx* c;
int pos;
@ -231,6 +307,52 @@ get_bt (MonoMethod *m, gint no, gint ilo, gboolean managed, AllocBTData* data)
return data->pos == BT_SIZE;
}
static void
write_checkpoint_if_needed (MonoProfiler* p)
{
HeapProfCheckpointRec rec;
HeapProfTimelineRec* trec;
guint32* ctx_rec;
guint32* type_rec;
guint64 pos;
guint32 time = get_delta_t (p);
int i;
if (p->last_checkpoint + CHECKPOINT_SPACING > p->foffset)
return;
trec = g_new0 (HeapProfTimelineRec, 1);
rec.time = leu32 (time | (1 << 31));
rec.event = leu32 (HEAP_PROF_EVENT_CHECKPOINT);
rec.event_num = p->timeline->len + 1;
rec.context_size = leu32 (p->ctx_table->len);
rec.type_size = leu32 (p->klass_table->len);
ctx_rec = g_newa (guint32, p->ctx_table->len);
type_rec = g_newa (guint32, p->klass_table->len);
for (i = 0; i < p->ctx_table->len; i ++)
ctx_rec [i] = leu32 (p->context_live_objects [i]);
for (i = 0; i < p->klass_table->len; i ++)
type_rec [i] = leu32 (p->type_live_data [i]);
pos = prof_write (p, &rec, sizeof (rec));
prof_write (p, ctx_rec, sizeof (*ctx_rec) * p->ctx_table->len);
prof_write (p, type_rec, sizeof (*type_rec) * p->klass_table->len);
trec->time = leu32 (time);
trec->event = leu32 (HEAP_PROF_EVENT_CHECKPOINT);
trec->file_pos = leu64 (pos);
g_ptr_array_add (p->timeline, trec);
p->last_checkpoint = p->foffset;
}
static void
write_allocation (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
{
@ -238,6 +360,7 @@ write_allocation (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
AllocationCtx c = {0};
guint32 offset;
HeapProfAllocationRec rec;
guint32 ctx_idx;
AllocRec* arec = g_new0 (AllocRec, 1);
btd.c = &c;
@ -248,9 +371,10 @@ write_allocation (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
c.size = mono_object_get_size (obj);
hp_lock_enter ();
ctx_idx = get_ctx_idx (p, &c);
rec.time = leu32 (get_delta_t (p));
rec.alloc_ctx = get_ctx_idx (p, &c);
rec.alloc_ctx = ctx_idx;
offset = prof_write (p, &rec, sizeof (rec));
@ -261,6 +385,10 @@ write_allocation (MonoProfiler *p, MonoObject *obj, MonoClass *klass)
arec->next = p->live_allocs;
p->live_allocs = arec;
record_obj (p, ctx_idx, TRUE);
write_checkpoint_if_needed (p);
hp_lock_leave ();
}
@ -268,13 +396,21 @@ static void
prof_marks_set (MonoProfiler *p, int gc_num)
{
HeapProfGCRec rec;
HeapProfTimelineRec* trec = g_new0 (HeapProfTimelineRec, 1);
guint64 pos;
guint32 time = get_delta_t (p);
guint32 old_size;
hp_lock_enter ();
rec.time = leu32 (get_delta_t (p) | (1 << 31));
rec.gc_num = leu32 (gc_num);
old_size = p->total_live_bytes;
rec.time = leu32 (time | (1 << 31));
rec.event = leu32 (HEAP_PROF_EVENT_GC);
rec.event_num = p->timeline->len + 1;
prof_write (p, &rec, sizeof (rec));
pos = prof_write (p, &rec, sizeof (rec));
AllocRec *l, *next = NULL, *prev = NULL;
for (l = p->live_allocs; l; l = next) {
@ -283,6 +419,8 @@ prof_marks_set (MonoProfiler *p, int gc_num)
if (! mono_profiler_mark_set (l->obj)) {
prof_write (p, &l->rec, sizeof (l->rec));
record_obj (p, l->rec.alloc_ctx, FALSE);
if (prev)
prev->next = next;
else
@ -298,20 +436,41 @@ prof_marks_set (MonoProfiler *p, int gc_num)
prof_write (p, &null, sizeof (null));
}
trec->time = leu32 (time);
trec->event = leu32 (HEAP_PROF_EVENT_RESIZE_HEAP);
trec->size_high = leu32 (old_size);
trec->size_low = leu32 (p->total_live_bytes);
trec->file_pos = leu64 (pos);
g_ptr_array_add (p->timeline, trec);
hp_lock_leave ();
}
static void
prof_heap_resize (MonoProfiler *p, int new_size)
{
HeapProfGCHeapResize rec;
HeapProfHeapResizeRec rec;
HeapProfTimelineRec* trec = g_new0 (HeapProfTimelineRec, 1);
guint64 pos;
guint32 time = get_delta_t (p);
hp_lock_enter ();
rec.time = leu32 (get_delta_t (p) | (1 << 31));
rec.new_size = leu32 (new_size | (1 << 31));
rec.time = leu32 (time | (1 << 31));
rec.event = leu32 (HEAP_PROF_EVENT_RESIZE_HEAP);
rec.new_size = leu32 (new_size);
rec.event_num = p->timeline->len + 1;
prof_write (p, &rec, sizeof (rec));
pos = prof_write (p, &rec, sizeof (rec));
trec->time = leu32 (time);
trec->event = leu32 (HEAP_PROF_EVENT_RESIZE_HEAP);
trec->size_high = leu32 (new_size);
trec->file_pos = leu64 (pos);
g_ptr_array_add (p->timeline, trec);
hp_lock_leave ();
}
@ -349,34 +508,14 @@ write_string_table (MonoProfiler* p, GPtrArray* arr)
}
static void
write_bt_table (MonoProfiler* p)
write_data_table (MonoProfiler* p, GPtrArray* arr, guint32 elesz)
{
GPtrArray* arr = p->bt_table;
int i;
guint32 size = leu32 (arr->len);
prof_write (p, &size, sizeof (size));
for (i = 0; i < arr->len; i ++) {
IdxBacktrace* b = g_ptr_array_index (arr, i);
prof_write (p, b, sizeof (*b));
}
}
static void
write_ctx_table (MonoProfiler* p)
{
GPtrArray* arr = p->ctx_table;
int i;
guint32 size = leu32 (arr->len);
prof_write (p, &size, sizeof (size));
for (i = 0; i < arr->len; i ++) {
IdxAllocationCtx* c = g_ptr_array_index (arr, i);
prof_write (p, c, sizeof (*c));
}
for (i = 0; i < arr->len; i ++)
prof_write (p, g_ptr_array_index (arr, i), elesz);
}
static void
@ -397,8 +536,9 @@ write_metadata_file (MonoProfiler* p)
write_string_table (p, p->klass_table);
write_string_table (p, p->method_table);
write_bt_table (p);
write_ctx_table (p);
write_data_table (p, p->bt_table, sizeof (IdxBacktrace));
write_data_table (p, p->ctx_table, sizeof (IdxAllocationCtx));
write_data_table (p, p->timeline, sizeof (HeapProfTimelineRec));
}
@ -472,8 +612,6 @@ bt_eq (const Backtrace* a, const Backtrace* b)
void
mono_profiler_startup (const char *desc)
{
const char* file;
char* dump_file;
MonoProfiler* p = g_new0 (MonoProfiler, 1);
InitializeCriticalSection (&hp_lock);
@ -494,6 +632,7 @@ mono_profiler_startup (const char *desc)
p->method_table = g_ptr_array_new ();
p->bt_table = g_ptr_array_new ();
p->ctx_table = g_ptr_array_new ();
p->timeline = g_ptr_array_new ();
p->out = fopen (p->file, "w+");

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

@ -1,5 +1,9 @@
2005-01-16 Ben Maurer <bmaurer@ximian.com>
* ProfileReader.cs: Update file format
* TypeTabulator.cs: cope with changes
* *.cs: Factor Profile out.
* Profile.cs: New file.

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

@ -32,12 +32,25 @@ public abstract class ProfileReader {
} else {
time &= int.MaxValue;
int data = br.ReadInt32 ();
EventType event_type = (EventType) br.ReadInt32 ();
int event_num = br.ReadInt32 ();
if ((data & (int)(1 << 31)) == 0)
GcSeen (time, data);
else
GcHeapResize (time, (data & int.MaxValue));
switch (event_type) {
case EventType.GC:
GcSeen (time, event_num);
break;
case EventType.HeapResize:
GcHeapResize (time, event_num, br.ReadInt32 ());
break;
case EventType.Checkpoint:
int context_size = br.ReadInt32 ();
int type_size = br.ReadInt32 ();
int cb = (context_size + type_size) * 4;
br.BaseStream.Seek (cb, SeekOrigin.Current);
break;
}
}
}
@ -59,10 +72,10 @@ public abstract class ProfileReader {
}
protected abstract void AllocationSeen (int time, Context ctx, long pos);
protected abstract void GcSeen (int time, int gc_num);
protected abstract void GcSeen (int time, int event_num);
protected abstract void GcFreedSeen (int time, Context ctx, long pos);
protected virtual void GcHeapResize (int time, int new_size)
protected virtual void GcHeapResize (int time, int event_num, int new_size)
{
}
@ -105,6 +118,7 @@ public class Metadata {
string [] methodTable;
int [][] backtraceTable;
Context [] contextTable;
Timeline [] timeline;
public int TypeTableSize { get { return typeTable.Length; } }
public int ContextTableSize { get { return contextTable.Length; } }
@ -143,6 +157,7 @@ public class Metadata {
methodTable = ReadStringTable (br);
backtraceTable = ReadBacktraceTable (br);
contextTable = ReadContextTable (br);
timeline = ReadTimeline (br);
}
}
@ -203,6 +218,24 @@ public class Metadata {
return d;
}
Timeline [] ReadTimeline (BinaryReader br)
{
int sz = br.ReadInt32 ();
Timeline [] d = new Timeline [sz];
for (int i = 0; i < sz; i ++) {
d [i].Id = i;
d [i].Time = br.ReadInt32 ();
d [i].Event = (EventType) br.ReadInt32 ();
d [i].SizeHigh = br.ReadInt32 ();
d [i].SizeLow = br.ReadInt32 ();
d [i].FilePos = br.ReadInt64 ();
}
return d;
}
}
class ProfilerSignature {
@ -216,7 +249,7 @@ class ProfilerSignature {
0xaa, 0x93, 0xc8, 0x76, 0xf4, 0x6a, 0x95, 0x11
};
const int Version = 3;
const int Version = 4;
public static void ReadHeader (BinaryReader br, bool is_dump)
{
@ -235,6 +268,20 @@ class ProfilerSignature {
}
public enum EventType {
GC = 0,
HeapResize = 1,
Checkpoint = 2
}
public struct Timeline {
public int Id;
public int Time;
public EventType Event;
public int SizeHigh, SizeLow;
public long FilePos;
}
public struct Context {
public int Id;
public int Type;

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

@ -78,7 +78,7 @@ class TypeTabulator : ProfileReader {
last_time = time;
}
protected override void GcHeapResize (int time, int new_size)
protected override void GcHeapResize (int time, int event_num, int new_size)
{
// Splitting twice here gives nice graphs, since you get a strait line
Split (time);