Added statistics on tasks. Added debug cycling of gab resync.

This commit is contained in:
Patrick Simpson 2017-02-08 18:05:42 +01:00
parent 112a7cf26a
commit 9f237b76e0
13 changed files with 167 additions and 34 deletions

View File

@ -47,6 +47,76 @@ namespace Acacia.Features.DebugSupport
Properties.Refresh(); Properties.Refresh();
} }
private class DebugCycleInfo
{
private int cycleIndex = 0;
private int cycleCount;
private Timer timer = new Timer();
private GAB.FeatureGAB gab;
private int zeroCount = 1000;
public DebugCycleInfo(DebugDialog dlg, GAB.FeatureGAB gab, int count)
{
this.cycleCount = count;
this.gab = gab;
timer.Interval = 1000;
timer.Tick += (a, b) =>
{
dlg.Text = string.Format("Cycle {0} of {1}", cycleIndex + 1, cycleCount);
dlg.GarbageCollect();
if (((DebugInfo)dlg.Properties.SelectedObject).ActiveTasks == 0)
{
// Make sure the value is stable at zero
++zeroCount;
if (zeroCount >= 3)
{
zeroCount = 0;
Logger.Instance.Debug(this, "CYCLER");
++cycleIndex;
if (cycleIndex >= cycleCount)
{
timer.Stop();
dlg.Hide();
ThisAddIn.Instance.Quit();
}
else
{
DebugCycle();
}
}
}
};
}
public void Run()
{
timer.Start();
}
private void DebugCycle()
{
Tasks.Task(gab, "DebugCycle", () =>
{
gab.FullResync();
});
}
}
private DebugCycleInfo cycle;
internal void DebugCycle(int count)
{
GAB.FeatureGAB gab = ThisAddIn.Instance.GetFeature<GAB.FeatureGAB>();
if (gab != null)
{
cycle = new DebugCycleInfo(this, gab, count);
cycle.Run();
}
}
#region Logging #region Logging
private const string INDENT = "+"; private const string INDENT = "+";
@ -89,6 +159,11 @@ namespace Acacia.Features.DebugSupport
private void buttonGC_Click(object sender, EventArgs e) private void buttonGC_Click(object sender, EventArgs e)
{ {
GarbageCollect();
}
private void GarbageCollect()
{
GC.Collect(); GC.Collect();
GC.WaitForPendingFinalizers(); GC.WaitForPendingFinalizers();
GC.Collect(); GC.Collect();

View File

@ -32,6 +32,7 @@ namespace Acacia.Features.DebugSupport
{ {
Version, Version,
Memory, Memory,
Tasks,
Wrappers, Wrappers,
Misc, Misc,
System, System,
@ -133,6 +134,25 @@ namespace Acacia.Features.DebugSupport
#endregion #endregion
#region Tasks
[DebugCategory(DebugCategory.Tasks)]
public string Threading
{
get { return Tasks.Executor.Name; }
}
[DebugCategory(DebugCategory.Tasks)]
public long ActiveTasks { get { return Statistics.StartedTasks - Statistics.FinishedTasks; } }
[DebugCategory(DebugCategory.Tasks)]
public long StartedTasks { get { return Statistics.StartedTasks; } }
[DebugCategory(DebugCategory.Tasks)]
public long FinishedTasks { get { return Statistics.FinishedTasks; } }
#endregion
#region Wrappers #region Wrappers
[DebugCategory(DebugCategory.Wrappers)] [DebugCategory(DebugCategory.Wrappers)]
@ -163,12 +183,6 @@ namespace Acacia.Features.DebugSupport
} }
} }
[DebugCategory(DebugCategory.Misc)]
public string Threading
{
get { return Tasks.Executor.Name; }
}
[DebugCategory(DebugCategory.Misc)] [DebugCategory(DebugCategory.Misc)]
public bool ZPushSync public bool ZPushSync
{ {
@ -227,7 +241,7 @@ namespace Acacia.Features.DebugSupport
#endregion #endregion
#region Outlook #region Outlook
[DebugCategory(DebugCategory.System)] [DebugCategory(DebugCategory.System)]
public string OutlookVersion public string OutlookVersion
@ -247,7 +261,7 @@ namespace Acacia.Features.DebugSupport
} }
} }
#endregion #endregion
#region Helpers #region Helpers

View File

@ -45,11 +45,19 @@ namespace Acacia.Features.DebugSupport
RegisterButton(this, "Settings", false, ShowSettings); RegisterButton(this, "Settings", false, ShowSettings);
} }
public override void AfterStartup()
{
ShowAbout();
}
#region About dialog #region About dialog
public void ShowAbout() public void ShowAbout()
{ {
new AboutDialog().ShowDialog(); DebugDialog dd = new DebugDialog();
dd.Show();
dd.DebugCycle(5);
} }
#endregion #endregion

View File

@ -25,6 +25,9 @@ namespace Acacia.Features.DebugSupport
{ {
public static class Statistics public static class Statistics
{ {
public static long StartedTasks;
public static long FinishedTasks;
public static long CreatedWrappers; public static long CreatedWrappers;
public static long DeletedWrappers; public static long DeletedWrappers;
public static long DisposedWrappers; public static long DisposedWrappers;

View File

@ -226,6 +226,11 @@ namespace Acacia.Features
} }
public virtual void AfterStartup()
{
}
#endregion #endregion
#region Z-Push channels #region Z-Push channels

View File

@ -333,10 +333,14 @@ namespace Acacia.Features.GAB
} }
// Do the resync // Do the resync
int remaining = _gabsByDomainName.Count;
foreach (GABHandler gab in _gabsByDomainName.Values) foreach (GABHandler gab in _gabsByDomainName.Values)
{ {
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName); Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
Tasks.Task(this, "FullResync", () => gab.FullResync()); Tasks.Task(this, "FullResync", () =>
{
gab.FullResync();
});
} }
} }
finally finally

View File

@ -41,6 +41,7 @@ namespace Acacia.Stubs
/// Restarts the application /// Restarts the application
/// </summary> /// </summary>
void Restart(); void Restart();
void Quit();
void InvokeUI(Action action); void InvokeUI(Action action);

View File

@ -57,6 +57,11 @@ namespace Acacia.Stubs.OutlookWrappers
_app.Quit(); _app.Quit();
} }
public void Quit()
{
_app.Quit();
}
public event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad public event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad
{ {
add { _app.ItemLoad += value; } add { _app.ItemLoad += value; }

View File

@ -44,9 +44,6 @@ namespace Acacia
private set; private set;
} }
// TODO: remove?
private Control _dispatcher;
#region Features #region Features
/// <summary> /// <summary>
@ -92,10 +89,6 @@ namespace Acacia
int lcid = Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI); int lcid = Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid); Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid);
// Create a dispatcher
_dispatcher = new Control();
_dispatcher.CreateControl();
// The synchronization context is needed to allow background tasks to jump back to the UI thread. // The synchronization context is needed to allow background tasks to jump back to the UI thread.
// It's null in older versions of .Net, this fixes that // It's null in older versions of .Net, this fixes that
if (SynchronizationContext.Current == null) if (SynchronizationContext.Current == null)
@ -142,6 +135,9 @@ namespace Acacia
// Done // Done
Logger.Instance.Debug(this, "Startup done"); Logger.Instance.Debug(this, "Startup done");
Acacia.Features.DebugSupport.Statistics.StartupTime.Stop(); Acacia.Features.DebugSupport.Statistics.StartupTime.Stop();
foreach (Feature feature in Features)
feature.AfterStartup();
} }
catch (System.Exception e) catch (System.Exception e)
{ {

View File

@ -15,9 +15,11 @@
/// Consult LICENSE file for details /// Consult LICENSE file for details
using Acacia.Features; using Acacia.Features;
using Acacia.Features.DebugSupport;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
namespace Acacia.Utils namespace Acacia.Utils
@ -64,10 +66,29 @@ namespace Acacia.Utils
} }
public interface TaskExecutor public abstract class TaskExecutor
{ {
string Name { get; } public abstract string Name { get; }
void ExecuteTask(AcaciaTask task);
public void AddTask(AcaciaTask task)
{
Interlocked.Increment(ref Statistics.StartedTasks);
EnqueueTask(task);
}
abstract protected void EnqueueTask(AcaciaTask task);
protected void PerformTask(AcaciaTask task)
{
try
{
task.Execute();
}
finally
{
Interlocked.Increment(ref Statistics.FinishedTasks);
}
}
} }
public static class Tasks public static class Tasks
@ -103,12 +124,12 @@ namespace Acacia.Utils
public static void Task(Feature owner, string name, Action action) public static void Task(Feature owner, string name, Action action)
{ {
Executor.ExecuteTask(new AcaciaTask(owner, name, action)); Task(new AcaciaTask(owner, name, action));
} }
public static void Task(AcaciaTask task) public static void Task(AcaciaTask task)
{ {
Executor.ExecuteTask(task); Executor.AddTask(task);
} }
} }
} }

View File

@ -1,4 +1,6 @@
/// Copyright 2016 Kopano b.v. 
using Acacia.Features.DebugSupport;
/// Copyright 2016 Kopano b.v.
/// ///
/// This program is free software: you can redistribute it and/or modify /// 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, /// it under the terms of the GNU Affero General Public License, version 3,
@ -13,7 +15,6 @@
/// along with this program.If not, see<http://www.gnu.org/licenses/>. /// along with this program.If not, see<http://www.gnu.org/licenses/>.
/// ///
/// Consult LICENSE file for details /// Consult LICENSE file for details
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -40,15 +41,15 @@ namespace Acacia.Utils
while (!_tasks.IsCompleted) while (!_tasks.IsCompleted)
{ {
AcaciaTask task = _tasks.Take(); AcaciaTask task = _tasks.Take();
task.Execute(); PerformTask(task);
} }
} }
public void ExecuteTask(AcaciaTask task) protected override void EnqueueTask(AcaciaTask task)
{ {
_tasks.Add(task); _tasks.Add(task);
} }
public string Name { get { return "Background"; } } override public string Name { get { return "Background"; } }
} }
} }

View File

@ -73,7 +73,7 @@ namespace Acacia.Utils
{ {
AcaciaTask task = _tasks.Dequeue(); AcaciaTask task = _tasks.Dequeue();
Logger.Instance.Trace(task.Id, "Beginning task"); Logger.Instance.Trace(task.Id, "Beginning task");
task.Execute(); PerformTask(task);
Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds); Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds);
// Execute another task if available and we haven't taken too long. // Execute another task if available and we haven't taken too long.
} while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50); } while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50);
@ -99,7 +99,7 @@ namespace Acacia.Utils
/// </summary> /// </summary>
/// <param name="name">The name, for debugging and logging.</param> /// <param name="name">The name, for debugging and logging.</param>
/// <param name="action">The action to execute</param> /// <param name="action">The action to execute</param>
public void ExecuteTask(AcaciaTask task) override protected void EnqueueTask(AcaciaTask task)
{ {
if (_init == InitState.Uninitialised) if (_init == InitState.Uninitialised)
{ {
@ -112,6 +112,6 @@ namespace Acacia.Utils
_tasks.Enqueue(task); _tasks.Enqueue(task);
} }
public string Name { get { return "MainThread"; } } override public string Name { get { return "MainThread"; } }
} }
} }

View File

@ -24,11 +24,11 @@ namespace Acacia.Utils
{ {
public class TasksSynchronous : TaskExecutor public class TasksSynchronous : TaskExecutor
{ {
public void ExecuteTask(AcaciaTask task) protected override void EnqueueTask(AcaciaTask task)
{ {
task.Execute(); PerformTask(task);
} }
public string Name { get { return "Synchronous"; } } override public string Name { get { return "Synchronous"; } }
} }
} }