HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Measure a given method's execution time - follow-up

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
methodtimefollowmeasuregivenexecution

Problem

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(this T t1, T t2)where T:IComparable
{
if (t1.CompareTo(t2) (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 GetIterations(Action action)
{
return Task.Run(() =>
{
const int minimumTime = 20;
int iterations = 0;
Watch.Start();
while (Watch.Elapsed.Milliseconds 0)
{
action();
}
Watch.Stop();
return Watch.Elapsed;
}

public static Task 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 Time

Solution

while (Watch.Elapsed.Milliseconds < minimumTime)


It probably won't affect this code, but Milliseconds doesn't do what you probably think it does. I think you want TotalMilliseconds.

public static Task 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);
        });
}


  • Generally speaking, if you can use await, you don't need ContinueWith().



  • What's the point of using Task.FromResult().ContinueWith()? Task.Run() would make much more sense here.



  • There is actually no reason to use Task and async-await here. You should use that only for truly asynchronous IO operations. If the caller wants to run your long-running CPU-bound code on a separate thread, they can easily do it themselves.



  • For performance-related code, it feels weird that you're calling GetIterations() even when it's not needed.

Code Snippets

while (Watch.Elapsed.Milliseconds < minimumTime)
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);
        });
}

Context

StackExchange Code Review Q#79869, answer score: 5

Revisions (0)

No revisions yet.