diff --git a/src/AddIns/Misc/Profiler/Controller/Data/CallTreeNode.cs b/src/AddIns/Misc/Profiler/Controller/Data/CallTreeNode.cs index e343114d6e..1c36a3bf2f 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/CallTreeNode.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/CallTreeNode.cs @@ -66,10 +66,24 @@ namespace ICSharpCode.Profiler.Controller.Data public abstract bool IsActiveAtStart { get; } /// - /// Gets how many CPU cycles where spent inside this method, including sub calls. + /// Gets how many CPU cycles were spent inside this method, including sub calls. /// public abstract long CpuCyclesSpent { get; } + /// + /// Gets how many CPU cycles were spent inside this method, excluding sub calls. + /// + public virtual long CpuCyclesSpentSelf { + get { + return GetCpuCyclesSelf(); + } + } + + long GetCpuCyclesSelf() + { + return CpuCyclesSpent - Children.Aggregate(0L, (sum, item) => sum + item.CpuCyclesSpent); + } + /// /// Gets the name of the method including namespace and class name. /// diff --git a/src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs b/src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs index a0994088d6..fa24e2f3fb 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/PerformanceCounterDescriptor.cs @@ -11,8 +11,6 @@ namespace ICSharpCode.Profiler.Controller.Data { public class PerformanceCounterDescriptor { - - public PerformanceCounterDescriptor() { } diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs index faa088f191..742a1ce07f 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs @@ -350,7 +350,7 @@ namespace ICSharpCode.Profiler.Controller.Data /// public override IQueryable GetFunctions(int startIndex, int endIndex) { - if (startIndex < 0 || startIndex > endIndex) + if (startIndex < 0 || startIndex >= this.dataSets.Count) throw new ArgumentOutOfRangeException("startIndex", startIndex, "Value must be between 0 and " + endIndex); if (endIndex < startIndex || endIndex >= this.DataSets.Count) throw new ArgumentOutOfRangeException("endIndex", endIndex, "Value must be between " + startIndex + " and " + (this.DataSets.Count - 1)); diff --git a/src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs b/src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs index 2a58f1c37d..357083d872 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/UnitTestRootCallTreeNode.cs @@ -25,67 +25,75 @@ namespace ICSharpCode.Profiler.Controller.Data this.unitTests = new List(unitTests); } - /// - /// Gets a reference to the name, return type and parameter list of the method. - /// + /// 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 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 Callers { get { return Enumerable.Empty().AsQueryable(); } } - + + /// public override IQueryable Children { get { return unitTests.AsQueryable(); diff --git a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml index 5d083796cd..584d149085 100644 --- a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml +++ b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerView.xaml @@ -40,7 +40,7 @@ - + diff --git a/src/AddIns/Misc/Profiler/Frontend/Controls/CallTreeNodeViewModel.cs b/src/AddIns/Misc/Profiler/Frontend/Controls/CallTreeNodeViewModel.cs index 16b2a4a503..e7a5acc2ad 100644 --- a/src/AddIns/Misc/Profiler/Frontend/Controls/CallTreeNodeViewModel.cs +++ b/src/AddIns/Misc/Profiler/Frontend/Controls/CallTreeNodeViewModel.cs @@ -46,7 +46,7 @@ namespace ICSharpCode.Profiler.Controls public event EventHandler> RequestBringIntoView; protected virtual void OnRequestBringIntoView(NodeEventArgs e) - { + { if (RequestBringIntoView != null) { RequestBringIntoView(this, e); } @@ -101,6 +101,15 @@ namespace ICSharpCode.Profiler.Controls } } + public Visibility HotPathIndicatorVisibility { + get { + if (TimePercentageOfParent >= 0.2) + return Visibility.Visible; + + return Visibility.Collapsed; + } + } + CallTreeNodeViewModel GetNodeFromLevel(int level) { if (this.level > level) { @@ -258,7 +267,7 @@ namespace ICSharpCode.Profiler.Controls OnPropertyChanged("IsExpanded"); this.IsExpandedChanged(new NodeEventArgs(this)); - if (!isExpanded) { + if (isExpanded) { DeselectChildren(children); } } @@ -328,6 +337,35 @@ namespace ICSharpCode.Profiler.Controls } } + public string TimeSpentSelf { + get { + if (!node.IsThread) { + double value = node.TimeSpent - node.Children.Aggregate(0.0, (sum, item) => sum + item.TimeSpent); + return value.ToString("f6") + "ms"; + } else + return null; + } + } + + public string TimeSpentSelfPerCall { + get { + if (!node.IsThread) { + double value = node.TimeSpent - node.Children.Aggregate(0.0, (sum, item) => sum + item.TimeSpent); + return (value / node.CallCount).ToString("f6") + "ms"; + } else + return null; + } + } + + public string TimeSpentPerCall { + get { + if (!node.IsThread) + return (node.TimeSpent / node.CallCount).ToString("f6") + "ms"; + else + return null; + } + } + public string CallCount { get { if (!node.IsThread) diff --git a/src/AddIns/Misc/Profiler/Frontend/Controls/Controls.csproj b/src/AddIns/Misc/Profiler/Frontend/Controls/Controls.csproj index 75f5ba6ae5..6b72e24eb7 100644 --- a/src/AddIns/Misc/Profiler/Frontend/Controls/Controls.csproj +++ b/src/AddIns/Misc/Profiler/Frontend/Controls/Controls.csproj @@ -93,6 +93,8 @@ + + {72FFB35A-C9E2-4A31-B4FA-E3E3E28DED5F} Controller diff --git a/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml b/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml index adc437ca03..de3977ef6d 100644 --- a/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml +++ b/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml @@ -77,6 +77,7 @@ + @@ -97,6 +98,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml.cs b/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml.cs index d64425c792..8db95da07c 100644 --- a/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml.cs +++ b/src/AddIns/Misc/Profiler/Frontend/Controls/QueryView.xaml.cs @@ -86,8 +86,6 @@ namespace ICSharpCode.Profiler.Controls ad.Child = bar; layer.Add(ad); - CallTreeNode resultRoot; - searchTask.Execute( () => DoSearchInBackground(list.Roots.Select(i => i.Node).ToList(), start, end, text, true), result => SearchCompleted(result, layer, ad), @@ -160,9 +158,12 @@ namespace ICSharpCode.Profiler.Controls this.treeView.SizeChanged += delegate(object sender, SizeChangedEventArgs e) { if (e.NewSize.Width > 0 && e.PreviousSize.Width > 0 && (nameColumn.Width + (e.NewSize.Width - e.PreviousSize.Width)) > 0) { - if ((nameColumn.Width + (e.NewSize.Width - e.PreviousSize.Width)) >= - (e.NewSize.Width - this.callCountColumn.Width - this.percentColumn.Width - this.timeSpentColumn.Width)) - this.nameColumn.Width = e.NewSize.Width - this.callCountColumn.Width - this.percentColumn.Width - this.timeSpentColumn.Width - 25; + double newValue = e.NewSize.Width - this.callCountColumn.Width + - this.percentColumn.Width - this.timeSpentColumn.Width + - this.timeSpentSelfColumn.Width - this.timeSpentPerCallColumn.Width + - this.timeSpentSelfPerCallColumn.Width; + if ((nameColumn.Width + (e.NewSize.Width - e.PreviousSize.Width)) >= newValue) + this.nameColumn.Width = newValue - 25; else nameColumn.Width += (e.NewSize.Width - e.PreviousSize.Width); }