Created
July 10, 2017 01:55
-
-
Save programmation/4f0b89b6ae32a4efa7d3e7dc2305372b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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