Skip to content

Instantly share code, notes, and snippets.

@programmation
Created July 10, 2017 01:55
Show Gist options
  • Save programmation/4f0b89b6ae32a4efa7d3e7dc2305372b to your computer and use it in GitHub Desktop.
Save programmation/4f0b89b6ae32a4efa7d3e7dc2305372b to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace MyNamespace
{
public interface IPerformanceTracker
{
ObservableCollection<PerformanceSummary> Metrics { get; }
void Track(PerformanceMetric metric);
}
public class PerformanceMetric
{
public string Name { get; private set; }
public double Value { get; private set; }
public PerformanceMetric(string name, double value)
{
Name = name;
Value = value;
}
}
public class PerformanceTimer : IDisposable
{
private bool _isStarted;
private Stopwatch _stopwatch;
public string Name { get; private set; }
public PerformanceTimer(string name, bool autoStart = true)
{
Name = name;
_stopwatch = new Stopwatch();
if (autoStart)
{
Start();
}
}
public void Start()
{
if (_isStarted)
{
return;
}
_stopwatch.Start();
_isStarted = true;
}
public void Stop()
{
if (!_isStarted)
{
return;
}
_stopwatch.Stop();
_isStarted = false;
}
public PerformanceMetric ToMetric()
{
return new PerformanceMetric(Name, _stopwatch.ElapsedMilliseconds);
}
private bool _isDisposed = false; // To detect redundant calls
protected virtual void Dispose(bool isDisposing)
{
if (_isDisposed)
{
return;
}
if (isDisposing)
{
Stop();
#if !RELEASE
PerformanceTracker.Instance.Track(ToMetric());
#endif
}
_isDisposed = true;
}
public void Dispose()
{
Dispose(true);
}
}
public class PerformanceSummary : NotifyingModel
{
public string Name { get; private set; }
public int WindowSize { get; private set; }
private int _valueCount;
private IList<double> _values;
public IList<double> Values
{
get { return _values; }
set { SetProperty(ref _values, value); }
}
public string FormattedMessage
{
get { return String.Format($"{Name}: {String.Join(",", Values)}"); }
}
private double _lastValue;
public double LastValue
{
get { return _lastValue; }
}
private double _maxValue;
public double MaxValue
{
get { return _maxValue; }
}
private double _averageValue;
public double AverageValue
{
get { return _averageValue; }
}
public PerformanceSummary(string name, int windowSize = 10)
{
Name = name;
WindowSize = windowSize;
Values = new List<double>();
Values.Resize(WindowSize);
PropertyChanged += HandlePropertyChanged;
}
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Values))
{
_lastValue = _valueCount > 0 ? Values[_valueCount - 1] : 0;
RaisePropertyChanged(nameof(LastValue));
_maxValue = Values.Max();
RaisePropertyChanged(nameof(MaxValue));
if (_valueCount > 0)
{
_averageValue = Values.Sum() / _valueCount;
RaisePropertyChanged(nameof(AverageValue));
}
}
}
public void Track(double value)
{
Debug.WriteLine($"Performance tracked: {Name} @ {value}ms");
_valueCount = Math.Min(_valueCount + 1, WindowSize);
Values.Insert(0, value);
Values.Resize(WindowSize);
RaisePropertyChanged(nameof(Values));
}
}
public class PerformanceTracker : NotifyingModel, IPerformanceTracker
{
private static object _guard = new object();
private ActionBlock<PerformanceMetric> _trackedPerformance;
private ObservableCollection<PerformanceSummary> _metrics;
public ObservableCollection<PerformanceSummary> Metrics
{
get { return _metrics; }
private set { SetProperty(ref _metrics, value); }
}
private static PerformanceTracker _instance;
public static PerformanceTracker Instance
{
get
{
lock (_guard)
{
if (_instance == null)
{
_instance = new PerformanceTracker();
}
}
return _instance;
}
}
public PerformanceTracker()
{
_trackedPerformance = new ActionBlock<PerformanceMetric>((m) =>
{
ProcessNewMetric(m);
});
Metrics = new ObservableCollection<PerformanceSummary>();
}
private void ProcessNewMetric(PerformanceMetric metric)
{
var summary = Metrics.FirstOrDefault(m => m.Name == metric.Name);
if (summary == null)
{
summary = new PerformanceSummary(metric.Name);
Metrics.Add(summary);
}
summary.Track(metric.Value);
}
public void Track(PerformanceMetric metric)
{
#if !RELEASE
_trackedPerformance.Post(metric);
#endif
}
public static TResult TrackPerformance<TResult>(string metricName, Func<TResult> trackedFunction)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = trackedFunction();
return result;
}
}
public static TResult TrackPerformance<T1, TResult>(string metricName, Func<T1, TResult> trackedFunction, T1 arg1)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = trackedFunction(arg1);
return result;
}
}
public static TResult TrackPerformance<T1, T2, TResult>(string metricName, Func<T1, T2, TResult> trackedFunction, T1 arg1, T2 arg2)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = trackedFunction(arg1, arg2);
return result;
}
}
public static TResult TrackPerformance<T1, T2, T3, TResult>(string metricName, Func<T1, T2, T3, TResult> trackedFunction, T1 arg1, T2 arg2, T3 arg3)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = trackedFunction(arg1, arg2, arg3);
return result;
}
}
public static async Task TrackPerformanceAsync(string metricName, Func<Task> trackedFunctionAsync)
{
using (var timer = new PerformanceTimer(metricName))
{
await trackedFunctionAsync();
}
}
public static async Task<TResult> TrackPerformanceAsync<TResult>(string metricName, Func<Task<TResult>> trackedFunctionAsync)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync();
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, TResult>(string metricName, Func<T1, Task<TResult>> trackedFunctionAsync, T1 arg1)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, TResult>(string metricName, Func<T1, T2, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, TResult>(string metricName, Func<T1, T2, T3, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, TResult>(string metricName, Func<T1, T2, T3, T4, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, T5, TResult>(string metricName, Func<T1, T2, T3, T4, T5, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4, arg5);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, T5, T6, TResult>(string metricName, Func<T1, T2, T3, T4, T5, T6, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4, arg5, arg6);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, T5, T6, T7, TResult>(string metricName, Func<T1, T2, T3, T4, T5, T6, T7, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(string metricName, Func<T1, T2, T3, T4, T5, T6, T7, T8, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
return result;
}
}
public static async Task<TResult> TrackPerformanceAsync<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>(string metricName, Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, Task<TResult>> trackedFunctionAsync, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
{
using (var timer = new PerformanceTimer(metricName))
{
var result = await trackedFunctionAsync(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
return result;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment