2005-02-06  Ben Maurer  <bmaurer@ximian.com>

	* TypeGraphViewer.cs: Changes to use the real scroller.

	* HeapScroller.cs: A real scroller, based on the one in f-spot.

In common:
2005-02-06  Ben Maurer  <bmaurer@ximian.com>

	* Profile.cs (MaxSize): new prop.
	(ContextDataTabulator): API change of ProfileReader
	(ContextDataTabulator.Checkpoint): missing a return here.

	* ProfileReader.cs: Don't do start file pos, but start file time.

	* TypeTabulator.cs: Add stuff to do a tabulation that starts
	midfile. Remove max size type stuff.

	* TypeGraphPlotter.cs: Get the max size from the profile


svn path=/trunk/heap-prof/; revision=40224
This commit is contained in:
Ben Maurer 2005-02-06 21:29:49 +00:00
Родитель 376f3a6154
Коммит dd14ce1453
8 изменённых файлов: 551 добавлений и 121 удалений

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

@ -1,3 +1,16 @@
2005-02-06 Ben Maurer <bmaurer@ximian.com>
* Profile.cs (MaxSize): new prop.
(ContextDataTabulator): API change of ProfileReader
(ContextDataTabulator.Checkpoint): missing a return here.
* ProfileReader.cs: Don't do start file pos, but start file time.
* TypeTabulator.cs: Add stuff to do a tabulation that starts
midfile. Remove max size type stuff.
* TypeGraphPlotter.cs: Get the max size from the profile
2005-01-20 Ben Maurer <bmaurer@ximian.com>
* Profile.cs, ProfileReader.cs: add stuff to get timeline

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

@ -21,33 +21,26 @@ public class Profile {
public int [] GetContextObjsForTime (int max_t)
{
int ev = Metadata.GetTimelineBefore (EventType.Checkpoint, max_t);
ContextDataTabulator tab;
if (ev != -1)
tab = new ContextDataTabulator (this, Metadata.GetTimeline (ev).FilePos, max_t);
else
tab = new ContextDataTabulator (this, 0, max_t);
ContextDataTabulator tab = new ContextDataTabulator (this, max_t);
tab.Read ();
return tab.ContextData;
}
class ContextDataTabulator : ProfileReader {
public int [] ContextData;
public ContextDataTabulator (Profile p, long s, int e) : base (p, s, e)
public ContextDataTabulator (Profile p, int s) : base (p, s, s)
{
if (s == 0)
if (p.Metadata.GetTimelineBefore (EventType.Checkpoint, s) == -1)
ContextData = new int [ContextTableSize];
}
protected override void Checkpoint (int time, int event_num)
{
if (ContextData != null)
if (ContextData != null) {
base.Checkpoint (time, event_num);
return;
}
int [] dummy;
ReadCheckpoint (out dummy, out ContextData);
@ -100,4 +93,21 @@ public class Profile {
public Timeline [] Timeline {
get { return Metadata.Timeline; }
}
}
int max_size = -1;
public int MaxSize {
get {
if (max_size != -1)
return max_size;
Timeline [] tl = Timeline;
for (int i = tl.Length - 1; i >= 0; i --)
if (tl [i].Event == EventType.HeapResize)
return max_size = tl [i].SizeHigh;
return max_size = 0;
}
}
}

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

@ -13,9 +13,16 @@ public abstract class ProfileReader {
Profile = p;
}
public ProfileReader (Profile p, long startpos, int end_t)
public ProfileReader (Profile p, int start_t, int end_t)
{
this.startpos = startpos;
int ev = p.Metadata.GetTimelineBefore (EventType.Checkpoint, start_t);
if (ev != -1)
startpos = p.Metadata.GetTimeline (ev).FilePos;
else
startpos = 0;
this.end_t = end_t;
Profile = p;
}

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

@ -16,6 +16,7 @@ class Plotter {
int xsize, ysize;
TypeTabulator d;
TypeList tl;
Profile Profile;
public Plotter (int xsize, int ysize, TypeTabulator d, TypeList tl)
{
@ -23,6 +24,7 @@ class Plotter {
this.ysize = ysize;
this.d = d;
this.tl = tl;
this.Profile = d.Profile;
FixupData ();
}
@ -33,10 +35,12 @@ class Plotter {
void FixupData ()
{
end_t = ((TimeData) d.Data [d.Data.Count - 1]).Time;
int start_t = d.StartTime;
int end_t = ((TimeData) d.Data [d.Data.Count - 1]).Time;
int del_t = end_t - start_t;
data = new ArrayList ();
int size_threshold = d.MaxSize / ysize;
int size_threshold = Profile.MaxSize / ysize;
foreach (TimeData td in d.Data) {
if (td.HeapSize < size_threshold)
@ -48,7 +52,7 @@ class Plotter {
p.Data = td;
p.Time = td.Time;
p.X = td.Time * xsize / end_t;
p.X = (td.Time - start_t) * xsize / del_t;
p.OtherSize = td.OtherSize;
p.TypeData = new int [tl.TypeIndexes.Length];
p.HeapSize = td.HeapSize;
@ -92,7 +96,7 @@ class Plotter {
psize = tp.TypeData [i];
line [j].X = tp.X;
line [j].Y = ysize - checked (offsets [j] + (int)((long)psize * (long) ysize / (long)d.MaxSize));
line [j].Y = ysize - checked (offsets [j] + (int)((long)psize * (long) ysize / (long)Profile.MaxSize));
offsets [j] = ysize - line [j].Y;
j ++;
}
@ -124,7 +128,7 @@ class Plotter {
int psize = tp.HeapSize;
line [j].X = tp.X;
line [j].Y = ysize - checked ((int)((long)psize * (long) ysize / (long)d.MaxSize));
line [j].Y = ysize - checked ((int)((long)psize * (long) ysize / (long)Profile.MaxSize));
j ++;
}

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

@ -15,23 +15,47 @@ class TypeTabulator : ProfileReader {
const int DeltaT = 50;
const double Threshold = .005;
public ArrayList Data;
public int MaxSize;
public ArrayList Data = new ArrayList ();
public long [] TotalTypeSizes;
public bool [] IsSizeLongEnough;
int [] current_type_data;
int [] current_context_data;
int last_time;
int cur_heap_size;
int start_t, end_t;
public TypeTabulator (Profile p) : base (p)
{
Data = new ArrayList ();
current_type_data = new int [TypeTableSize];
}
public TypeTabulator (Profile p, int start_t, int end_t) : base (p, start_t, end_t)
{
this.start_t = start_t;
this.end_t = end_t;
if (p.Metadata.GetTimelineBefore (EventType.Checkpoint, start_t) == -1)
current_type_data = new int [TypeTableSize];
}
protected override void Checkpoint (int time, int event_num)
{
if (current_type_data != null) {
base.Checkpoint (time, event_num);
return;
}
int [] dummy;
int last_resize = Profile.Metadata.GetTimelineBefore (EventType.HeapResize, time);
if (last_resize != -1) {
cur_heap_size = Profile.Metadata.GetTimeline (last_resize).SizeHigh;
}
ReadCheckpoint (out current_type_data, out dummy);
Split (time);
}
void Split (int time)
{
TimeData td = new TimeData ();
@ -42,8 +66,6 @@ class TypeTabulator : ProfileReader {
foreach (int i in td.TypeData)
td.TotalSize += i;
MaxSize = Math.Max (td.HeapSize, MaxSize);
Data.Add (td);
}
@ -124,7 +146,9 @@ class TypeTabulator : ProfileReader {
public void Process ()
{
int cutoff = (int) (MaxSize * Threshold);
Split (end_t);
int cutoff = (int) (Profile.MaxSize * Threshold);
TotalTypeSizes = new long [TypeTableSize];
IsSizeLongEnough = new bool [TypeTableSize];
@ -147,4 +171,8 @@ class TypeTabulator : ProfileReader {
}
}
}
}
public int StartTime {
get { return start_t; }
}
}

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

@ -1,3 +1,9 @@
2005-02-06 Ben Maurer <bmaurer@ximian.com>
* TypeGraphViewer.cs: Changes to use the real scroller.
* HeapScroller.cs: A real scroller, based on the one in f-spot.
2005-01-20 Ben Maurer <bmaurer@ximian.com>
* TypeGraphViewer.cs: add the heap scroller in an ifdef

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

@ -6,90 +6,410 @@ using Gtk;
using System.Reflection;
using System.Runtime.InteropServices;
//
// A sample using inheritance to draw
//
class HeapScroller : DrawingArea {
// because some people are too fucking scared of something not in ECMA
using GRect = Gdk.Rectangle;
Profile p;
public class HeapScroller : Bin {
int border = 8;
int box_spacing = 2;
int box_top_padding = 6;
private Glass glass;
Gdk.Window event_window;
public GRect background;
public GRect legend;
Gdk.Pixmap bitmap_cache;
Gdk.Rectangle current_allocation; // The current allocation.
bool allocated = false;
public HeapScroller (Profile p)
static bool BoxTest (GRect bounds, double x, double y)
{
this.p = p;
Events |= Gdk.EventMask.ButtonPressMask;
SetSizeRequest (100, 100);
if (x >= bounds.X &&
x < bounds.X + bounds.Width &&
y >= bounds.Y &&
y < bounds.Y + bounds.Height)
return true;
return false;
}
protected override bool OnButtonPressEvent (Gdk.EventButton args)
{
double x = args.X + Allocation.X;
double y = args.Y + Allocation.Y;
if (glass.IsInside (x, y))
glass.StartDrag (x, y, args.Time);
else {
int x_new = (int) x - background.X;
if (x_new < 0)
x_new = 0;
else if (x_new + glass.Width > background.Width)
x_new = background.Width - glass.Width;
glass.Position = x_new;
ScrollChanged ();
}
return base.OnButtonPressEvent (args);
}
protected override bool OnButtonReleaseEvent (Gdk.EventButton args)
{
double x = args.X + Allocation.X;
double y = args.Y + Allocation.Y;
if (glass.Dragging)
glass.EndDrag (x, y);
return base.OnButtonReleaseEvent (args);
}
protected override bool OnMotionNotifyEvent (Gdk.EventMotion args)
{
double x = args.X + Allocation.X;
double y = args.Y + Allocation.Y;
GRect box = glass.Bounds ();
if (glass.Dragging) {
glass.UpdateDrag (x, y);
} else {
if (glass.IsInside (x, y))
glass.State = StateType.Prelight;
else
glass.State = StateType.Normal;
}
return base.OnMotionNotifyEvent (args);
}
protected override void OnRealized ()
{
Flags |= (int)WidgetFlags.Realized;
GdkWindow = ParentWindow;
base.OnRealized ();
Gdk.WindowAttr attr = Gdk.WindowAttr.Zero;
attr.WindowType = Gdk.WindowType.Child;
attr.X = Allocation.X;
attr.Y = Allocation.Y;
attr.Width = Allocation.Width;
attr.Height = Allocation.Height;
attr.Wclass = Gdk.WindowClass.InputOnly;
attr.EventMask = (int) Events;
attr.EventMask |= (int) (Gdk.EventMask.ButtonPressMask |
Gdk.EventMask.ButtonReleaseMask |
Gdk.EventMask.PointerMotionMask);
event_window = new Gdk.Window (GdkWindow, attr, (int) (Gdk.WindowAttributesType.X | Gdk.WindowAttributesType.Y));
event_window.UserData = this.Handle;
}
protected override void OnUnrealized ()
{
event_window.Dispose ();
event_window = null;
}
protected void ScrollChanged ()
{
if (OnScrolled != null)
OnScrolled ();
}
public abstract class Manipulator {
protected HeapScroller selector;
public bool Dragging;
int x_0;
int x_n;
public abstract int Width {
get;
}
public void StartDrag (double x, double y, uint time)
{
State = StateType.Active;
Dragging = true;
x_n = Position;
x_0 = (int)x;
Console.WriteLine ("Position: {0}", Position);
}
public void UpdateDrag (double x, double y)
{
GRect then = Bounds ();
int x_new = position + (int) x - x_0;
if (x_new < 0)
x_n = 0;
else if (x_new + Width > selector.background.Width)
x_n = selector.background.Width - Width;
else
x_n = x_new;
GRect now = Bounds ();
if (selector.Visible) {
selector.GdkWindow.InvalidateRect (then, false);
selector.GdkWindow.InvalidateRect (now, false);
}
}
public void EndDrag (double x, double y)
{
GRect box = Bounds ();
Position = x_n;
State = StateType.Prelight;
Dragging = false;
selector.ScrollChanged ();
Console.WriteLine ("Position: {0}", Position);
}
private StateType state;
public StateType State {
get {
return state;
}
set {
if (state != value) {
selector.GdkWindow.InvalidateRect (Bounds (), false);
}
state = value;
}
}
private int position;
public int Position {
get {
return position;
}
set {
GRect then = Bounds ();
position = value;
GRect now = Bounds ();
if (selector.Visible) {
selector.GdkWindow.InvalidateRect (then, false);
selector.GdkWindow.InvalidateRect (now, false);
}
}
}
public abstract void Draw (GRect area);
public abstract GRect Bounds ();
public virtual bool IsInside (double x, double y)
{
return BoxTest (Bounds (), x, y);
}
public Manipulator (HeapScroller selector)
{
this.selector = selector;
}
protected int XPos {
get {
if (! Dragging)
return Position;
return x_n;
}
}
}
private class Glass : Manipulator {
private int handle_height = 15;
private int border {
get {
return selector.box_spacing * 2;
}
}
private GRect InnerBounds ()
{
GRect box = GRect.Zero;
box.Height = selector.background.Height;
box.Y = selector.background.Y;
box.X = selector.background.X + XPos;
box.Width = Width;
return box;
}
public override GRect Bounds ()
{
GRect box = InnerBounds ();
box.X -= border;
box.Y -= border;
box.Width += 2 * border;
box.Height += 2 * border + handle_height;
return box;
}
public override void Draw (GRect area)
{
GRect inner = InnerBounds ();
GRect bounds = Bounds ();
if (bounds.Intersect (area, out area)) {
int i = 0;
GRect box = inner;
box.Width -= 1;
box.Height -= 1;
while (i < border) {
box.X -= 1;
box.Y -= 1;
box.Width += 2;
box.Height += 2;
selector.GdkWindow.DrawRectangle (selector.Style.BackgroundGC (State),
false, box);
i++;
}
Style.PaintHandle (selector.Style, selector.GdkWindow, State, ShadowType.None,
area, selector, "glass", bounds.X, inner.Y + inner. Height,
bounds.Width, handle_height + border, Orientation.Horizontal);
Style.PaintShadow (selector.Style, selector.GdkWindow, State, ShadowType.Out,
area, selector, null, bounds.X, bounds.Y, bounds.Width, bounds.Height);
Style.PaintShadow (selector.Style, selector.GdkWindow, State, ShadowType.In,
area, selector, null, inner.X, inner.Y, inner.Width, inner.Height);
}
}
public override int Width {
get { return (selector.TimeSpan * selector.background.Width) / selector.maxt; }
}
public Glass (HeapScroller selector) : base (selector) {}
}
protected override void OnMapped ()
{
base.OnMapped ();
if (event_window != null)
event_window.Show ();
}
protected override bool OnExposeEvent (Gdk.EventExpose args)
{
if (bitmap_cache == null) {
bitmap_cache = new Gdk.Pixmap (GdkWindow, current_allocation.Width, current_allocation.Height, -1);
bitmap_cache = new Gdk.Pixmap (GdkWindow, background.Width, background.Height, -1);
bitmap_cache.DrawRectangle (Style.WhiteGC, true, 0, 0,
current_allocation.Width, current_allocation.Height);
background.Width, background.Height);
using (Graphics g = Gtk.DotNet.Graphics.FromDrawable (bitmap_cache)) {
Plot (g);
}
}
Gdk.Rectangle area = args.Area;
Gdk.Rectangle area;
if (args.Area.Intersect (background, out area)) {
GRect active = background;
if (active.Intersect (area, out active)) {
GdkWindow.DrawRectangle (Style.BaseGC (State), true, active);
}
}
GdkWindow.DrawDrawable (Style.BlackGC,
bitmap_cache,
area.X, area.Y,
area.X, area.Y,
area.Width, area.Height);
return true;
0, 0,
background.X, background.Y,
background.Width, background.Height);
Style.PaintShadow (this.Style, GdkWindow, State, ShadowType.In, area,
this, null, background.X, background.Y,
background.Width, background.Height);
if (glass != null) {
glass.Draw (args.Area);
}
return base.OnExposeEvent (args);
}
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
protected override void OnSizeAllocated (GRect alloc)
{
allocated = true;
current_allocation = allocation;
base.OnSizeAllocated (alloc);
int legend_height = 20;
background = new GRect (alloc.X + border, alloc.Y + border,
alloc.Width - 2* border,
alloc.Height - 2 * border - legend_height);
legend = new GRect (border, background.Y + background.Height,
background.Width, legend_height);
if (event_window != null) {
event_window.MoveResize (alloc.X, alloc.Y, alloc.Width, alloc.Height);
event_window.Move (alloc.X, alloc.Y);
}
UpdateCache ();
base.OnSizeAllocated (allocation);
Console.WriteLine ("Background {0}", background);
}
void UpdateCache ()
public HeapScroller (Profile p)
{
if (bitmap_cache != null)
bitmap_cache.Dispose ();
bitmap_cache = null;
}
protected override bool OnButtonPressEvent (Gdk.EventButton e)
{
if (e.Button != 3)
return false;
Console.WriteLine ("Button press at ({0}, {1})", e.X, e.Y);
return true;
}
void Plot (Graphics g)
{
int maxx = current_allocation.Width;
int maxy = current_allocation.Height;
this.p = p;
Events |= Gdk.EventMask.ButtonPressMask;
Timeline [] tl = p.Timeline;
int maxt = tl [tl.Length - 1].Time;
int maxsz = 0;
maxt = tl [tl.Length - 1].Time;
foreach (Timeline t in tl)
if (t.Event == EventType.HeapResize)
maxsz = t.SizeHigh;
time_span = maxt / 5;
SetSizeRequest (100, 100);
Flags |= (int)WidgetFlags.NoWindow;
background = GRect.Zero;
glass = new Glass (this);
}
Profile p;
Gdk.Pixmap bitmap_cache;
void Plot (Graphics g)
{
int maxx = background.Width;
int maxy = background.Height;
Timeline [] tl = p.Timeline;
int maxsz = p.MaxSize;
int lastx = 0;
@ -127,4 +447,30 @@ class HeapScroller : DrawingArea {
lasty = ly;
}
}
}
int maxt;
int time_span;
public int StartTime {
get { return (glass.Position * maxt) / background.Width; }
}
public int EndTime {
get { return StartTime + time_span; }
}
public int TimeSpan {
get { return time_span; }
}
void UpdateCache ()
{
if (bitmap_cache != null)
bitmap_cache.Dispose ();
bitmap_cache = null;
}
public delegate void ScrollChangedDelegate ();
public event ScrollChangedDelegate OnScrolled;
}

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

@ -7,35 +7,40 @@ using System.Reflection;
using System.Runtime.InteropServices;
class TypeGraphComponent : ShellComponent {
DrawingArea d;
TypeGrpah d;
TypeTabulator t;
TypeList tl;
HPaned paned;
VBox box;
HeapScroller scroller;
public Profile Profile;
public TypeGraphComponent (Profile p)
{
t = new TypeTabulator (p);
t.Read ();
t.Process ();
Profile = p;
Title = "Type Graph";
this.t = t;
tl = new TypeList (t);
box = new VBox ();
box.Spacing = 12;
paned = new HPaned ();
d = new PrettyGraphic (t, tl, this);
Add (box);
scroller = new HeapScroller (p);
scroller.OnScrolled += delegate { t = null; d.UpdateCache (); d.QueueDraw (); };
box.PackStart (scroller, false, false, 0);
// FIXME: HACKISH
TypeTabulator xxx = new TypeTabulator (p);
xxx.Read ();
xxx.Process ();
tl = new TypeList (xxx);
d = new TypeGrpah (tl, this);
ScrolledWindow sw = new ScrolledWindow ();
sw.Add (new TypeListNodeStore (tl).GetNodeView ());
@ -43,16 +48,30 @@ class TypeGraphComponent : ShellComponent {
paned.Pack1 (d, true, true);
paned.Pack2 (sw, false, true);
Add (box);
#if false
scroller = new HeapScroller (p);
box.PackStart (scroller, false, false, 0);
#endif
box.PackStart (paned, true, true, 0);
}
public int StartTime {
get { return scroller.StartTime; }
}
public int EndTime {
get { return scroller.EndTime; }
}
public TypeTabulator CurrentTabulator {
get {
if (t == null) {
Console.WriteLine ("start: {0}", StartTime);
Console.WriteLine ("end: {0}", EndTime);
t = new TypeTabulator (Profile, StartTime, EndTime);
t.Read ();
t.Process ();
}
return t;
}
}
}
@ -170,23 +189,20 @@ class TypeListTreeNode : TreeNode {
//
// A sample using inheritance to draw
//
class PrettyGraphic : DrawingArea {
TypeTabulator t;
class TypeGrpah : DrawingArea {
TypeList tl;
Gdk.Pixmap bitmap_cache;
//System.Drawing.Bitmap bitmap_cache;
Gdk.Rectangle current_allocation; // The current allocation.
Gdk.Rectangle allocation; // The current allocation.
bool allocated = false;
Plotter plot;
TypeGraphComponent parent;
public PrettyGraphic (TypeTabulator t, TypeList tl, TypeGraphComponent parent)
public TypeGrpah (TypeList tl, TypeGraphComponent parent)
{
Events |= Gdk.EventMask.ButtonPressMask;
this.t = t;
this.tl = tl;
this.parent = parent;
SetSizeRequest (700, 700);
@ -196,12 +212,12 @@ class PrettyGraphic : DrawingArea {
{
if (bitmap_cache == null) {
bitmap_cache = new Gdk.Pixmap (GdkWindow, current_allocation.Width, current_allocation.Height, -1);
bitmap_cache = new Gdk.Pixmap (GdkWindow, allocation.Width, allocation.Height, -1);
bitmap_cache.DrawRectangle (Style.WhiteGC, true, 0, 0,
current_allocation.Width, current_allocation.Height);
allocation.Width, allocation.Height);
using (Graphics g = Gtk.DotNet.Graphics.FromDrawable (bitmap_cache)) {
plot = new Plotter (current_allocation.Width, current_allocation.Height, t, tl);
plot = new Plotter (allocation.Width, allocation.Height, parent.CurrentTabulator, tl);
plot.Draw (g);
}
}
@ -219,12 +235,12 @@ class PrettyGraphic : DrawingArea {
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
{
allocated = true;
current_allocation = allocation;
this.allocation = allocation;
UpdateCache ();
base.OnSizeAllocated (allocation);
}
void UpdateCache ()
public void UpdateCache ()
{
if (bitmap_cache != null)
bitmap_cache.Dispose ();
@ -243,7 +259,7 @@ class PrettyGraphic : DrawingArea {
if (tp.X >= e.X) {
Console.WriteLine ("Found {0}", tp.Time);
parent.Parent.Add (new BacktraceViewerComponent (tp.Data, t.Profile));
parent.Parent.Add (new BacktraceViewerComponent (tp.Data, parent.Profile));
break;
}