7
\$\begingroup\$

I have been playing around with some improvements to some sort algorithms like Selection Sort and Merge Sort and I ended up needing some sort of measurement to check if my versions were any faster than the original algorithm form. I also had a need to implement some sort of time measurement before but never did it, so here came the chance. And so I ended up coding the following measurement method:

public static double Measure(Action action, bool print = true)
{
    Stopwatch watch = new Stopwatch();
    const int precision = 1; //estimated precision of 1 milisecond on my machine
    const int error = 1; //max error
    const int times = 10;
    double min = double.MaxValue;
    for (int i = 0; i < times; ++i)
    {
        int iterations = 0;
        watch.Restart();
        while (watch.Elapsed.Milliseconds < precision*(100-error))
        {
            action();
            ++iterations;
        }
        watch.Stop();
        min = Math.Min(min, watch.Elapsed.Milliseconds*1000.0/iterations);
    }

    if(print)
        Debug.WriteLine("The action takes {0:N4} nanos to complete", min);

    return min;
}

Is this a well conducted measurement algorithm? Any suggestions or improvements that I could apply?

\$\endgroup\$
3
  • \$\begingroup\$ Can you explain what you are checking with watch.Elapsed.Milliseconds < precision*(100-error) condition? \$\endgroup\$ Commented Feb 14, 2014 at 12:56
  • \$\begingroup\$ I found that the stopWatch has a precision of about a milisecond. And so to only have a error of 1% i need to run a method at least during about 100 milliseconds, although this only applies to the methods that take only some nanoseconds to run. That's also why ChrisW suggested his approach. \$\endgroup\$ Commented Feb 14, 2014 at 13:49
  • \$\begingroup\$ So if my precision decreases (meaning that it would be bigger for example 2 milliseconds) I would need to test the method for about 200 milliseconds to have a 1% error. \$\endgroup\$ Commented Feb 14, 2014 at 15:32

1 Answer 1

6
\$\begingroup\$

The thing you're timing is:

while (watch.Elapsed.Milliseconds < precision*(100-error))
{
    action();
    ++iterations;
}

The problem is that if action takes a very short time, then most of what you're timing is the time it takes to call the watch.Elapsed.Milliseconds property.

A more accurate timer would be something like:

int iterations = 1000;
watch.Restart();
while (iterations--)
{
    action();
}
watch.Stop();

You would then need to do something to ensure you pick a suitable number of iterations (e.g. try again with 10 times as many iterations if the measured time is too short to be accurate).

\$\endgroup\$
1
  • \$\begingroup\$ You made a point there. I think that I could mix my code with yours. So I would find the number of iterations on 100 milliseconds and than measure the time again using your way. Hopefully will save some precious nanoseconds in measurament. \$\endgroup\$ Commented Feb 14, 2014 at 2:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.