diff --git a/SharpDevelop.Tests.sln b/SharpDevelop.Tests.sln index cc081995fe..4c8ba7888e 100644 --- a/SharpDevelop.Tests.sln +++ b/SharpDevelop.Tests.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 10 -# SharpDevelop 4.0.0.4979 +# SharpDevelop 4.0.0.5015 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" ProjectSection(SolutionItems) = postProject EndProjectSection @@ -525,6 +525,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Profiler", "Profiler", "{C4 ProjectSection(SolutionItems) = postProject EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Profiler.Tests", "src\AddIns\Misc\Profiler\Tests\Profiler.Tests\Profiler.Tests.csproj", "{068F9531-5D29-49E0-980E-59982A3A0469}" + ProjectSection(ProjectDependencies) = postProject + {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} + EndProjectSection +EndProject Project("{0E96FCFA-9DAC-4534-AC18-01A90C368873}") = "Hook", "src\AddIns\Misc\Profiler\Hook\Hook.vcxproj", "{68D5EE3B-0C35-4DF1-BD29-6606851A02C1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Profiler.X64Converter", "src\AddIns\Misc\Profiler\X64Converter\Profiler.X64Converter.csproj", "{FE88FE17-D9FB-4FCC-9A35-6BFFB6B26CC6}" @@ -957,6 +962,10 @@ Global {68D5EE3B-0C35-4DF1-BD29-6606851A02C1}.Debug|Win32.ActiveCfg = Debug|Win32 {68D5EE3B-0C35-4DF1-BD29-6606851A02C1}.Release|Win32.Build.0 = Release|Win32 {68D5EE3B-0C35-4DF1-BD29-6606851A02C1}.Release|Win32.ActiveCfg = Release|Win32 + {068F9531-5D29-49E0-980E-59982A3A0469}.Debug|Any CPU.Build.0 = Debug|Any CPU + {068F9531-5D29-49E0-980E-59982A3A0469}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {068F9531-5D29-49E0-980E-59982A3A0469}.Release|Any CPU.Build.0 = Release|Any CPU + {068F9531-5D29-49E0-980E-59982A3A0469}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1074,5 +1083,6 @@ Global {72FFB35A-C9E2-4A31-B4FA-E3E3E28DED5F} = {C4035C32-026F-4158-AF15-113EA1EF1960} {FE88FE17-D9FB-4FCC-9A35-6BFFB6B26CC6} = {C4035C32-026F-4158-AF15-113EA1EF1960} {68D5EE3B-0C35-4DF1-BD29-6606851A02C1} = {C4035C32-026F-4158-AF15-113EA1EF1960} + {068F9531-5D29-49E0-980E-59982A3A0469} = {C4035C32-026F-4158-AF15-113EA1EF1960} EndGlobalSection EndGlobal diff --git a/src/AddIns/Misc/Profiler/Controller/BuildEvents.proj b/src/AddIns/Misc/Profiler/Controller/BuildEvents.proj deleted file mode 100644 index 5560437743..0000000000 --- a/src/AddIns/Misc/Profiler/Controller/BuildEvents.proj +++ /dev/null @@ -1,13 +0,0 @@ - - - - $(PrepareForRunDependsOn);MyPostBuildTarget - - - - - - - - - \ No newline at end of file diff --git a/src/AddIns/Misc/Profiler/Controller/Data/Linq/OptimizeQueryExpressionVisitor.cs b/src/AddIns/Misc/Profiler/Controller/Data/Linq/OptimizeQueryExpressionVisitor.cs index 79c013eca0..48ce93215f 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/Linq/OptimizeQueryExpressionVisitor.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/Linq/OptimizeQueryExpressionVisitor.cs @@ -33,12 +33,16 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq protected override Expression VisitExtension(Expression node) { Filter filter = node as Filter; + MergeByName mergeByName = node as MergeByName; if (filter != null) return VisitFilter(filter); + else if (mergeByName != null) + return VisitMergeByName(mergeByName); else return base.VisitExtension(node); } + #region Filter optimizations QueryNode VisitFilter(Filter filter) { QueryNode result = OptimizeFilter(filter); @@ -130,9 +134,24 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq else return new Filter(target, newConditions.ToArray()); } + #endregion + + #region MergeByName Optimizations + QueryNode VisitMergeByName(MergeByName merge) + { + // First optimize the Target expression + QueryNode target = Visit(merge.Target); + if (target is MergeByName) { + // x.MergeByName().MergeByName() -> x.MergeByName() + return target; + } + return new MergeByName(target); + } + #endregion protected override Expression VisitMethodCall(MethodCallExpression node) { + // Optimize List.Contains when the list has 0 or 1 elements if (node.Method == KnownMembers.ListOfInt_Contains && node.Object.NodeType == ExpressionType.Constant && node.Arguments[0].Type == typeof(int)) { List list = (List)((ConstantExpression)node.Object).Value; if (list.Count == 0) diff --git a/src/AddIns/Misc/Profiler/Controller/Data/Linq/QueryAst.cs b/src/AddIns/Misc/Profiler/Controller/Data/Linq/QueryAst.cs index b8481f081c..eda0ff3ad3 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/Linq/QueryAst.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/Linq/QueryAst.cs @@ -106,7 +106,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq StringBuilder b = new StringBuilder(); BuildSql(b, new SqlQueryContext(provider)); Console.WriteLine(b.ToString()); - return provider.RunSQL(b.ToString()).AsQueryable(); + return provider.RunSQLNodeList(b.ToString()).AsQueryable(); } } diff --git a/src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs b/src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs index b72a841fd4..f8d242ee86 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/Linq/SQLiteQueryProvider.cs @@ -45,6 +45,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq Valid expressions in QueryAst nodes: Only a limited set of expressions are valid in conditions and sort descriptors. These are checked by the SafeExpressionImporter. + The set of valid expressions is: - Integer constants - Binary operators: < <= > >= == != && || - value(List).Contains(validExpr) @@ -61,6 +62,8 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq Properties serving as query roots: sqliteCallTreeNode.Children -> AllCalls.Filter((SingleCall c) => sqliteCallTreeNode.ids.Contains(c.ParentID)) + sqliteCallTreeNode.Callers + -> AllCalls.Filter((SingleCall c) => idList.Contains(c.ID)) where idList is calculated using a manual SQL query profilingDataSQLiteProvider.GetFunctions -> AllCalls.Filter((SingleCall c) => @start <= c.DataSetId && c.DataSetId <= @end).MergeByName() profilingDataSQLiteProvider.GetRoot @@ -88,6 +91,7 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq x.Filter(y).Filter(z) -> x.Filter(y && z) x.MergeByName().Filter(criteria) -> x.Filter(x, criteria).MergeByName() for some safe criterias Criterias are safe if they access no CallTreeNode properties except for NameMapping + x.MergeByName().MergeByName() -> x.MergeByName() SQL string building and execution: It must be possible to create SQL for every combination of QueryNodes, even if they do strange things like merging multiple times. @@ -131,9 +135,17 @@ namespace ICSharpCode.Profiler.Controller.Data.Linq get { return sqliteProvider.ProcessorFrequency; } } - internal IList RunSQL(string command) + public IList RunSQLNodeList(string command) { - return sqliteProvider.RunSQL(this, command); + return sqliteProvider.RunSQLNodeList(this, command); + } + + /// + /// Executes an SQL command that returns a list of integers. + /// + public List RunSQLIDList(string command) + { + return sqliteProvider.RunSQLIDList(command); } public IQueryable CreateQuery(QueryNode query) diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs index b6e0bade27..3271239d15 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs @@ -299,9 +299,9 @@ namespace ICSharpCode.Profiler.Controller.Data return c => startIndex <= c.DataSetID && c.DataSetID <= endIndex; } - internal IList RunSQL(SQLiteQueryProvider queryProvider, string command) + internal IList RunSQLNodeList(SQLiteQueryProvider queryProvider, string command) { - IList result = new List(); + List result = new List(); SQLiteCommand cmd; using (LockAndCreateCommand(out cmd)) { @@ -329,6 +329,25 @@ namespace ICSharpCode.Profiler.Controller.Data return result; } + /// + /// Executes an SQL command that returns a list of integers. + /// + internal List RunSQLIDList(string command) + { + List result = new List(); + SQLiteCommand cmd; + using (LockAndCreateCommand(out cmd)) { + cmd.CommandText = command; + + using (SQLiteDataReader reader = cmd.ExecuteReader()) { + while (reader.Read()) { + result.Add(reader.GetInt32(0)); + } + } + } + return result; + } + LockObject LockAndCreateCommand(out SQLiteCommand cmd) { this.rwLock.EnterReadLock(); diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs index 395d1a3fc6..0f85da436d 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteWriter.cs @@ -79,6 +79,7 @@ namespace ICSharpCode.Profiler.Controller.Data /// /// Sets or gets the processor frequency of the computer, where the profiling session was created. + /// The processor frequency is measured in MHz. /// public int ProcessorFrequency { get { diff --git a/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs b/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs index ecdc7a1921..251a1ad232 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs @@ -133,6 +133,8 @@ namespace ICSharpCode.Profiler.Controller.Data mergedNode.ids.AddRange(node.ids); mergedNode.callCount += node.callCount; mergedNode.cpuCyclesSpent += node.cpuCyclesSpent; + mergedNode.activeCallCount += node.activeCallCount; + mergedNode.hasChildren |= node.hasChildren; if (!initialised || mergedNode.nameId == node.nameId) mergedNode.nameId = node.nameId; else @@ -150,7 +152,12 @@ namespace ICSharpCode.Profiler.Controller.Data if (this.parent != null) return (new CallTreeNode[] { this.parent }).AsQueryable(); - throw new NotImplementedException(); + List parentIDList = provider.RunSQLIDList( + "SELECT parentid FROM FunctionData " + + "WHERE id IN(" + string.Join(",", this.ids.Select(s => s.ToString()).ToArray()) + @")"); + + Expression> filterLambda = c => parentIDList.Contains(c.ID); + return provider.CreateQuery(new MergeByName(new Filter(AllCalls.Instance, filterLambda))); } } diff --git a/src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj b/src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj index b102c38738..fe7d873990 100644 --- a/src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj +++ b/src/AddIns/Misc/Profiler/Controller/Profiler.Controller.csproj @@ -143,7 +143,6 @@ Profiler.cs - @@ -162,7 +161,6 @@ -