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