From 59ad301b0338cb52b1a879fe1924ec740f3f26b3 Mon Sep 17 00:00:00 2001
From: Patrick Simpson
Date: Wed, 5 Jul 2017 12:12:43 +0200
Subject: [PATCH] [KOE-130] Added wrapper tracing feature
---
.../AcaciaZPushPlugin.csproj | 3 +
.../DebugSupport/DebugDialog.Designer.cs | 153 ++++-
.../Features/DebugSupport/DebugDialog.cs | 97 +++-
.../Features/DebugSupport/DebugDialog.resx | 522 +++++++++++++++---
.../Features/DebugSupport/DebugInfo.cs | 4 +-
.../AcaciaZPushPlugin/GlobalOptions.cs | 9 +
.../Utils/DisposableTracer.cs | 15 +
.../Utils/DisposableTracerDummy.cs | 23 +
.../Utils/DisposableTracerFull.cs | 182 ++++++
.../Utils/DisposableWrapper.cs | 36 +-
10 files changed, 947 insertions(+), 97 deletions(-)
create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracer.cs
create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerDummy.cs
create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerFull.cs
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
index e9e4b33..8f1e121 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
@@ -388,6 +388,9 @@
+
+
+
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs
index 280828f..6cc050a 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.Designer.cs
@@ -28,23 +28,58 @@
///
private void InitializeComponent()
{
+ System.Windows.Forms.ColumnHeader columnMethod;
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DebugDialog));
+ System.Windows.Forms.ColumnHeader columnFile;
+ System.Windows.Forms.ColumnHeader columnLine;
this.tableMain = new System.Windows.Forms.TableLayoutPanel();
this.flowButtons = new System.Windows.Forms.FlowLayoutPanel();
this.buttonGC = new System.Windows.Forms.Button();
this.buttonRefresh = new System.Windows.Forms.Button();
this.buttonClose = new System.Windows.Forms.Button();
this.buttonLog = new System.Windows.Forms.Button();
+ this._tabs = new System.Windows.Forms.TabControl();
+ this._tabProperties = new System.Windows.Forms.TabPage();
this.Properties = new System.Windows.Forms.PropertyGrid();
+ this._tabWrapperTypes = new System.Windows.Forms.TabPage();
+ this.listWrapperTypes = new System.Windows.Forms.ListView();
+ this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this._tabWrapperLocations = new System.Windows.Forms.TabPage();
+ this._layoutLocations = new System.Windows.Forms.TableLayoutPanel();
+ this.listStackTrace = new System.Windows.Forms.ListView();
+ this.listWrapperLocations = new System.Windows.Forms.ListView();
+ this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ columnMethod = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ columnFile = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ columnLine = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.tableMain.SuspendLayout();
this.flowButtons.SuspendLayout();
+ this._tabs.SuspendLayout();
+ this._tabProperties.SuspendLayout();
+ this._tabWrapperTypes.SuspendLayout();
+ this._tabWrapperLocations.SuspendLayout();
+ this._layoutLocations.SuspendLayout();
this.SuspendLayout();
//
+ // columnMethod
+ //
+ resources.ApplyResources(columnMethod, "columnMethod");
+ //
+ // columnFile
+ //
+ resources.ApplyResources(columnFile, "columnFile");
+ //
+ // columnLine
+ //
+ resources.ApplyResources(columnLine, "columnLine");
+ //
// tableMain
//
resources.ApplyResources(this.tableMain, "tableMain");
this.tableMain.Controls.Add(this.flowButtons, 0, 1);
- this.tableMain.Controls.Add(this.Properties, 0, 0);
+ this.tableMain.Controls.Add(this._tabs, 0, 0);
this.tableMain.Name = "tableMain";
//
// flowButtons
@@ -85,14 +120,109 @@
this.buttonLog.UseVisualStyleBackColor = true;
this.buttonLog.Click += new System.EventHandler(this.buttonLog_Click);
//
+ // _tabs
+ //
+ this._tabs.Controls.Add(this._tabProperties);
+ this._tabs.Controls.Add(this._tabWrapperTypes);
+ this._tabs.Controls.Add(this._tabWrapperLocations);
+ resources.ApplyResources(this._tabs, "_tabs");
+ this._tabs.Name = "_tabs";
+ this._tabs.SelectedIndex = 0;
+ //
+ // _tabProperties
+ //
+ this._tabProperties.Controls.Add(this.Properties);
+ resources.ApplyResources(this._tabProperties, "_tabProperties");
+ this._tabProperties.Name = "_tabProperties";
+ this._tabProperties.UseVisualStyleBackColor = true;
+ //
// Properties
//
- resources.ApplyResources(this.Properties, "Properties");
this.Properties.DisabledItemForeColor = System.Drawing.SystemColors.ControlText;
+ resources.ApplyResources(this.Properties, "Properties");
this.Properties.Name = "Properties";
this.Properties.PropertySort = System.Windows.Forms.PropertySort.Categorized;
this.Properties.ToolbarVisible = false;
//
+ // _tabWrapperTypes
+ //
+ this._tabWrapperTypes.Controls.Add(this.listWrapperTypes);
+ resources.ApplyResources(this._tabWrapperTypes, "_tabWrapperTypes");
+ this._tabWrapperTypes.Name = "_tabWrapperTypes";
+ this._tabWrapperTypes.UseVisualStyleBackColor = true;
+ //
+ // listWrapperTypes
+ //
+ this.listWrapperTypes.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.columnHeader1,
+ this.columnHeader2});
+ resources.ApplyResources(this.listWrapperTypes, "listWrapperTypes");
+ this.listWrapperTypes.Name = "listWrapperTypes";
+ this.listWrapperTypes.ShowItemToolTips = true;
+ this.listWrapperTypes.Sorting = System.Windows.Forms.SortOrder.Descending;
+ this.listWrapperTypes.UseCompatibleStateImageBehavior = false;
+ this.listWrapperTypes.View = System.Windows.Forms.View.Details;
+ //
+ // columnHeader1
+ //
+ resources.ApplyResources(this.columnHeader1, "columnHeader1");
+ //
+ // columnHeader2
+ //
+ resources.ApplyResources(this.columnHeader2, "columnHeader2");
+ //
+ // _tabWrapperLocations
+ //
+ this._tabWrapperLocations.Controls.Add(this._layoutLocations);
+ resources.ApplyResources(this._tabWrapperLocations, "_tabWrapperLocations");
+ this._tabWrapperLocations.Name = "_tabWrapperLocations";
+ this._tabWrapperLocations.UseVisualStyleBackColor = true;
+ //
+ // _layoutLocations
+ //
+ resources.ApplyResources(this._layoutLocations, "_layoutLocations");
+ this._layoutLocations.Controls.Add(this.listStackTrace, 0, 1);
+ this._layoutLocations.Controls.Add(this.listWrapperLocations, 0, 0);
+ this._layoutLocations.Name = "_layoutLocations";
+ //
+ // listStackTrace
+ //
+ this.listStackTrace.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ columnMethod,
+ columnLine,
+ columnFile});
+ resources.ApplyResources(this.listStackTrace, "listStackTrace");
+ this.listStackTrace.FullRowSelect = true;
+ this.listStackTrace.MultiSelect = false;
+ this.listStackTrace.Name = "listStackTrace";
+ this.listStackTrace.ShowItemToolTips = true;
+ this.listStackTrace.UseCompatibleStateImageBehavior = false;
+ this.listStackTrace.View = System.Windows.Forms.View.Details;
+ //
+ // listWrapperLocations
+ //
+ this.listWrapperLocations.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.columnHeader3,
+ this.columnHeader4});
+ resources.ApplyResources(this.listWrapperLocations, "listWrapperLocations");
+ this.listWrapperLocations.FullRowSelect = true;
+ this.listWrapperLocations.HideSelection = false;
+ this.listWrapperLocations.MultiSelect = false;
+ this.listWrapperLocations.Name = "listWrapperLocations";
+ this.listWrapperLocations.ShowItemToolTips = true;
+ this.listWrapperLocations.Sorting = System.Windows.Forms.SortOrder.Descending;
+ this.listWrapperLocations.UseCompatibleStateImageBehavior = false;
+ this.listWrapperLocations.View = System.Windows.Forms.View.Details;
+ this.listWrapperLocations.SelectedIndexChanged += new System.EventHandler(this.listWrapperLocations_SelectedIndexChanged);
+ //
+ // columnHeader3
+ //
+ resources.ApplyResources(this.columnHeader3, "columnHeader3");
+ //
+ // columnHeader4
+ //
+ resources.ApplyResources(this.columnHeader4, "columnHeader4");
+ //
// DebugDialog
//
resources.ApplyResources(this, "$this");
@@ -101,13 +231,16 @@
this.Controls.Add(this.tableMain);
this.MinimizeBox = false;
this.Name = "DebugDialog";
- this.ShowInTaskbar = false;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
- this.TopMost = true;
this.tableMain.ResumeLayout(false);
this.tableMain.PerformLayout();
this.flowButtons.ResumeLayout(false);
this.flowButtons.PerformLayout();
+ this._tabs.ResumeLayout(false);
+ this._tabProperties.ResumeLayout(false);
+ this._tabWrapperTypes.ResumeLayout(false);
+ this._tabWrapperLocations.ResumeLayout(false);
+ this._layoutLocations.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
@@ -122,5 +255,17 @@
private System.Windows.Forms.Button buttonRefresh;
private System.Windows.Forms.Button buttonClose;
private System.Windows.Forms.Button buttonLog;
+ private System.Windows.Forms.TabControl _tabs;
+ private System.Windows.Forms.TabPage _tabProperties;
+ private System.Windows.Forms.TabPage _tabWrapperTypes;
+ private System.Windows.Forms.TabPage _tabWrapperLocations;
+ private System.Windows.Forms.ListView listWrapperTypes;
+ private System.Windows.Forms.ColumnHeader columnHeader1;
+ private System.Windows.Forms.ColumnHeader columnHeader2;
+ private System.Windows.Forms.TableLayoutPanel _layoutLocations;
+ private System.Windows.Forms.ListView listStackTrace;
+ private System.Windows.Forms.ListView listWrapperLocations;
+ private System.Windows.Forms.ColumnHeader columnHeader3;
+ private System.Windows.Forms.ColumnHeader columnHeader4;
}
}
\ No newline at end of file
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs
index 398ac6a..d6b6aaa 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.cs
@@ -1,4 +1,4 @@
-/// Copyright 2016 Kopano b.v.
+/// Copyright 2017 Kopano b.v.
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License, version 3,
@@ -35,18 +35,105 @@ namespace Acacia.Features.DebugSupport
{
public partial class DebugDialog : KopanoDialog
{
+ private readonly DisposableTracerFull _tracer;
public DebugDialog()
{
InitializeComponent();
Properties.SelectedObject = new DebugInfo();
+
+ _tracer = DisposableWrapper.GetTracer();
+ if (_tracer == null)
+ {
+ // If we don't have a wrapper tracer, hide the tabs
+ _tabs.SizeMode = TabSizeMode.Fixed;
+ _tabs.ItemSize = new Size(0, 1);
+ }
+ else
+ {
+ listWrapperTypes.ListViewItemSorter = new WrapperCountSorter();
+ listWrapperLocations.ListViewItemSorter = new WrapperCountSorter();
+ RefreshWrappers();
+
+ // Make it a bit bigger
+ Width = Width + 400;
+ Height = Height + 200;
+ }
}
private void UpdateFields()
{
Properties.Refresh();
+ RefreshWrappers();
}
+ #region Wrappers
+
+ private void RefreshWrappers()
+ {
+ // Wrapper types
+ listWrapperTypes.Items.Clear();
+ foreach(KeyValuePair type in _tracer.GetTypes())
+ {
+ string name = type.Key.Name;
+ if (type.Key.DeclaringType != null)
+ name = type.Key.DeclaringType.Name + "." + name;
+
+ ListViewItem item = new ListViewItem(name);
+ item.ToolTipText = type.Key.FullName;
+ item.SubItems.Add(type.Value.ToString());
+ listWrapperTypes.Items.Add(item);
+ }
+
+ listWrapperTypes.Columns[0].Width = -2;
+ listWrapperTypes.Columns[1].Width = -2;
+
+ // Wrapper locations
+ listWrapperLocations.Items.Clear();
+ foreach (KeyValuePair entry in _tracer.GetLocations())
+ {
+ ListViewItem item = new ListViewItem(entry.Key.DisplayName);
+ item.SubItems.Add(entry.Value.ToString());
+ item.Tag = entry.Key;
+ listWrapperLocations.Items.Add(item);
+ }
+
+ listWrapperLocations.Columns[0].Width = -2;
+ listWrapperLocations.Columns[1].Width = -2;
+ }
+
+ private class WrapperCountSorter : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ int ix = int.Parse(((ListViewItem)x).SubItems[1].Text);
+ int iy = int.Parse(((ListViewItem)y).SubItems[1].Text);
+ return iy - ix;
+ }
+ }
+
+ private void listWrapperLocations_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ listStackTrace.Items.Clear();
+ if (listWrapperLocations.SelectedItems.Count > 0)
+ {
+ DisposableTracerFull.CustomTrace trace = (DisposableTracerFull.CustomTrace)listWrapperLocations.SelectedItems[0].Tag;
+ foreach(DisposableTracerFull.CustomFrame frame in trace.Frames)
+ {
+ ListViewItem item = new ListViewItem(frame.MethodName);
+ item.SubItems.Add(frame.LineNumber.ToString());
+ item.SubItems.Add(frame.FileName ?? "");
+ listStackTrace.Items.Add(item);
+ }
+ }
+ foreach (ColumnHeader header in listStackTrace.Columns)
+ header.Width = -2;
+ }
+
+ #endregion
+
+ #region Cycling
+
private class DebugCycleInfo
{
private int cycleIndex = 0;
@@ -108,6 +195,12 @@ namespace Acacia.Features.DebugSupport
private DebugCycleInfo cycle;
+ ///
+ /// Runs the specific number of cycles. In each cycle the GAB is resynced. This is to test
+ /// memory errors, which show most frequently when using the GAB, as that touches most of
+ /// the code.
+ ///
+ /// The number of cycles to run
internal void DebugCycle(int count)
{
GAB.FeatureGAB gab = ThisAddIn.Instance.GetFeature();
@@ -118,6 +211,8 @@ namespace Acacia.Features.DebugSupport
}
}
+ #endregion
+
#region Logging
private const string INDENT = "+";
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx
index 547d1a0..e04e14b 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugDialog.resx
@@ -117,11 +117,35 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ False
+
+
+ Method
+
+
+
+ 44
+
+
+ False
+
+
+ File
+
+
+ 44
+
+
+ False
+
+
+ Line
+
Top, Bottom, Left, Right
-
True
@@ -137,18 +161,333 @@
True
+
+ buttonGC
+
+
+ System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ flowButtons
+
+
+ 0
+
+
+ buttonRefresh
+
+
+ System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ flowButtons
+
+
+ 1
+
+
+ buttonClose
+
+
+ System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ flowButtons
+
+
+ 2
+
+
+ buttonLog
+
+
+ System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ flowButtons
+
+
+ 3
+
+
+ RightToLeft
+
+
+
+ 4, 703
+
+
+ 4, 3, 4, 3
+
+
+ 615, 64
+
+
+ 1
+
+
+ flowButtons
+
+
+ System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ tableMain
+
+
+ 0
+
+
+ Properties
+
+
+ System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabProperties
+
+
+ 0
+
+
+ 4, 33
+
+
+ 3, 3, 3, 3
+
+
+ 609, 657
+
+
+ 0
+
+
+ General
+
+
+ _tabProperties
+
+
+ System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabs
+
+
+ 0
+
+
+ listWrapperTypes
+
+
+ System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabWrapperTypes
+
+
+ 0
+
+
+ 4, 33
+
+
+ 3, 3, 3, 3
+
+
+ 609, 657
+
+
+ 1
+
+
+ Wrapper types
+
+
+ _tabWrapperTypes
+
+
+ System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabs
+
+
+ 1
+
+
+ 1
+
+
+ Fill
+
+
+ 3, 328
+
+
+ 597, 320
+
+
+ 3
+
+
+ listStackTrace
+
+
+ System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _layoutLocations
+
+
+ 0
+
+
+ Fill
+
+
+ 3, 3
+
+
+ 597, 319
+
+
+ 2
+
+
+ listWrapperLocations
+
+
+ System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _layoutLocations
+
+
+ 1
+
+
+ Fill
+
+
+ 3, 3
+
+
+ 2
+
+
+ 603, 651
+
+
+ 2
+
+
+ _layoutLocations
+
+
+ System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabWrapperLocations
+
+
+ 0
+
+
+ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="listStackTrace" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="listWrapperLocations" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,Absolute,20" /><Rows Styles="Percent,50,Percent,50" /></TableLayoutSettings>
+
+
+ 4, 33
+
+
+ 3, 3, 3, 3
+
+
+ 609, 657
+
+
+ 2
+
+
+ Wrapper locations
+
+
+ _tabWrapperLocations
+
+
+ System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabs
+
+
+ 2
+
+
+ Fill
+
+
+ 3, 3
+
+
+ 617, 694
+
+
+ 3
+
+
+ _tabs
+
+
+ System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ tableMain
+
+
+ 1
+
+
+ 0, 0
+
+
+ 4, 3, 4, 3
+
+
+ 2
+
+
+ 623, 770
+
+
+ 0
+
+
+ tableMain
+
+
+ System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ $this
+
+
+ 0
+
+
+ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="flowButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_tabs" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0,Absolute,20" /></TableLayoutSettings>
+
True
-
- 352, 4
+ 483, 6
- 4, 4, 4, 4
+ 6, 6, 6, 6
- 91, 33
+ 126, 52
0
@@ -172,13 +511,13 @@
True
- 253, 4
+ 346, 6
- 4, 4, 4, 4
+ 6, 6, 6, 6
- 91, 33
+ 125, 52
1
@@ -202,13 +541,13 @@
True
- 145, 4
+ 196, 6
- 4, 4, 4, 4
+ 6, 6, 6, 6
- 100, 33
+ 138, 52
2
@@ -232,13 +571,13 @@
True
- 62, 4
+ 81, 6
- 4, 4, 4, 4
+ 6, 6, 6, 6
- 75, 33
+ 103, 52
3
@@ -258,47 +597,20 @@
3
-
- RightToLeft
-
-
- 3, 470
-
-
- 3, 2, 3, 2
-
-
- 447, 41
-
-
- 1
-
-
- flowButtons
-
-
- System.Windows.Forms.FlowLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- tableMain
-
-
- 0
-
-
- Top, Bottom, Left, Right
+
+ Fill
False
- 3, 2
+ 3, 3
- 3, 2, 3, 2
+ 4, 3, 4, 3
- 447, 464
+ 603, 651
2
@@ -310,55 +622,73 @@
System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- tableMain
+ _tabProperties
- 1
-
-
- 0, 0
-
-
- 3, 2, 3, 2
-
-
- 2
-
-
- 453, 513
-
-
0
-
- tableMain
+
+ Fill
-
- System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 3, 3
-
- $this
+
+ 603, 651
-
+
0
-
- <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="flowButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="Properties" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,100,AutoSize,0" /></TableLayoutSettings>
+
+ listWrapperTypes
+
+
+ System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ _tabWrapperTypes
+
+
+ 0
+
+
+ Type
+
+
+ 44
+
+
+ Count
+
+
+ 44
+
+
+ Type
+
+
+ 44
+
+
+ Count
+
+
+ 44
True
- 8, 16
+ 11, 24
True
- 453, 511
+ 623, 766
- 3, 2, 3, 2
+ 4, 3, 4, 3
CenterParent
@@ -366,10 +696,52 @@
Debug
+
+ columnMethod
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnFile
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnLine
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnHeader1
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnHeader2
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnHeader3
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ columnHeader4
+
+
+ System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
DebugDialog
- System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+ Acacia.UI.KopanoDialog, Kopano, Version=0.1.0.0, Culture=neutral, PublicKeyToken=null
\ No newline at end of file
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs
index 695331c..68a2535 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/DebugSupport/DebugInfo.cs
@@ -273,7 +273,7 @@ namespace Acacia.Features.DebugSupport
#endregion
-#region Helpers
+ #region Helpers
private string TimeToString(Stopwatch time)
{
@@ -297,6 +297,6 @@ namespace Acacia.Features.DebugSupport
return string.Format("{0:n1} {1}", dValue, SizeSuffixes[i]);
}
-#endregion
+ #endregion
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs
index 7d7e9d2..3c281ea 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/GlobalOptions.cs
@@ -107,6 +107,15 @@ namespace Acacia
}
private static readonly BoolOption COM_RELEASE = new BoolOption("COMRelease", true);
+ [AcaciaOption("Enables tracing of wrapper allocation. Should only be enabled for debugging, as it's very " +
+ "resource intensive.")]
+ public bool WrapperTrace
+ {
+ get { return GetOption(null, WRAPPER_TRACE); }
+ set { SetOption(null, WRAPPER_TRACE, value); }
+ }
+ private static readonly BoolOption WRAPPER_TRACE = new BoolOption("WrapperTrace", false);
+
[AcaciaOption("Enables or disables logging completely.")]
public bool Logging
{
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracer.cs
new file mode 100644
index 0000000..d1fc373
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracer.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Acacia.Utils
+{
+ public interface DisposableTracer
+ {
+ void Created(DisposableWrapper wrapper);
+ void Deleted(DisposableWrapper wrapper, bool wasDisposed);
+ void Disposed(DisposableWrapper wrapper);
+ }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerDummy.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerDummy.cs
new file mode 100644
index 0000000..415ccf8
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerDummy.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Acacia.Utils
+{
+ public class DisposableTracerDummy : DisposableTracer
+ {
+ public void Created(DisposableWrapper wrapper)
+ {
+ }
+
+ public void Deleted(DisposableWrapper wrapper, bool wasDisposed)
+ {
+ }
+
+ public void Disposed(DisposableWrapper wrapper)
+ {
+ }
+ }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerFull.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerFull.cs
new file mode 100644
index 0000000..37f5c37
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableTracerFull.cs
@@ -0,0 +1,182 @@
+using Acacia.Stubs.OutlookWrappers;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Reflection;
+
+namespace Acacia.Utils
+{
+ public class DisposableTracerFull : DisposableTracer
+ {
+ public class CustomFrame
+ {
+ private readonly StackFrame _frame;
+
+ public CustomFrame(StackFrame stackFrame)
+ {
+ this._frame = stackFrame;
+ }
+
+ public string MethodName
+ {
+ get
+ {
+ // Make the qualified method name
+ string name = _frame.GetMethod().Name;
+ Type t = _frame.GetMethod().DeclaringType;
+ while (t != null)
+ {
+ name = t.Name + "." + name;
+ t = t.DeclaringType;
+ }
+ return name;
+ }
+ }
+
+ public string FileName
+ {
+ get
+ {
+ return _frame.GetFileName();
+ }
+ }
+
+ public int LineNumber
+ {
+ get
+ {
+ return _frame.GetFileLineNumber();
+ }
+ }
+
+ public override string ToString()
+ {
+
+ // Add any file information
+ string location = "";
+ if (_frame.GetFileName() != null)
+ {
+ location += " @ " + _frame.GetFileName();
+ location += ":" + _frame.GetFileLineNumber();
+ }
+
+ return MethodName + location + "\n";
+ }
+ }
+
+ public class CustomTrace : IComparable
+ {
+ private static bool fullTrace = false;
+ private readonly StackTrace _stackTrace;
+ private readonly CustomFrame[] _frames;
+ private int _nameIndex;
+
+ public CustomTrace(StackTrace stackTrace)
+ {
+ this._stackTrace = stackTrace;
+
+ // Find a useful name to display
+ StackFrame[] frames = stackTrace.GetFrames();
+ for (_nameIndex = 0; _nameIndex < frames.Length; ++_nameIndex)
+ {
+ StackFrame frame = frames[_nameIndex];
+ if (!IsCreationMethod(frame.GetMethod()))
+ break;
+ }
+ int startIndex = fullTrace ? 0 : _nameIndex;
+
+ // Create a custom trace from the frames
+ _frames = new CustomFrame[stackTrace.FrameCount - startIndex];
+ for (int i = 0; i < _frames.Length; ++i)
+ _frames[i] = new CustomFrame(frames[i + startIndex]);
+ }
+
+ private bool IsCreationMethod(MethodBase method)
+ {
+ // Any method in Mapping or Wrappers is purely for creation
+ if (method.DeclaringType == typeof(Mapping) ||
+ method.DeclaringType == typeof(Stubs.Wrappers))
+ return true;
+
+ // As is any ctor in OutlookWrappers. Methods there aren't, as they might created a
+ // wrapper for a property
+ if (method.IsConstructor &&
+ method.DeclaringType.Namespace == "Acacia.Stubs.OutlookWrappers")
+ return true;
+
+ return false;
+ }
+
+ public override string ToString()
+ {
+ string s = "";
+ foreach (CustomFrame frame in _frames)
+ s += frame.ToString();
+ return s;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ToString().Equals(obj.ToString());
+ }
+
+ public override int GetHashCode()
+ {
+ return ToString().GetHashCode();
+ }
+
+ public int CompareTo(CustomTrace other)
+ {
+ return ToString().CompareTo(other.ToString());
+ }
+
+ public string DisplayName
+ {
+ get { return _frames[fullTrace ? _nameIndex : 0].MethodName; }
+ }
+
+ public CustomFrame[] Frames
+ {
+ get { return _frames; }
+ }
+ }
+
+ private readonly ConcurrentDictionary _types = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary _locations = new ConcurrentDictionary();
+
+ public void Created(DisposableWrapper wrapper)
+ {
+ _types.AddOrUpdate(wrapper.GetType(), 1, (i, value) => value + 1);
+ _locations.AddOrUpdate(new CustomTrace(wrapper.StackTrace), 1, (i, value) => value + 1);
+ }
+
+ public void Deleted(DisposableWrapper wrapper, bool wasDisposed)
+ {
+ if (!wasDisposed)
+ {
+ _types.AddOrUpdate(wrapper.GetType(), 0, (i, value) => value - 1);
+ _locations.AddOrUpdate(new CustomTrace(wrapper.StackTrace), 0, (i, value) => value - 1);
+ }
+ }
+
+ public void Disposed(DisposableWrapper wrapper)
+ {
+ _types.AddOrUpdate(wrapper.GetType(), 0, (i, value) => value - 1);
+ _locations.AddOrUpdate(new CustomTrace(wrapper.StackTrace), 0, (i, value) => value - 1);
+ }
+
+ public IEnumerable> GetTypes()
+ {
+ return _types;
+ }
+
+ public IEnumerable> GetLocations()
+ {
+ return _locations;
+ }
+ }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableWrapper.cs
index b7cefcf..8a0010c 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableWrapper.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/DisposableWrapper.cs
@@ -26,12 +26,28 @@ namespace Acacia.Utils
{
abstract public class DisposableWrapper : IDisposable
{
- private static Dictionary typeCounts = new Dictionary();
+ private static DisposableTracer tracer = InitTracer();
+
+ private static DisposableTracer InitTracer()
+ {
+ if (GlobalOptions.INSTANCE.WrapperTrace)
+ return new DisposableTracerFull();
+ return new DisposableTracerDummy();
+ }
+
+ public static DisposableTracerFull GetTracer()
+ {
+ return tracer as DisposableTracerFull;
+ }
+
+ private bool _isDisposed;
+ public readonly System.Diagnostics.StackTrace StackTrace;
protected DisposableWrapper()
{
Interlocked.Increment(ref Statistics.CreatedWrappers);
- this._createdTrace = new System.Diagnostics.StackTrace();
+ this.StackTrace = new System.Diagnostics.StackTrace(1, true);
+ tracer.Created(this);
}
~DisposableWrapper()
@@ -39,27 +55,17 @@ namespace Acacia.Utils
Interlocked.Increment(ref Statistics.DeletedWrappers);
if (!_isDisposed)
{
- Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
- // Dispose, but don't count auto disposals, so the stats show it.
+ Logger.Instance.Warning(this, "Undisposed wrapper: {0}", StackTrace);
DoRelease();
}
- else
- {
- --typeCounts[GetType()];
- }
+ tracer.Deleted(this, _isDisposed);
}
- private bool _isDisposed;
- private readonly System.Diagnostics.StackTrace _createdTrace;
-
virtual public void Dispose()
{
if (!_isDisposed)
{
- if (!typeCounts.ContainsKey(GetType()))
- typeCounts.Add(GetType(), 1);
- else
- ++typeCounts[GetType()];
+ tracer.Disposed(this);
_isDisposed = true;
Interlocked.Increment(ref Statistics.DisposedWrappers);