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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
|
// <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 @@ |
|||||||
// <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 @@ |
|||||||
// <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 @@ |
|||||||
// <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 @@ |
|||||||
// <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