using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace Artemis.Core { /// /// Represents a set of profiling measurements /// public class ProfilingMeasurement { private bool _filledArray; private int _index; private long _last; private bool _open; private long _start; internal ProfilingMeasurement(string identifier) { Identifier = identifier; } /// /// Gets the unique identifier of this measurement /// public string Identifier { get; } /// /// Gets the last 1000 measurements /// public long[] Measurements { get; } = new long[1000]; /// /// Starts measuring time until is called /// public void Start() { _start = Stopwatch.GetTimestamp(); _open = true; } /// /// Stops measuring time and stores the time passed in the list /// /// An optional correction in ticks to subtract from the measurement /// The time passed since the last call public long Stop(long correction = 0) { if (!_open) return 0; long difference = Stopwatch.GetTimestamp() - _start - correction; _open = false; Measurements[_index] = difference; _index++; if (_index >= 1000) { _filledArray = true; _index = 0; } _last = difference; return difference; } /// /// Gets the last measured time /// public TimeSpan GetLast() { return new TimeSpan(_last); } /// /// Gets the average time of the last 1000 measurements /// public TimeSpan GetAverage() { if (!_filledArray && _index == 0) return TimeSpan.Zero; return _filledArray ? new TimeSpan((long) Measurements.Average(m => m)) : new TimeSpan((long) Measurements.Take(_index).Average(m => m)); } /// /// Gets the min time of the last 1000 measurements /// public TimeSpan GetMin() { if (!_filledArray && _index == 0) return TimeSpan.Zero; return _filledArray ? new TimeSpan(Measurements.Min()) : new TimeSpan(Measurements.Take(_index).Min()); } /// /// Gets the max time of the last 1000 measurements /// public TimeSpan GetMax() { if (!_filledArray && _index == 0) return TimeSpan.Zero; return _filledArray ? new TimeSpan(Measurements.Max()) : new TimeSpan(Measurements.Take(_index).Max()); } /// /// Gets the nth percentile of the last 1000 measurements /// public TimeSpan GetPercentile(double percentile) { if (!_filledArray && _index == 0) return TimeSpan.Zero; long[] collection = _filledArray ? Measurements.OrderBy(l => l).ToArray() : Measurements.Take(_index).OrderBy(l => l).ToArray(); return new TimeSpan((long) Percentile(collection, percentile)); } private static double Percentile(long[] elements, double percentile) { Array.Sort(elements); double realIndex = percentile * (elements.Length - 1); int index = (int) realIndex; double frac = realIndex - index; if (index + 1 < elements.Length) return elements[index] * (1 - frac) + elements[index + 1] * frac; return elements[index]; } } }