diff --git a/src/AddIns/Misc/Profiler/Controller/Controller.csproj b/src/AddIns/Misc/Profiler/Controller/Controller.csproj index 89b73bd3ab..c83c0abb80 100644 --- a/src/AddIns/Misc/Profiler/Controller/Controller.csproj +++ b/src/AddIns/Misc/Profiler/Controller/Controller.csproj @@ -66,6 +66,7 @@ + diff --git a/src/AddIns/Misc/Profiler/Controller/Data/IncompatibleDatabaseException.cs b/src/AddIns/Misc/Profiler/Controller/Data/IncompatibleDatabaseException.cs new file mode 100644 index 0000000000..e02400b3bc --- /dev/null +++ b/src/AddIns/Misc/Profiler/Controller/Data/IncompatibleDatabaseException.cs @@ -0,0 +1,66 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Runtime.Serialization; + +namespace ICSharpCode.Profiler.Controller.Data +{ + /// + /// Thrown when the database used to internally store the usage data is incompatible with the DB version + /// expected by the UsageDataCollector library. + /// + [Serializable] + public class IncompatibleDatabaseException : Exception + { + /// + /// Expected database version. + /// + public Version ExpectedVersion { get; set; } + + /// + /// Actual database version. + /// + public Version ActualVersion { get; set; } + + /// + /// Creates a new IncompatibleDatabaseException instance. + /// + public IncompatibleDatabaseException() {} + + /// + /// Creates a new IncompatibleDatabaseException instance. + /// + public IncompatibleDatabaseException(Version expectedVersion, Version actualVersion) + : base("Expected DB version " + expectedVersion + " but found " + actualVersion) + { + this.ExpectedVersion = expectedVersion; + this.ActualVersion = actualVersion; + } + + /// + /// Deserializes an IncompatibleDatabaseException instance. + /// + protected IncompatibleDatabaseException(SerializationInfo info, StreamingContext context) : base(info, context) + { + if (info != null) { + this.ExpectedVersion = (Version)info.GetValue("ExpectedVersion", typeof(Version)); + this.ActualVersion = (Version)info.GetValue("ActualVersion", typeof(Version)); + } + } + + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + if (info != null) { + info.AddValue("ExpectedVersion", this.ExpectedVersion, typeof(Version)); + info.AddValue("ActualVersion", this.ActualVersion, typeof(Version)); + } + } + } +} diff --git a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs index a5afa7fb36..bf84f348a8 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/ProfilingDataSQLiteProvider.cs @@ -42,6 +42,16 @@ namespace ICSharpCode.Profiler.Controller.Data this.connection = new SQLiteConnection(conn.ConnectionString); this.connection.Open(); + + CheckFileVersion(); + } + + void CheckFileVersion() + { + string version = GetProperty("version"); + + if (version != "1.0") + throw new IncompatibleDatabaseException(new Version(1, 0), new Version(version)); } /// @@ -69,42 +79,11 @@ namespace ICSharpCode.Profiler.Controller.Data internal IQueryable GetCallers(SQLiteCallTreeNode item) { - SQLiteCommand cmd; - using (LockAndCreateCommand(out cmd)) { - cmd.CommandText = @"SELECT id, nameid, callcount, timespent, isactiveatstart - FROM FunctionData - WHERE id IN( - SELECT parentid - FROM FunctionData - WHERE id IN(" + string.Join(",", item.ids.Select(s => s.ToString()).ToArray()) + @") - ) - ORDER BY id;"; - - Debug.Print("GetCallers cmd: " + cmd.CommandText); - - using (SQLiteDataReader reader = cmd.ExecuteReader()) { - List items = new List(); - - while (reader.Read()) { - int childNameId = reader.GetInt32(1); - SQLiteCallTreeNode newItem = items.Find(node => node.nameId == childNameId); - if (newItem == null) { - newItem = new SQLiteCallTreeNode(childNameId, null, this); - newItem.selectionStartIndex = item.selectionStartIndex; - items.Add(newItem); - - // works because of ORDER BY id - newItem.isActiveAtStart = reader.GetBoolean(4); - } - - newItem.callCount += reader.GetInt32(2); - newItem.cpuCyclesSpent += (ulong)reader.GetInt64(3); - newItem.ids.Add(reader.GetInt32(0)); - } - - return items.Cast().AsQueryable(); // TODO : remove Cast<> in .NET 4.0 - } - } + return GetMergedFunctionData(@"id IN( + SELECT parentid + FROM FunctionData + WHERE id IN(" + string.Join(",", item.ids.Select(s => s.ToString()).ToArray()) + ")" + + ")", item.selectionStartIndex); } /// diff --git a/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs b/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs index c9b390b8e3..a0e45d0d2d 100644 --- a/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs +++ b/src/AddIns/Misc/Profiler/Controller/Data/SQLiteCallTreeNode.cs @@ -20,7 +20,6 @@ namespace ICSharpCode.Profiler.Controller.Data class SQLiteCallTreeNode : CallTreeNode { internal int nameId; - internal bool isActiveAtStart; internal int callCount; internal ulong cpuCyclesSpent; CallTreeNode parent; @@ -106,12 +105,12 @@ namespace ICSharpCode.Profiler.Controller.Data /// public override bool IsActiveAtStart { get { - return isActiveAtStart; + return activeCallCount > 0; } } public override int CallCount { - get { return callCount + activeCallCount; } + get { return Math.Max(1, callCount + activeCallCount); } } /// @@ -122,13 +121,17 @@ namespace ICSharpCode.Profiler.Controller.Data public override CallTreeNode Merge(IEnumerable nodes) { SQLiteCallTreeNode mergedNode = new SQLiteCallTreeNode(0, null, this.provider); + mergedNode.selectionStartIndex = int.MaxValue; bool initialised = false; foreach (SQLiteCallTreeNode node in nodes) { mergedNode.ids.AddRange(node.ids); + mergedNode.hasChildren |= node.hasChildren; mergedNode.selectionStartIndex = Math.Min(mergedNode.selectionStartIndex, node.selectionStartIndex); mergedNode.callCount += node.callCount; + mergedNode.activeCallCount += node.activeCallCount; mergedNode.cpuCyclesSpent += node.cpuCyclesSpent; + if (!initialised || mergedNode.nameId == node.nameId) mergedNode.nameId = node.nameId; else diff --git a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/CopySelectedData.cs b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/CopySelectedData.cs index 6209ca52a8..a2fb39f5a2 100644 --- a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/CopySelectedData.cs +++ b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Commands/CopySelectedData.cs @@ -35,7 +35,16 @@ namespace ICSharpCode.Profiler.AddIn.Commands foreach (CallTreeNodeViewModel node in list) { if (node != null) - builder.AppendLine(new string('\t', node.Level) + node.Name + "\t" + node.CallCount + "\t" + node.TimeSpent + "\t" + node.TimePercentageOfParentAsText); + builder.AppendLine( + new string('\t', node.Level) + + node.Name + "\t" + + node.CallCount + "\t" + + node.TimeSpent + "\t" + + node.TimeSpentSelf + "\t" + + node.TimeSpentPerCall + "\t" + + node.TimeSpentSelfPerCall + "\t" + + node.TimePercentageOfParentAsText + ); } Clipboard.SetText(builder.ToString()); diff --git a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerDisplayBinding.cs b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerDisplayBinding.cs index 2ae212d2c6..a35d723dfa 100644 --- a/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerDisplayBinding.cs +++ b/src/AddIns/Misc/Profiler/Frontend/AddIn/Src/Views/ProfilerDisplayBinding.cs @@ -5,10 +5,11 @@ // $Revision$ // -using ICSharpCode.Profiler.Controller.Data; +using ICSharpCode.Core; using System; using System.IO; using ICSharpCode.Profiler.Controller; +using ICSharpCode.Profiler.Controller.Data; using ICSharpCode.SharpDevelop; namespace ICSharpCode.Profiler.AddIn.Views @@ -29,7 +30,12 @@ namespace ICSharpCode.Profiler.AddIn.Views public ICSharpCode.SharpDevelop.Gui.IViewContent CreateContentForFile(OpenedFile file) { - return new WpfViewer(file); + try { + return new WpfViewer(file); + } catch (IncompatibleDatabaseException e) { + MessageService.ShowErrorFormatted("${res:AddIns.Profiler.DatabaseTooNewError}", e.ActualVersion.ToString(), e.ExpectedVersion.ToString()); + return null; + } } } }