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];
}
}
}