Browse Source
- fixed memory leak - removed ICSharpCode.SharpDevelop.Profiling namespace - added filter for unit tests when selecting "Run with profiler" git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4863 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
21 changed files with 400 additions and 320 deletions
@ -0,0 +1,95 @@
@@ -0,0 +1,95 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
|
||||
namespace ICSharpCode.Profiler.Controller.Data |
||||
{ |
||||
/// <summary>
|
||||
/// Wraps multiple CallTreeNodes that represent unit test methods for proper display in the listview.
|
||||
/// </summary>
|
||||
public class UnitTestRootCallTreeNode : CallTreeNode |
||||
{ |
||||
List<CallTreeNode> unitTests; |
||||
|
||||
/// <summary>
|
||||
/// Creates a new UnitTestRootCallTreeNode.
|
||||
/// </summary>
|
||||
public UnitTestRootCallTreeNode(IEnumerable<CallTreeNode> unitTests) |
||||
{ |
||||
this.unitTests = new List<CallTreeNode>(unitTests); |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the name, return type and parameter list of the method.
|
||||
/// </summary>
|
||||
public override NameMapping NameMapping { |
||||
get { |
||||
return new NameMapping(0, null, "Merged node", null); |
||||
} |
||||
} |
||||
|
||||
public override long CpuCyclesSpent { |
||||
get { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public override bool IsActiveAtStart { |
||||
get { |
||||
return this.unitTests.Any(test => test.IsActiveAtStart); |
||||
} |
||||
} |
||||
|
||||
public override double TimeSpent { |
||||
get { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public override int RawCallCount { |
||||
get { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public override CallTreeNode Parent { |
||||
get { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public override CallTreeNode Merge(System.Collections.Generic.IEnumerable<CallTreeNode> nodes) |
||||
{ |
||||
// throw new ShouldNeverHappenException();
|
||||
throw new NotSupportedException("Cannot merge a UnitTestRootCallTreeNode (should never be possible)"); |
||||
} |
||||
|
||||
public override int GetHashCode() |
||||
{ |
||||
return this.unitTests.Aggregate(0, (sum, item) => sum ^= item.GetHashCode()); |
||||
} |
||||
|
||||
public override bool Equals(CallTreeNode other) |
||||
{ |
||||
return (other is UnitTestRootCallTreeNode) && (other as UnitTestRootCallTreeNode).unitTests.SequenceEqual(unitTests); |
||||
} |
||||
|
||||
public override IQueryable<CallTreeNode> Callers { |
||||
get { |
||||
return Enumerable.Empty<CallTreeNode>().AsQueryable(); |
||||
} |
||||
} |
||||
|
||||
public override IQueryable<CallTreeNode> Children { |
||||
get { |
||||
return unitTests.AsQueryable(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using System.Linq; |
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.Profiler.AddIn; |
||||
using ICSharpCode.Profiler.Controller.Data; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Dom; |
||||
using ICSharpCode.UnitTesting; |
||||
|
||||
namespace ICSharpCode.Profiler.AddIn.Commands |
||||
{ |
||||
public class RunTestWithProfilerCommand : AbstractRunTestCommand |
||||
{ |
||||
protected override void RunTests(UnitTestApplicationStartHelper helper) |
||||
{ |
||||
TestRunnerCategory.AppendLine(helper.GetCommandLine()); |
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(helper.UnitTestApplication); |
||||
|
||||
string path = helper.Project.GetSessionFileName(); |
||||
|
||||
startInfo.Arguments = helper.GetArguments(); |
||||
startInfo.WorkingDirectory = UnitTestApplicationStartHelper.UnitTestApplicationDirectory; |
||||
LoggingService.Info("starting profiler..."); |
||||
|
||||
ProfilerRunner runner = new ProfilerRunner(startInfo, true, new ProfilingDataSQLiteWriter(path, true, GetUnitTestNames(helper).ToArray())); |
||||
|
||||
runner.RunFinished += delegate { |
||||
WorkbenchSingleton.SafeThreadCall(() => FileService.OpenFile(path)); |
||||
AfterFinish(helper, path); |
||||
}; |
||||
|
||||
runner.Run(); |
||||
} |
||||
|
||||
IEnumerable<string> GetUnitTestNames(UnitTestApplicationStartHelper helper) |
||||
{ |
||||
IProjectContent content = ParserService.GetProjectContent(helper.Project); |
||||
|
||||
if (helper.Fixture == null) { |
||||
var testClasses = content.Classes |
||||
.Where(c => c.Attributes.Any(a => a.AttributeType.FullyQualifiedName == "NUnit.Framework.TestFixtureAttribute")); |
||||
return testClasses |
||||
.SelectMany(c2 => c2.Methods) |
||||
.Where(m => m.Attributes.Any(a2 => a2.AttributeType.FullyQualifiedName == "NUnit.Framework.TestAttribute")) |
||||
.Select(m2 => m2.FullyQualifiedName); |
||||
} |
||||
|
||||
if (helper.Test == null) { |
||||
return content.Classes |
||||
.Where(c => c.FullyQualifiedName == helper.Fixture).First().Methods |
||||
.Where(m => m.Attributes.Any(a2 => a2.AttributeType.FullyQualifiedName == "NUnit.Framework.TestAttribute")) |
||||
.Select(m2 => m2.FullyQualifiedName); |
||||
} |
||||
|
||||
return new[] { helper.Fixture + "." + helper.Test }; |
||||
} |
||||
|
||||
void AfterFinish(UnitTestApplicationStartHelper helper, string path) |
||||
{ |
||||
helper.Project.AddSessionToProject(path); |
||||
WorkbenchSingleton.SafeThreadAsyncCall(TestsFinished); |
||||
LoggingService.Info("shutting profiler down..."); |
||||
} |
||||
|
||||
public override void Run() |
||||
{ |
||||
// if (ProfilerService.IsProfilerLoaded && ProfilerService.CurrentProfiler.IsRunning) {
|
||||
// MessageService.ShowError("Currently there is a profiling session in progress. " +
|
||||
// "Please finish the current session before starting a new one.");
|
||||
// } else {
|
||||
base.Run(); |
||||
// }
|
||||
} |
||||
|
||||
protected override void OnStop() |
||||
{ |
||||
// if (ProfilerService.CurrentProfiler.IsRunning) {
|
||||
// LoggingService.Info("stopping profiler...");
|
||||
// ProfilerService.CurrentProfiler.Stop();
|
||||
// }
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="siegfriedpammer@gmail.com"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
using System; |
||||
using System.Globalization; |
||||
using System.IO; |
||||
using ICSharpCode.SharpDevelop; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.Profiler.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// Description of Extensions.
|
||||
/// </summary>
|
||||
public static class Extensions |
||||
{ |
||||
public static string GetSessionFileName(this IProject project) |
||||
{ |
||||
string filename = @"ProfilingSessions\Session" + |
||||
DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture) + |
||||
".sdps"; |
||||
|
||||
string path = Path.Combine(project.Directory, filename); |
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)); |
||||
|
||||
return path; |
||||
} |
||||
|
||||
public static void AddSessionToProject(this IProject project, string path) |
||||
{ |
||||
Action updater = () => { |
||||
if (!File.Exists(path)) |
||||
return; |
||||
FileService.OpenFile(path); |
||||
if (!project.ReadOnly) { |
||||
FileProjectItem file = new FileProjectItem(project, ItemType.Content, "ProfilingSessions\\" + Path.GetFileName(path)); |
||||
ProjectService.AddProjectItem(project, file); |
||||
ProjectBrowserPad.Instance.ProjectBrowserControl.RefreshView(); |
||||
project.Save(); |
||||
} |
||||
}; |
||||
|
||||
WorkbenchSingleton.SafeThreadCall(updater); |
||||
} |
||||
} |
||||
} |
@ -1,94 +0,0 @@
@@ -1,94 +0,0 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Diagnostics; |
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.Profiler.Controller.Data; |
||||
using ICSharpCode.SharpDevelop.Profiling; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
using System.IO; |
||||
|
||||
namespace ICSharpCode.Profiler.AddIn |
||||
{ |
||||
/// <summary>
|
||||
/// Description of WindowsProfiler.
|
||||
/// </summary>
|
||||
public class WindowsProfiler : IProfiler |
||||
{ |
||||
ProfilerRunner runner; |
||||
bool isRunning = false; |
||||
|
||||
public WindowsProfiler() |
||||
{ |
||||
} |
||||
|
||||
public bool CanProfile(IProject project) |
||||
{ |
||||
return project != null && project.IsStartable; |
||||
} |
||||
|
||||
public void Start(ProcessStartInfo info, string outputPath, Action afterFinishAction) |
||||
{ |
||||
this.runner = new ProfilerRunner(info, true, new ProfilingDataSQLiteWriter(outputPath)); |
||||
|
||||
if (runner != null) { |
||||
runner.RunFinished += delegate { |
||||
try { |
||||
afterFinishAction(); |
||||
} finally { |
||||
this.isRunning = false; |
||||
} |
||||
}; |
||||
this.isRunning = true; |
||||
runner.Run(); |
||||
} |
||||
} |
||||
|
||||
public static ProfilerRunner CreateRunner(IProfilingDataWriter writer) |
||||
{ |
||||
AbstractProject currentProj = ProjectService.CurrentProject as AbstractProject; |
||||
|
||||
if (currentProj == null) |
||||
return null; |
||||
|
||||
if (!currentProj.IsStartable) { |
||||
if (MessageService.AskQuestion("This project cannot be started. Do you want to profile the solution's StartUp project instead?")) { |
||||
currentProj = ProjectService.OpenSolution.StartupProject as AbstractProject; |
||||
if (currentProj == null) { |
||||
MessageService.ShowError("No startable project was found. Aborting ..."); |
||||
return null; |
||||
} |
||||
} else |
||||
return null; |
||||
} |
||||
if (!File.Exists(currentProj.OutputAssemblyFullPath)) { |
||||
MessageService.ShowError("This project cannot be started because the executable file was not found, " + |
||||
"please ensure that the project and all its depencies are built correctly!"); |
||||
return null; |
||||
} |
||||
|
||||
ProfilerRunner runner = new ProfilerRunner(currentProj.CreateStartInfo(), true, writer); |
||||
return runner; |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
} |
||||
|
||||
public bool IsRunning { |
||||
get { |
||||
return this.isRunning; |
||||
} |
||||
} |
||||
|
||||
public void Stop() |
||||
{ |
||||
this.runner.Stop(); |
||||
} |
||||
} |
||||
} |
@ -1,44 +0,0 @@
@@ -1,44 +0,0 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using ICSharpCode.Core; |
||||
using System; |
||||
using System.Diagnostics; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Profiling |
||||
{ |
||||
public class DefaultProfiler : IProfiler |
||||
{ |
||||
public bool CanProfile(ICSharpCode.SharpDevelop.Project.IProject project) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
public void Start(ProcessStartInfo info, string outputPath, Action afterFinishedAction) |
||||
{ |
||||
MessageService.ShowError("Profiling not supported! " + |
||||
"No appropriate Profiler AddIn was found."); |
||||
afterFinishedAction(); |
||||
} |
||||
|
||||
public void Dispose() |
||||
{ |
||||
Stop(); |
||||
} |
||||
|
||||
public bool IsRunning { |
||||
get { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public void Stop() |
||||
{ |
||||
} |
||||
} |
||||
} |
@ -1,21 +0,0 @@
@@ -1,21 +0,0 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using ICSharpCode.SharpDevelop.Project; |
||||
using System; |
||||
using System.Diagnostics; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Profiling |
||||
{ |
||||
public interface IProfiler : IDisposable |
||||
{ |
||||
bool CanProfile(IProject project); |
||||
void Start(ProcessStartInfo info, string outputPath, Action afterFinishedAction); |
||||
void Stop(); |
||||
bool IsRunning { get; } |
||||
} |
||||
} |
@ -1,87 +0,0 @@
@@ -1,87 +0,0 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Siegfried Pammer" email="sie_pam@gmx.at"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Globalization; |
||||
using System.IO; |
||||
|
||||
using ICSharpCode.Core; |
||||
using ICSharpCode.SharpDevelop.Gui; |
||||
using ICSharpCode.SharpDevelop.Project; |
||||
|
||||
namespace ICSharpCode.SharpDevelop.Profiling |
||||
{ |
||||
public static class ProfilerService |
||||
{ |
||||
static IProfiler currentProfiler; |
||||
static IProfiler[] profilers; |
||||
|
||||
static ProfilerService() |
||||
{ |
||||
profilers = AddInTree.BuildItems<IProfiler>("/SharpDevelop/Services/ProfilerService/Profiler", null, false).ToArray(); |
||||
} |
||||
|
||||
public static bool IsProfilerLoaded |
||||
{ |
||||
get { |
||||
return currentProfiler != null; |
||||
} |
||||
} |
||||
|
||||
static IProfiler GetCompatibleProfiler() |
||||
{ |
||||
IProject project = null; |
||||
if (ProjectService.OpenSolution != null) |
||||
project = ProjectService.OpenSolution.StartupProject; |
||||
foreach (var p in profilers) { |
||||
if (p != null && p.CanProfile(project)) |
||||
return p; |
||||
} |
||||
return new DefaultProfiler(); |
||||
} |
||||
|
||||
public static IProfiler CurrentProfiler { |
||||
get { |
||||
if (currentProfiler == null) { |
||||
currentProfiler = GetCompatibleProfiler(); |
||||
} |
||||
|
||||
return currentProfiler; |
||||
} |
||||
} |
||||
|
||||
public static string GetSessionFileName(IProject project) |
||||
{ |
||||
string filename = @"ProfilingSessions\Session" + |
||||
DateTime.Now.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture) + |
||||
".sdps"; |
||||
|
||||
string path = Path.Combine(project.Directory, filename); |
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)); |
||||
|
||||
return path; |
||||
} |
||||
|
||||
public static void AddSessionToProject(IProject project, string path) |
||||
{ |
||||
Action updater = () => { |
||||
if (!File.Exists(path)) |
||||
return; |
||||
FileService.OpenFile(path); |
||||
if (!project.ReadOnly) { |
||||
FileProjectItem file = new FileProjectItem(project, ItemType.Content, "ProfilingSessions\\" + Path.GetFileName(path)); |
||||
ProjectService.AddProjectItem(project, file); |
||||
ProjectBrowserPad.Instance.ProjectBrowserControl.RefreshView(); |
||||
project.Save(); |
||||
} |
||||
}; |
||||
|
||||
WorkbenchSingleton.SafeThreadCall(updater); |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue