diff options
author | Mike Krüger <mkrueger@novell.com> | 2010-11-22 16:29:14 +0300 |
---|---|---|
committer | Mike Krüger <mkrueger@novell.com> | 2010-11-22 16:29:14 +0300 |
commit | 30249142735ae4ffcfc3c40701d697af9a3a2129 (patch) | |
tree | 91748882ac72a17ab7ffc98a450c1eddb3d60e60 /main/src/addins/MonoDevelop.ProfilerGui | |
parent | ec7f1c46c1f62797cf4d2f688690572c08d20313 (diff) |
Worked on the profiler gui.
Timeline widget/more & more useful data is collected.
Diffstat (limited to 'main/src/addins/MonoDevelop.ProfilerGui')
4 files changed, 232 insertions, 77 deletions
diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs index 229aa5ba78..f91b8a6f07 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs @@ -31,7 +31,6 @@ namespace MonoDevelop.Profiler { public partial class ProfileDialog : Gtk.Window { - const int MethodInfoColumn = 4; TimeLineWidget timeLineWidget; TreeStore store; @@ -48,6 +47,10 @@ namespace MonoDevelop.Profiler base.OnDestroyed (); } + const int TimeSelfColumn = 4; + const int TotalTimeColumn = 5; + const int MethodInfoColumn = 6; + public ProfileDialog (string fileName) : base(Gtk.WindowType.Toplevel) { this.Build (); @@ -61,7 +64,9 @@ namespace MonoDevelop.Profiler store = new TreeStore (typeof(string), // name typeof(string), // icon typeof(ulong), // call count - typeof(double), // time with children + typeof(double), // time with children % + typeof(double), // time self (ms) + typeof(double), // total time (ms) typeof(AnalyseVisitor.MethodInfo) // method info ); profileResultsView.Model = store; @@ -77,10 +82,34 @@ namespace MonoDevelop.Profiler methodColumn.AddAttribute (textRender, "text", 0); profileResultsView.AppendColumn (methodColumn); + var timeSelfColumn = new TreeViewColumn (); + timeSelfColumn.SortColumnId = TimeSelfColumn; + timeSelfColumn.SortIndicator = true; + timeSelfColumn.Title = "Time self (ms)"; + timeSelfColumn.Resizable = true; + timeSelfColumn.PackStart (textRender, true); + timeSelfColumn.SetCellDataFunc (textRender, delegate (Gtk.TreeViewColumn column, Gtk.CellRenderer cell,Gtk.TreeModel model, Gtk.TreeIter iter) { + double time = (double)model.GetValue (iter, TimeSelfColumn); + ((CellRendererText)cell).Text = string.Format ("{0:0.0}", time); + }); + profileResultsView.AppendColumn (timeSelfColumn); + + var totalTimeColumn = new TreeViewColumn (); + totalTimeColumn.SortColumnId = TimeSelfColumn; + totalTimeColumn.SortIndicator = true; + totalTimeColumn.Title = "Total time (ms)"; + totalTimeColumn.Resizable = true; + totalTimeColumn.PackStart (textRender, true); + totalTimeColumn.SetCellDataFunc (textRender, delegate (Gtk.TreeViewColumn column, Gtk.CellRenderer cell,Gtk.TreeModel model, Gtk.TreeIter iter) { + double time = (double)model.GetValue (iter, TotalTimeColumn); + ((CellRendererText)cell).Text = string.Format ("{0:0.0}", time); + }); + profileResultsView.AppendColumn (totalTimeColumn); + var timeWithChidrenColumn = new TreeViewColumn (); timeWithChidrenColumn.SortColumnId = 3; timeWithChidrenColumn.SortIndicator = true; - timeWithChidrenColumn.Title = "Time with children (%)"; + timeWithChidrenColumn.Title = "Time from parent (%)"; timeWithChidrenColumn.Resizable = true; var timeCellRenderer = new TimeCellRenderer (); timeWithChidrenColumn.PackStart (timeCellRenderer, true); @@ -103,11 +132,11 @@ namespace MonoDevelop.Profiler profileResultsView.ShowExpanders = true; // timeout = GLib.Timeout.Add (500, delegate { - try { - buffer = LogBuffer.Read (fileName); - } catch (Exception) { - } - AnalyzeBuffer (); + try { + buffer = LogBuffer.Read (fileName); + } catch (Exception) { + } + AnalyzeBuffer (); /* return true; });*/ } @@ -148,7 +177,7 @@ namespace MonoDevelop.Profiler store.Remove (ref child); } - foreach (var methodCall in info.CallStack) { + foreach (var methodCall in info.MethodCalls.Values) { AppendMethodInfo (args.Iter, methodCall); } } @@ -157,10 +186,13 @@ namespace MonoDevelop.Profiler { if (buffer == null) return; - ulong t0 = buffer.buffers [0].Header.TimeBase; - visitor.StartTime = t0 + start; - visitor.EndTime = t0 + end; - System.Console.WriteLine ("set time:" + visitor.StartTime + " - " + visitor.EndTime); + if (start == 0 && end == 0) { + visitor.StartTime = visitor.EndTime = 0; + } else { + ulong t0 = buffer.buffers [0].Header.TimeBase; + visitor.StartTime = t0 + start; + visitor.EndTime = t0 + end; + } AnalyzeBuffer (); } @@ -169,6 +201,7 @@ namespace MonoDevelop.Profiler { if (buffer == null) return; + expandedRows.Clear (); long selectedID = SelectedThreadID; visitor.LookupThread = selectedID; visitor.Reset (); @@ -200,39 +233,51 @@ namespace MonoDevelop.Profiler comboboxThreads.Changed += HandleComboboxThreadsChanged; store.Clear (); - foreach (var info in visitor.methodDictionary.Values) { - if (info.Calls == 0) + foreach (var threadContext in visitor.threadDictionary.Values) { + if (selectedID != 0 && threadContext.ThreadId != selectedID) continue; - AppendMethodInfo (TreeIter.Zero, info); + foreach (var info in threadContext.MethodCalls.Values) { + AppendMethodInfo (TreeIter.Zero, info); + } } + timeLineWidget.Update (); } void AppendMethodInfo (TreeIter iter, AnalyseVisitor.MethodInfo info) { TreeIter subiter; double time = (double)totalTime; - if (visitor.StartTime != 0) { - time = (visitor.EndTime - visitor.StartTime); - System.Console.WriteLine (totalTime + ":" + time); + if (info.Parent != null) { + time = info.Parent.TimeWithChildren; + } else { + if (visitor.StartTime != 0) { + time = Math.Min (totalTime, visitor.EndTime - visitor.StartTime); + } } if (iter.Equals (TreeIter.Zero)) { - subiter = store.AppendValues (info.Name, + subiter = store.AppendValues (visitor.LookupName (info.MethodBase), "", info.Calls, 100.0 * (double)info.TimeWithChildren / time, + (info.TimeWithChildren - info.CalleeTime) / 1000.0, + info.TimeWithChildren / 1000.0, info); } else { - subiter = store.AppendValues (iter, info.Name, + subiter = store.AppendValues (iter, visitor.LookupName (info.MethodBase), "", info.Calls, 100.0 * (double)info.TimeWithChildren / time, + (info.TimeWithChildren - info.CalleeTime) / 1000.0, + info.TimeWithChildren / 1000.0, info); } - if (info.CallStack.Count > 0) { + if (info.MethodCalls.Count > 0) { store.AppendValues (subiter, "", "", 0UL, 0d, + 0d, + 0d, null); } @@ -246,14 +291,19 @@ namespace MonoDevelop.Profiler ulong timeBase; ulong eventCount = 0; ulong lastTimeBase = 0; - const int interval = 100000; - public List<ulong> Events = new List<ulong> (); - public ulong StartTime { + const + int interval = 100000 ; + public + List<ulong> Events = new List<ulong> (); + + public + ulong StartTime { get; set; } - public ulong EndTime { + public + ulong EndTime { get; set; } @@ -296,31 +346,49 @@ namespace MonoDevelop.Profiler { public long ThreadId { get; set; } public string Name { get; set; } - + + public Dictionary<long, MethodInfo> MethodCalls = new Dictionary<long, MethodInfo> (); + public Stack<MethodInfo> Stack = new Stack<MethodInfo> (); public Stack<ulong> timeStack = new Stack<ulong> (); public Stack<ulong> calleeTimeStack = new Stack<ulong> (); public long LastTime { get; set; } - - public void PushMethod (MethodInfo methodInfo, ulong timeStamp) + + MethodInfo GetInfo (long methodBase) { + Dictionary<long, MethodInfo> dict; if (Stack.Count > 0) { - Stack.Peek ().CallStack.Add (methodInfo); + dict = Stack.Peek ().MethodCalls; + } else { + dict = MethodCalls; } - methodInfo.RecurseCount++; - methodInfo.Calls++; + MethodInfo info; + if (!dict.TryGetValue (methodBase, out info)) { + dict [methodBase] = info = new MethodInfo (methodBase); + if (Stack.Count > 0) + info.Parent = Stack.Peek (); + } + return info; + } + + public void PushMethod (long methodBase, ulong timeStamp) + { + MethodInfo info = GetInfo (methodBase); + + info.RecurseCount++; + info.Calls++; timeStack.Push (timeStamp); calleeTimeStack.Push (0); - Stack.Push (methodInfo); + Stack.Push (info); } - public void PopMethod (MethodInfo methodInfo, ulong timeStamp) + public void PopMethod (long methodBase, ulong timeStamp) { - methodInfo.RecurseCount--; - if (Stack.Count > 0 && Stack.Peek () == methodInfo) { - Stack.Pop (); + if (Stack.Count > 0 && Stack.Peek ().MethodBase == methodBase) { + MethodInfo methodInfo = Stack.Pop (); + methodInfo.RecurseCount--; ulong timeDiff = timeStamp - timeStack.Pop (); methodInfo.TimeWithChildren += timeDiff; methodInfo.CalleeTime = calleeTimeStack.Pop (); @@ -332,6 +400,11 @@ namespace MonoDevelop.Profiler public class MethodInfo { + public MethodInfo Parent { + get; + set; + } + public long RecurseCount { get; set; @@ -342,7 +415,7 @@ namespace MonoDevelop.Profiler set; } - public string Name { + public long MethodBase { get; set; } @@ -357,21 +430,28 @@ namespace MonoDevelop.Profiler set; } - public HashSet<MethodInfo> CallStack = new HashSet<MethodInfo> (); + public Dictionary<long, MethodInfo> MethodCalls = new Dictionary<long, MethodInfo> (); - public MethodInfo (string name) + public MethodInfo (long methodBase) { - this.Name = name; + this.MethodBase = methodBase; } } - public Dictionary<long, MethodInfo> methodDictionary = new Dictionary<long, MethodInfo> (); + public Dictionary<long, string> nameDictionary = new Dictionary<long, string> (); public Dictionary<long, ThreadContext> threadDictionary = new Dictionary<long, ThreadContext> (); + public string LookupName (long methodBase) + { + string name; + if (nameDictionary.TryGetValue (methodBase, out name)) + return name; + return "Unknown method"; + } + public void Reset () { Events.Clear (); - methodDictionary.Clear (); threadDictionary.Clear (); } @@ -381,23 +461,23 @@ namespace MonoDevelop.Profiler TimeBase += methodEvent.TimeDiff; switch (methodEvent.Type) { case MethodEvent.MethodType.Jit: - methodDictionary [methodBase] = new MethodInfo (methodEvent.Name); + nameDictionary [methodBase] = methodEvent.Name; break; case MethodEvent.MethodType.Enter: if (ShouldLog) { - if (!methodDictionary.ContainsKey (methodBase)) - methodDictionary [methodBase] = new MethodInfo ("Unknown method."); + if (!nameDictionary.ContainsKey (methodBase)) + nameDictionary [methodBase] = "[Unknown method]"; - currentThread.PushMethod (methodDictionary [methodBase], TimeBase); + currentThread.PushMethod (methodBase, TimeBase); } break; case MethodEvent.MethodType.Leave: if (ShouldLog) { - if (!methodDictionary.ContainsKey (methodBase)) - methodDictionary [methodBase] = new MethodInfo ("Unknown method."); - currentThread.PopMethod (methodDictionary [methodBase], TimeBase); + if (!nameDictionary.ContainsKey (methodBase)) + nameDictionary [methodBase] = "[Unknown method]"; + currentThread.PopMethod (methodBase, TimeBase); } break; } diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs index e4a826dbad..4fb00913db 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs @@ -24,6 +24,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; +using System.Linq; using System.ComponentModel; using Gtk; using Cairo; @@ -36,38 +37,71 @@ namespace MonoDevelop.Profiler { ProfileDialog dialog; int maxEvents = 230; + int slider = 0; public TimeLineWidget (ProfileDialog dialog) { this.dialog = dialog; Events |= Gdk.EventMask.ButtonMotionMask | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask; } + + public void Update () + { + maxEvents = (int)(Math.Round (dialog.visitor.Events.Max () / 100.0) * 100 + 30); + QueueDraw (); + } + double pressStart, pressEnd; bool pressed; protected override bool OnButtonPressEvent (Gdk.EventButton evnt) { - if (evnt.Button == 1) { + if (evnt.Button == 1) pressed = true; - pressStart = pressEnd = Math.Max (boxWidth, evnt.X); + if (evnt.Y > Allocation.Height - scrollBarHeight) { + MoveSlider (evnt.X); + } else { + if (evnt.Button == 1) { + pressStart = pressEnd = slider + Math.Max (boxWidth, evnt.X) / 2; + } else { + pressStart = pressEnd = 0; + dialog.SetTime (0, 0); + } } return base.OnButtonPressEvent (evnt); } protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) { - var min = 100000 * (Math.Min (pressStart, pressEnd) - boxWidth); - var max = 100000 * (Math.Max (pressStart, pressEnd) - boxWidth); - dialog.SetTime ((ulong)min, (ulong)max); - pressed = false; + if (evnt.Button == 1) { + var min = 100000 * (Math.Min (pressStart, pressEnd) - boxWidth); + var max = 100000 * (Math.Max (pressStart, pressEnd) - boxWidth); + dialog.SetTime ((ulong)min, (ulong)max); + pressed = false; + } return base.OnButtonReleaseEvent (evnt); } + void MoveSlider (double x) + { + if (x >= boxWidth) { + double length = Allocation.Width - boxWidth; + double displayLength = length / 2; + + slider = Math.Max (0, (int)(dialog.visitor.Events.Count * (x - boxWidth) / length - displayLength / 2)); + QueueDraw (); + } + } + protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt) { if (pressed) { - pressEnd = Math.Max (boxWidth, evnt.X); - QueueDraw (); + if (evnt.Y > Allocation.Height - scrollBarHeight) { + MoveSlider (evnt.X); + } else { + pressEnd = slider + Math.Max (boxWidth, evnt.X) / 2; + QueueDraw (); + } } return base.OnMotionNotifyEvent (evnt); } @@ -76,7 +110,8 @@ namespace MonoDevelop.Profiler { base.OnSizeRequested (ref requisition); } - + + const double scrollBarHeight = 22; const double timeHeight = 28; const double eventHeight = 20; const double boxWidth = 60; @@ -113,10 +148,32 @@ namespace MonoDevelop.Profiler gr.LineTo (boxWidth + 0.5, Allocation.Height); gr.Stroke (); } + + void DrawScrollBar (Context gr) + { + gr.LineWidth = 1; + + gr.Rectangle (boxWidth, Allocation.Height - scrollBarHeight, Allocation.Width - boxWidth, scrollBarHeight); + gr.Color = new Color (0.7, 0.7, 0.7); + gr.Fill (); + + double length = Allocation.Width - boxWidth; + double displayLength = length / 2; + double f = (double)displayLength / dialog.visitor.Events.Count; + double s = slider * 2 * f; + double w = length * f; + + gr.Rectangle (boxWidth + s + 0.5, Allocation.Height - scrollBarHeight + 0.5, w, scrollBarHeight); + gr.Color = new Color (1, 1, 1); + gr.FillPreserve (); + gr.Color = new Color (0, 0, 0); + gr.Stroke (); + } protected override bool OnExposeEvent (Gdk.EventExpose evnt) { using (var gr = Gdk.CairoHelper.Create (evnt.Window)) { + DrawBackground (gr); var layout = gr.CreateLayout (); @@ -143,12 +200,14 @@ namespace MonoDevelop.Profiler gr.LineTo (boxWidth, y); gr.Stroke (); } - var eventMetricHeight = Allocation.Height - timeHeight - eventHeight; - gr.MoveTo (boxWidth + 1, Allocation.Height); + var eventMetricHeight = Allocation.Height - timeHeight - eventHeight - scrollBarHeight; + gr.MoveTo (boxWidth + 1, Allocation.Height - scrollBarHeight); gr.Color = new Color (1, 0, 0); - for (int i = 0; i < dialog.visitor.Events.Count; i++) { + double x = boxWidth + 1; + for (int i = slider; i < dialog.visitor.Events.Count && x < Allocation.Width; i++) { var e = dialog.visitor.Events [i]; - gr.LineTo (boxWidth + 1 + i * 2, Allocation.Height - (eventMetricHeight * e / (double)maxEvents)); + gr.LineTo (x, Allocation.Height - scrollBarHeight - (eventMetricHeight * e / (double)maxEvents)); + x += 2; } gr.Stroke (); @@ -163,17 +222,32 @@ namespace MonoDevelop.Profiler gr.ShowLayout (layout); layout.Dispose (); - - gr.Rectangle (pressStart, 0, pressEnd - pressStart, Allocation.Height); - gr.Color = new Color (0, 1, 1, 0.2); - gr.Fill (); + x = (pressStart - slider) * 2; + double delta = 0; + if (x < boxWidth) + delta = boxWidth - x; + double width = pressEnd * 2 - pressStart * 2 - delta; + if (width > 0) { + gr.Rectangle (x + delta, 0, width, Allocation.Height - scrollBarHeight); + gr.Color = new Color (0, 1, 1, 0.2); + gr.Fill (); + } gr.Color = new Color (0, 1, 1, 0.3); - gr.MoveTo (pressStart, 0); - gr.LineTo (pressStart, Allocation.Height); - gr.MoveTo (pressEnd, 0); - gr.LineTo (pressEnd, Allocation.Height); - gr.Stroke (); + if (x > boxWidth) { + gr.MoveTo (x, 0); + gr.LineTo (x, Allocation.Height); + gr.Stroke (); + } + + x = (pressEnd - slider) * 2; + if (x > boxWidth) { + gr.MoveTo (x, 0); + gr.LineTo (x, Allocation.Height); + gr.Stroke (); + } + + DrawScrollBar (gr); } return base.OnExposeEvent (evnt); diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj index d73ea55220..282d97b041 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj @@ -14,7 +14,7 @@ <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> - <OutputPath>..\..\..\..\build\AddIns</OutputPath> + <OutputPath>..\..\..\build\AddIns</OutputPath> <DefineConstants>DEBUG</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> @@ -29,7 +29,7 @@ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <DebugType>none</DebugType> <Optimize>false</Optimize> - <OutputPath>..\..\..\..\build\AddIns</OutputPath> + <OutputPath>..\..\..\build\AddIns</OutputPath> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <PlatformTarget>x86</PlatformTarget> diff --git a/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic b/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic index 00c0ef271b..e349a0ee6a 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic +++ b/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic @@ -6,9 +6,10 @@ </configuration> <import> <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" /> - <widget-library name="../../../../../build/bin/MonoDevelop.Ide.dll" /> - <widget-library name="../../../../../build/bin/Mono.TextEditor.dll" /> - <widget-library name="../../../../../build/AddIns/MonoDevelop.Profiler.dll" internal="true" /> + <widget-library name="MonoDevelop.Ide, Version=2.4.0.0, Culture=neutral" /> + <widget-library name="Mono.TextEditor, Version=1.0.0.0, Culture=neutral" /> + <widget-library name="../../../../build/AddIns/MonoDevelop.Profiler.dll" internal="true" /> + <widget-library name="../../../../build/AddIns/MonoDevelop.GtkCore/libstetic.dll" /> </import> <widget class="Gtk.Window" id="MonoDevelop.Profiler.ProfileDialog" design-size="400 300"> <property name="MemberName" /> |