diff options
author | Mike Krüger <mkrueger@novell.com> | 2010-12-02 13:07:57 +0300 |
---|---|---|
committer | Mike Krüger <mkrueger@novell.com> | 2010-12-02 13:07:57 +0300 |
commit | 7d626cc772d993e9138b1e2e97585fba062549c5 (patch) | |
tree | 3ceaa7f0dee6ac3f6c140a45adb7047019896f14 /main/src/addins/MonoDevelop.ProfilerGui | |
parent | 0b7923e6a4cac947cfb35c5d0d574cd9b141b275 (diff) |
Worked on profiler GUI.
The profiler now works on the file on disk - it doesn't store the events in memory. Some GUI elements work better - timeslider has now a scrollbar. The selection from-to is still not 100% correct. The profiler displays now more valuable timing information and a correct call-tree.
Diffstat (limited to 'main/src/addins/MonoDevelop.ProfilerGui')
9 files changed, 202 insertions, 72 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 f91b8a6f07..64d473fd5e 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfileDialog.cs @@ -26,12 +26,12 @@ using System; using Gtk; using System.Collections.Generic; +using MonoDevelop.Ide; namespace MonoDevelop.Profiler { public partial class ProfileDialog : Gtk.Window { - TimeLineWidget timeLineWidget; TreeStore store; ListStore threadStore; @@ -40,10 +40,15 @@ namespace MonoDevelop.Profiler protected override void OnDestroyed () { + System.Console.WriteLine ("DESTROYED !!!"); if (timeout != 0) { GLib.Source.Remove (timeout); timeout = 0; } + try { + System.IO.File.Delete (buffer.FileName); + } catch (Exception) { + } base.OnDestroyed (); } @@ -54,6 +59,8 @@ namespace MonoDevelop.Profiler public ProfileDialog (string fileName) : base(Gtk.WindowType.Toplevel) { this.Build (); + this.TransientFor = IdeApp.Workbench.RootWindow; + this.DestroyWithParent = true; timeLineWidget = new TimeLineWidget (this); scrolledwindow1.AddWithViewport (timeLineWidget); scrolledwindow1.ShowAll (); @@ -130,15 +137,14 @@ namespace MonoDevelop.Profiler profileResultsView.AppendColumn (callCountColumn); profileResultsView.TestExpandRow += HandleProfileResultsViewTestExpandRow; profileResultsView.ShowExpanders = true; - -// timeout = GLib.Timeout.Add (500, delegate { - try { - buffer = LogBuffer.Read (fileName); - } catch (Exception) { - } + buffer = new LogBuffer (fileName, visitor); + + buffer.Updated += delegate { + Application.Invoke (delegate { + AnalyzeBuffer (); + }); + }; AnalyzeBuffer (); -/* return true; - });*/ } @@ -181,17 +187,22 @@ namespace MonoDevelop.Profiler AppendMethodInfo (args.Iter, methodCall); } } - + public ulong T0 { + get { + return buffer.ReadBuffer (0).Header.TimeBase; + } + } + ulong startTime, endTime; public void SetTime (ulong start, ulong end) { if (buffer == null) return; if (start == 0 && end == 0) { - visitor.StartTime = visitor.EndTime = 0; + startTime = endTime = 0; } else { - ulong t0 = buffer.buffers [0].Header.TimeBase; - visitor.StartTime = t0 + start; - visitor.EndTime = t0 + end; + ulong t0 = T0; + startTime = t0 + start; + endTime = t0 + end; } AnalyzeBuffer (); } @@ -202,14 +213,24 @@ namespace MonoDevelop.Profiler if (buffer == null) return; expandedRows.Clear (); + long selectedID = SelectedThreadID; - visitor.LookupThread = selectedID; - visitor.Reset (); - totalTime = 0; - foreach (var b in buffer.buffers) { - visitor.CurrentBuffer = b; - b.RunVisitor (visitor); - totalTime += visitor.TimeBase - b.Header.TimeBase; + var v = visitor; + + if (startTime > 0) { + v = new AnalyseVisitor (); + v.LookupThread = selectedID; + v.nameDictionary = visitor.nameDictionary; + v.StartTime = startTime; + v.EndTime = endTime; + for (int i = 0; i < buffer.BufferCount; i++) { + var b = buffer.ReadBuffer (i); + if (startTime <= b.Header.TimeBase) { + System.Console.WriteLine ("analyze !!! " + b); + v.CurrentBuffer = b; + b.RunVisitor (v); + } + } } comboboxThreads.Changed -= HandleComboboxThreadsChanged; @@ -217,7 +238,7 @@ namespace MonoDevelop.Profiler threadStore.AppendValues ("[All Threads]", null); bool first = true; int active = 0; - int i = 1; + int j = 1; foreach (var thread in visitor.threadDictionary.Values) { string name = thread.Name; if (string.IsNullOrEmpty (name) && first) { @@ -225,15 +246,15 @@ namespace MonoDevelop.Profiler } first = false; if (thread.ThreadId == selectedID) - active = i; + active = j; threadStore.AppendValues (name + " (" + thread.ThreadId + ")", thread); - i++; + j++; } comboboxThreads.Active = active; comboboxThreads.Changed += HandleComboboxThreadsChanged; store.Clear (); - foreach (var threadContext in visitor.threadDictionary.Values) { + foreach (var threadContext in v.threadDictionary.Values) { if (selectedID != 0 && threadContext.ThreadId != selectedID) continue; foreach (var info in threadContext.MethodCalls.Values) { @@ -280,7 +301,6 @@ namespace MonoDevelop.Profiler 0d, null); } - } public class AnalyseVisitor : EventVisitor @@ -291,19 +311,15 @@ namespace MonoDevelop.Profiler ulong timeBase; ulong eventCount = 0; ulong lastTimeBase = 0; - const - int interval = 100000 ; - public - List<ulong> Events = new List<ulong> (); + const int interval = 100000; + public List<KeyValuePair<ulong, ulong>> Events = new List<KeyValuePair<ulong,ulong>> (); - public - ulong StartTime { + public ulong StartTime { get; set; } - public - ulong EndTime { + public ulong EndTime { get; set; } @@ -313,10 +329,9 @@ namespace MonoDevelop.Profiler return timeBase; } set { - eventCount++; timeBase = value; if (timeBase - lastTimeBase > interval) { - Events.Add (eventCount); + Events.Add (new KeyValuePair<ulong, ulong> (timeBase, eventCount)); eventCount = 0; lastTimeBase = timeBase; } @@ -329,7 +344,7 @@ namespace MonoDevelop.Profiler set { lookupThread = value; } } - public Buffer CurrentBuffer { + public override Buffer CurrentBuffer { get { return currentBuffer; } set { currentBuffer = value; @@ -466,6 +481,7 @@ namespace MonoDevelop.Profiler case MethodEvent.MethodType.Enter: if (ShouldLog) { + eventCount++; if (!nameDictionary.ContainsKey (methodBase)) nameDictionary [methodBase] = "[Unknown method]"; diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfilerExecutionHandler.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfilerExecutionHandler.cs index 9bb1384e2c..711b729462 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfilerExecutionHandler.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/ProfilerExecutionHandler.cs @@ -65,7 +65,7 @@ namespace MonoDevelop.Profiler public bool CloseExternalConsoleOnExit { get; set; } - public ProfilerStartInfo (string monoRuntimePrefix, Dictionary<string,string> monoRuntimeEnvironmentVariables) + public ProfilerStartInfo (string monoRuntimePrefix,Dictionary<string,string> monoRuntimeEnvironmentVariables) { this.MonoRuntimePrefix = monoRuntimePrefix; this.MonoRuntimeEnvironmentVariables = monoRuntimeEnvironmentVariables; @@ -99,11 +99,13 @@ namespace MonoDevelop.Profiler if (File.Exists (tmpfile)) File.Delete (tmpfile); var result = cmd.TargetRuntime.GetExecutionHandler ().Execute (cmd, console); +// new ProfileDialog (tmpfile); + result.Completed += delegate { if (File.Exists (tmpfile)) { Application.Invoke (delegate { new ProfileDialog (tmpfile); - File.Delete (tmpfile); + }); } }; 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 4fb00913db..59491f7754 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.Gui/TimeLineWidget.cs @@ -47,7 +47,11 @@ namespace MonoDevelop.Profiler public void Update () { - maxEvents = (int)(Math.Round (dialog.visitor.Events.Max () / 100.0) * 100 + 30); + ulong max = 0; + for (int i = 0; i < dialog.visitor.Events.Count; i++) { + max = Math.Max (max, dialog.visitor.Events[i].Value); + } + maxEvents = (int)(Math.Round (max / 100.0) * 100 + 30); QueueDraw (); } @@ -62,7 +66,7 @@ namespace MonoDevelop.Profiler MoveSlider (evnt.X); } else { if (evnt.Button == 1) { - pressStart = pressEnd = slider + Math.Max (boxWidth, evnt.X) / 2; + pressStart = pressEnd = slider + Math.Max (0, evnt.X - boxWidth) / 2 ; } else { pressStart = pressEnd = 0; dialog.SetTime (0, 0); @@ -74,8 +78,8 @@ namespace MonoDevelop.Profiler protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) { if (evnt.Button == 1) { - var min = 100000 * (Math.Min (pressStart, pressEnd) - boxWidth); - var max = 100000 * (Math.Max (pressStart, pressEnd) - boxWidth); + var min = 100000.0 * Math.Min (pressStart, pressEnd) / 2; + var max = 100000.0 * Math.Max (pressStart, pressEnd) / 2; dialog.SetTime ((ulong)min, (ulong)max); pressed = false; } @@ -87,8 +91,8 @@ namespace MonoDevelop.Profiler 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)); + + slider = Math.Max (0, (int)((dialog.visitor.TimeBase - dialog.T0) / 100000.0 * (x - boxWidth) / length)); QueueDraw (); } } @@ -99,7 +103,7 @@ namespace MonoDevelop.Profiler if (evnt.Y > Allocation.Height - scrollBarHeight) { MoveSlider (evnt.X); } else { - pressEnd = slider + Math.Max (boxWidth, evnt.X) / 2; + pressEnd = slider + Math.Max (0, evnt.X - boxWidth) / 2; QueueDraw (); } } @@ -159,7 +163,10 @@ namespace MonoDevelop.Profiler double length = Allocation.Width - boxWidth; double displayLength = length / 2; - double f = (double)displayLength / dialog.visitor.Events.Count; + + double delta = (dialog.visitor.TimeBase - dialog.T0) / 100000.0; + + double f = (double)displayLength / delta; double s = slider * 2 * f; double w = length * f; @@ -204,10 +211,15 @@ namespace MonoDevelop.Profiler gr.MoveTo (boxWidth + 1, Allocation.Height - scrollBarHeight); gr.Color = new Color (1, 0, 0); double x = boxWidth + 1; - for (int i = slider; i < dialog.visitor.Events.Count && x < Allocation.Width; i++) { + ulong time0 = dialog.T0; + for (int i = 0; i < dialog.visitor.Events.Count && x < Allocation.Width; i++) { var e = dialog.visitor.Events [i]; - gr.LineTo (x, Allocation.Height - scrollBarHeight - (eventMetricHeight * e / (double)maxEvents)); - x += 2; + x = boxWidth + 1 + (e.Key - time0) / 100000.0 - slider; + if (x < boxWidth + 1) + continue; + if (x > Allocation.Width) + break; + gr.LineTo (x, Allocation.Height - scrollBarHeight - (eventMetricHeight * e.Value / (double)maxEvents)); } gr.Stroke (); diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj index 282d97b041..015303e699 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.csproj @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> @@ -9,6 +9,7 @@ <OutputType>Library</OutputType> <RootNamespace>MonoDevelop.Profiler</RootNamespace> <AssemblyName>MonoDevelop.Profiler</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <DebugSymbols>true</DebugSymbols> @@ -90,7 +91,7 @@ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> <MonoDevelop> - <Properties InternalTargetFrameworkVersion="3.5"> + <Properties> <Policies> <StandardHeader inheritsSet="MITX11License" /> </Policies> diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.sln b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.sln index 26c1dd842f..9e20b410f7 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.sln +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler.sln @@ -1,6 +1,6 @@
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual Studio 2005
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoDevelop.Profiler", "MonoDevelop.Profiler.csproj", "{EB37652A-0E94-4AFE-BAD6-72586628FF3A}"
EndProject
Global
@@ -15,6 +15,6 @@ Global {EB37652A-0E94-4AFE-BAD6-72586628FF3A}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
- StartupItem = Mono.ProfilerGui\MonoDevelop.Profiler.csproj
+ StartupItem = MonoDevelop.Profiler.csproj
EndGlobalSection
EndGlobal
diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/Buffer.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/Buffer.cs index 1950b6869d..ce8f71546b 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/Buffer.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/Buffer.cs @@ -52,7 +52,7 @@ namespace MonoDevelop.Profiler ObjBase = reader.ReadInt64 (); ThreadId = reader.ReadInt64 (); MethodBase = reader.ReadInt64 (); - System.Console.WriteLine ("Buffer: Thread:{0:X}, len:{1}, time: {2}", ThreadId, Length, TimeBase); +// System.Console.WriteLine ("Buffer: Thread:{0:X}, len:{1}, time: {2}", ThreadId, Length, TimeBase); } public static BufferHeader Read (BinaryReader reader) @@ -73,7 +73,6 @@ namespace MonoDevelop.Profiler while (reader.BaseStream.Position < endPos) { Events.Add (Event.Read (reader)); } - System.Console.WriteLine ("Buffer loaded."); } public void RunVisitor (EventVisitor visitor) diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/EventVisitor.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/EventVisitor.cs index a6f71485f2..fdf589c7f8 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/EventVisitor.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/EventVisitor.cs @@ -29,6 +29,11 @@ namespace MonoDevelop.Profiler { public abstract class EventVisitor { + public abstract Buffer CurrentBuffer { + get; + set; + } + public virtual object Visit (AllocEvent allocEvent) { return null; diff --git a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/LogBuffer.cs b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/LogBuffer.cs index 4bfbf4748f..0cc9c3376e 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/LogBuffer.cs +++ b/main/src/addins/MonoDevelop.ProfilerGui/MonoDevelop.Profiler/LogBuffer.cs @@ -27,31 +27,127 @@ using System; using System.IO; using System.Collections.Generic; +using System.Security.AccessControl; +using System.Threading; namespace MonoDevelop.Profiler { - public class LogBuffer + public class LogBuffer : IDisposable { - public readonly Header Header; - public readonly List<Buffer> buffers = new List<Buffer> (); - - public static LogBuffer Read (string fileName) + public Header Header { get; private set; } + public List<long> bufferPositions = new List<long> (); + + FileStream stream; + BinaryReader reader; + Thread thread; + bool running = true; + object fileLock = new object (); + string fileName; + + public string FileName { + get { + return this.fileName; + } + } + + public EventVisitor Visitor { + get; + private set; + } + + public LogBuffer (string fileName, EventVisitor visitor) { - if (!File.Exists (fileName)) - return null; - BinaryReader reader = new BinaryReader (File.OpenRead (fileName)); - LogBuffer result = new LogBuffer (reader); - reader.Close (); + this.fileName = fileName; + this.Visitor = visitor; + + // thread = new Thread (delegate () { + + long position = 0; +// while (running) { + bool shouldUpdate = false; +// lock (fileLock) { + do { + try { + stream = new FileStream (fileName, FileMode.Open, FileSystemRights.Read, FileShare.Read, 1024, FileOptions.RandomAccess); + } catch (Exception) { + // Thread.Sleep (100); + } + } while (running && stream == null); + if (!running) + return; + reader = new BinaryReader (stream); + + if (this.Header == null) { + try { + stream.Position = 0; + this.Header = Header.Read (reader); + position = reader.BaseStream.Position; + } catch (Exception e) { + System.Console.WriteLine (e); + Thread.Sleep (200); +// continue; + } + } + stream.Position = position; + while (stream.Position < stream.Length) { + try { + var buffer = Buffer.Read (reader); + bufferPositions.Add (position); + position = stream.Position; + if (Visitor != null) { + Visitor.CurrentBuffer = buffer; + buffer.Events.ForEach (e => e.Accept (Visitor)); + } + shouldUpdate = true; + } catch (Exception e) { + System.Console.WriteLine (e); + Thread.Sleep (200); + continue; + } + } +// reader.Close (); +// stream.Close (); +// } + if (shouldUpdate) + OnUpdated (EventArgs.Empty); +// Thread.Sleep (1000); +// } +// }); +// thread.IsBackground = true; +// thread.Start (); + } + + public int BufferCount { + get { + return bufferPositions.Count; + } + } + + public Buffer ReadBuffer (int bufferNumber) + { + stream.Position = bufferPositions [bufferNumber]; + var result = Buffer.Read (reader); return result; } - LogBuffer (BinaryReader reader) + #region IDisposable implementation + public void Dispose () { - this.Header = Header.Read (reader); - while (reader.BaseStream.Position < reader.BaseStream.Length) { - buffers.Add (Buffer.Read (reader)); + if (running) { + running = false; + thread.Join (); } } + #endregion + + protected virtual void OnUpdated (EventArgs e) + { + EventHandler handler = this.Updated; + if (handler != null) + handler (this, e); + } + + public event EventHandler Updated; } } diff --git a/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic b/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic index e349a0ee6a..3169d9af82 100644 --- a/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic +++ b/main/src/addins/MonoDevelop.ProfilerGui/gtk-gui/gui.stetic @@ -9,7 +9,6 @@ <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" /> |