A long time ago, I've written a method that would allow me to measure the amount of time a method takes to run. I've decided to tweak this method and make use of TPL since measuring a method may take some time.
public static class ComparableUtils
{
public static T Min<T>(this T t1, T t2)where T:IComparable
{
if (t1.CompareTo(t2) <= 0)
{
return t1;
}
return t2;
}
public static T Max<T>(this T t1, T t2) where T : IComparable
{
if (t1.CompareTo(t2) >= 0)
{
return t1;
}
return t2;
}
}
public static class TestUtils
{
private static readonly Stopwatch Watch = new Stopwatch();
//This determines a minimum amount of iterations needed to perform to get a significative time measurment
private static Task<int> GetIterations(Action action)
{
return Task.Run(() =>
{
const int minimumTime = 20;
int iterations = 0;
Watch.Start();
while (Watch.Elapsed.Milliseconds < minimumTime)
{
action();
++iterations;
}
return iterations;
});
}
private static TimeSpan MeasureTime(Action action, int iterations)
{
Watch.Restart();
while (iterations-- > 0)
{
action();
}
Watch.Stop();
return Watch.Elapsed;
}
public static Task<Time> Measure(Action action, int? iterations = null, int times = 1)
{
return Task.FromResult(iterations)
.ContinueWith(async t => t.Result.GetValueOrDefault(await GetIterations(action)))
.Unwrap()
.ContinueWith(t =>
{
var iters = t.Result;
TimeSpan timeTaken = TimeSpan.MaxValue;
for (int i = 0; i < times; ++i)
{
timeTaken = MeasureTime(action, iters).Min(timeTaken);
}
return new Time(timeTaken.Ticks*100/iters);
});
}
}
public class Time
{
private readonly long _nanoSeconds;
public Time(long nanoSeconds)
{
_nanoSeconds = nanoSeconds;
}
public override string ToString()
{
if (_nanoSeconds < 9999)
{
return _nanoSeconds.ToString()+"ns";
}
return new TimeSpan(_nanoSeconds / 100).ToString("g");
}
}
Is this a well conducted measurement algorithm? Is there something that is amiss?