diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs
index 88a243898e..1eabf92ed0 100644
--- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/TreeListViewDebuggerItem.cs
@@ -69,6 +69,8 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (!dirty) return;
if (!IsVisible) return;
+ DateTime startTime = Debugger.Util.HighPrecisionTimer.Now;
+
if (this.TreeListView != null) {
((DebuggerTreeListView)this.TreeListView).DelayRefresh();
Highlight = (val.AsString != SubItems[1].Text);
@@ -90,6 +92,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
dirty = false;
+
+ TimeSpan totalTime = Debugger.Util.HighPrecisionTimer.Now - startTime;
+ //val.Process.TraceMessage("Local Variables Pad item updated: " + val.Name + " (" + totalTime.TotalMilliseconds + " ms)");
}
public void BeforeExpand()
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
index 9f2658f9d4..ac4ee06200 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
@@ -345,7 +345,6 @@
-
@@ -379,6 +378,8 @@
+
+
@@ -397,6 +398,7 @@
+
\ No newline at end of file
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs
index 59cd0e4b99..c323e1393d 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs
@@ -227,7 +227,7 @@ namespace Debugger
}
}
- internal void TraceMessage(string message)
+ public void TraceMessage(string message)
{
System.Diagnostics.Debug.WriteLine("Debugger:" + message);
debugger.OnDebuggerTraceMessage(new MessageEventArgs(this, message));
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/HighPrecisionTimer.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/HighPrecisionTimer.cs
new file mode 100644
index 0000000000..e54d05cd84
--- /dev/null
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/HighPrecisionTimer.cs
@@ -0,0 +1,50 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Debugger.Util
+{
+ ///
+ /// HighPrecisionTimer can obtain much more accurate time measurement
+ /// for performace optimization
+ ///
+ public static class HighPrecisionTimer
+ {
+ [DllImport("kernel32.dll")]
+ static extern int QueryPerformanceFrequency(out long frequency);
+
+ [DllImport("kernel32.dll")]
+ static extern int QueryPerformanceCounter(out long count);
+
+ static DateTime startTime;
+ static long startTicks;
+
+ static HighPrecisionTimer()
+ {
+ startTime = DateTime.Now;
+ startTicks = Ticks;
+ }
+
+ static long Ticks {
+ get {
+ long frequency;
+ long count;
+ QueryPerformanceFrequency(out frequency);
+ QueryPerformanceCounter(out count);
+ return (count / frequency) * TimeSpan.TicksPerSecond + (count % frequency) * TimeSpan.TicksPerSecond / frequency;
+ }
+ }
+
+ public static DateTime Now {
+ get {
+ return startTime.AddTicks(Ticks - startTicks);
+ }
+ }
+ }
+}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Util.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/Lists.cs
similarity index 84%
rename from src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Util.cs
rename to src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/Lists.cs
index 959ecbbd86..7e6aae3b7f 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Util.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Util/Lists.cs
@@ -1,16 +1,16 @@
-//
+//
//
//
-//
+//
// $Revision$
//
using System;
using System.Collections.Generic;
-namespace Debugger
+namespace Debugger.Util
{
- static class Util
+ public class Lists
{
public static List MergeLists(T a, IEnumerable b)
{
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Types/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Types/DebugType.cs
index 7ce3b16b0f..cfdbe830ae 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Types/DebugType.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Types/DebugType.cs
@@ -27,10 +27,10 @@ namespace Debugger
Module module;
TypeDefProps classProps;
- // Cache
- List fields;
- List methods;
- List properties;
+ // Members of the type; empty lists if not applicable
+ List fields = new List();
+ List methods = new List();
+ List properties = new List();
void AssertClassOrValueType()
{
@@ -180,9 +180,9 @@ namespace Debugger
this.corClass = corType.Class;
this.module = process.GetModule(corClass.Module);
this.classProps = module.MetaData.GetTypeDefProps(corClass.Token);
+
+ LoadType();
}
-
- process.TraceMessage("Created type " + this.Name);
}
///
@@ -214,66 +214,43 @@ namespace Debugger
this.IsSubclassOf(objectInstance.Type);
}
- List GetAllFields()
+ void LoadType()
{
- AssertClassOrValueType();
+ DateTime startTime = Util.HighPrecisionTimer.Now;
- // Build cache
- if (fields == null) {
- process.TraceMessage("Loading fields for type " + this.Name);
- fields = new List();
- foreach(FieldProps field in module.MetaData.EnumFields(this.MetadataToken)) {
- // TODO: Why?
- if (field.IsStatic && field.IsLiteral) continue; // Skip static literals
- fields.Add(new FieldInfo(this, field));
- };
- }
- return fields;
- }
-
- List GetAllMethods()
- {
- AssertClassOrValueType();
+ // Load fields
+ foreach(FieldProps field in module.MetaData.EnumFields(this.MetadataToken)) {
+ if (field.IsStatic && field.IsLiteral) continue; // Skip static literals TODO: Why?
+ fields.Add(new FieldInfo(this, field));
+ };
- // Build cache
- if (methods == null) {
- process.TraceMessage("Loading methods for type " + this.Name);
- methods = new List();
- foreach(MethodProps m in module.MetaData.EnumMethods(this.MetadataToken)) {
- methods.Add(new MethodInfo(this, m));
- }
+ // Load methods
+ foreach(MethodProps m in module.MetaData.EnumMethods(this.MetadataToken)) {
+ methods.Add(new MethodInfo(this, m));
}
- return methods;
- }
-
- // TODO: Handle indexers ("get_Item") in other code
- List GetAllProperties()
- {
- AssertClassOrValueType();
- // Build cache
- if (properties == null) {
- process.TraceMessage("Loading properties for type " + this.Name);
- properties = new List();
- // Collect data
- Dictionary methods = new Dictionary();
- Dictionary names = new Dictionary();
- foreach(MethodInfo method in GetAllMethods()) {
- if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_"))) {
- methods.Add(method.Name, method);
- names.Add(method.Name.Remove(0,4), null);
- }
- }
- // Pair up getters and setters
- foreach(KeyValuePair kvp in names) {
- MethodInfo getter = null;
- MethodInfo setter = null;
- methods.TryGetValue("get_" + kvp.Key, out getter);
- methods.TryGetValue("set_" + kvp.Key, out setter);
- properties.Add(new PropertyInfo(this, getter, setter));
+ // Load properties
+ // TODO: Handle indexers ("get_Item") in other code
+ // Collect data
+ Dictionary accessors = new Dictionary();
+ Dictionary propertyNames = new Dictionary();
+ foreach(MethodInfo method in methods) {
+ if (method.IsSpecialName && (method.Name.StartsWith("get_") || method.Name.StartsWith("set_"))) {
+ accessors.Add(method.Name, method);
+ propertyNames[method.Name.Remove(0,4)] = null;
}
}
- return properties;
+ // Pair up getters and setters
+ foreach(KeyValuePair kvp in propertyNames) {
+ MethodInfo getter = null;
+ MethodInfo setter = null;
+ accessors.TryGetValue("get_" + kvp.Key, out getter);
+ accessors.TryGetValue("set_" + kvp.Key, out setter);
+ properties.Add(new PropertyInfo(this, getter, setter));
+ }
+
+ TimeSpan totalTime = Util.HighPrecisionTimer.Now - startTime;
+ process.TraceMessage("Loaded type " + this.Name + " (" + totalTime.TotalMilliseconds + " ms)");
}
/// Return all public fields.
@@ -285,11 +262,7 @@ namespace Debugger
/// Return all fields satisfing binding flags.
public IList GetFields(BindingFlags bindingFlags)
{
- if (IsClass || IsValueType) {
- return FilterMemberInfo(GetAllFields(), bindingFlags);
- } else {
- return new List();
- }
+ return FilterMemberInfo(fields, bindingFlags);
}
/// Return all public methods.
@@ -301,11 +274,7 @@ namespace Debugger
/// Return all methods satisfing binding flags.
public IList GetMethods(BindingFlags bindingFlags)
{
- if (IsClass || IsValueType) {
- return FilterMemberInfo(GetAllMethods(), bindingFlags);
- } else {
- return new List();
- }
+ return FilterMemberInfo(methods, bindingFlags);
}
/// Return all public properties.
@@ -317,11 +286,7 @@ namespace Debugger
/// Return all properties satisfing binding flags.
public IList GetProperties(BindingFlags bindingFlags)
{
- if (IsClass || IsValueType) {
- return FilterMemberInfo(GetAllProperties(), bindingFlags);
- } else {
- return new List();
- }
+ return FilterMemberInfo(properties, bindingFlags);
}
/// Compares two types
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value-Common.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value-Common.cs
index 81502b487c..83a8d03ff0 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value-Common.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value-Common.cs
@@ -25,11 +25,7 @@ namespace Debugger
/// Gets a string representation of the value
public string AsString {
get {
- if (IsNull) return "";
- if (IsArray) return "{" + this.Type.Name + "}";
- if (IsObject) return "{" + this.Type.Name + "}";
- if (IsPrimitive) return PrimitiveValue != null ? PrimitiveValue.ToString() : String.Empty;
- throw new DebuggerException("Unknown value type");
+ return Cache.AsString;
}
}
}
diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value.cs
index 87cdab99a7..e08f419b51 100644
--- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value.cs
+++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Values/Value.cs
@@ -40,9 +40,6 @@ namespace Debugger
CorValueGetter corValueGetter;
- ICorDebugValue currentCorValue;
- PauseSession currentCorValuePauseSession;
-
/// Occurs when the Value can not be used anymore
public event EventHandler Expired;
@@ -51,6 +48,47 @@ namespace Debugger
bool isExpired = false;
+ ValueCache cache;
+
+ private class ValueCache
+ {
+ public PauseSession PauseSession;
+ public ICorDebugValue RawCorValue;
+ public ICorDebugValue CorValue;
+ public DebugType Type;
+ public string AsString = String.Empty;
+ }
+
+ ///
+ /// Cache stores expensive or commonly used information about the value
+ ///
+ ValueCache Cache {
+ get {
+ if (this.HasExpired) throw new CannotGetValueException("Value has expired");
+
+ if (cache == null || (cache.PauseSession != process.PauseSession && !cache.RawCorValue.Is())) {
+ DateTime startTime = Util.HighPrecisionTimer.Now;
+
+ cache = new ValueCache();
+ cache.PauseSession = process.PauseSession;
+ cache.RawCorValue = corValueGetter();
+ cache.CorValue = DereferenceUnbox(RawCorValue);
+ cache.Type = DebugType.Create(process, RawCorValue.As().ExactType);
+
+ // AsString representation
+ if (IsNull) cache.AsString = "";
+ if (IsArray) cache.AsString = "{" + this.Type.Name + "}";
+ if (IsObject) cache.AsString = "{" + this.Type.Name + "}";
+ if (IsPrimitive) cache.AsString = PrimitiveValue != null ? PrimitiveValue.ToString() : String.Empty;
+
+
+ TimeSpan totalTime = Util.HighPrecisionTimer.Now - startTime;
+ process.TraceMessage("Obtained value: " + cache.AsString + " (" + totalTime.TotalMilliseconds + " ms)");
+ }
+ return cache;
+ }
+ }
+
/// The process that owns the value
public Process Process {
get {
@@ -68,7 +106,7 @@ namespace Debugger
internal ICorDebugValue CorValue {
get {
- return DereferenceUnbox(RawCorValue);
+ return Cache.CorValue;
}
}
@@ -84,12 +122,7 @@ namespace Debugger
ICorDebugValue RawCorValue {
get {
- if (this.HasExpired) throw new CannotGetValueException("CorValue has expired");
- if (currentCorValue == null || (currentCorValuePauseSession != process.PauseSession && !currentCorValue.Is())) {
- currentCorValue = corValueGetter();
- currentCorValuePauseSession = process.PauseSession;
- }
- return currentCorValue;
+ return Cache.RawCorValue;
}
}
@@ -153,9 +186,8 @@ namespace Debugger
internal void NotifyChange()
{
+ cache = null;
if (!isExpired) {
- currentCorValue = null;
- currentCorValuePauseSession = null;
OnChanged(new ValueEventArgs(this));
}
}
@@ -180,7 +212,7 @@ namespace Debugger
/// Returns the of the value
public DebugType Type {
get {
- return DebugType.Create(process, RawCorValue.As().ExactType);
+ return Cache.Type;
}
}