J
J
Jaguar_sea2016-02-05 08:30:38
C++ / C#
Jaguar_sea, 2016-02-05 08:30:38

Why does Stopwatch work like this?

There is this code:

static void Main()
        {
            for (int i = 2; i <= 15; i++)
            {
                Stopwatch timerForRecursiveFactorial = Stopwatch.StartNew();
                int RecursiveFactorial = ComputeFactorialRecursive(i);
                timerForRecursiveFactorial.Stop();
                long ticksSpentOnRecursiveFactorial = timerForRecursiveFactorial.ElapsedTicks;
                Console.WriteLine("Факториал вычеслен рекурсивно. Результат = " + RecursiveFactorial + ". Затрачено " + ticksSpentOnRecursiveFactorial + " тиков");

                Stopwatch timerForInterativeFactorial = Stopwatch.StartNew();
                int IterativeFactorial = ComputeFactorialIterative(i);
                timerForInterativeFactorial.Stop();
                long ticksSpentOnIterativeFactorial = timerForInterativeFactorial.ElapsedTicks;
                Console.WriteLine("Факториал вычеслен итеративно. Результат = " + IterativeFactorial + ". Затрачено " + ticksSpentOnIterativeFactorial + " тиков");

                if (ticksSpentOnIterativeFactorial < ticksSpentOnRecursiveFactorial)
                    Console.WriteLine("Победил итеративный метод");
                else
                    Console.WriteLine("Победил рекурсивный метод");
            }

            Console.ReadKey();
        }

In doing so, I get the following result:
Факториал вычеслен рекурсивно. Результат = 2. Затрачено 471 тиков
Факториал вычеслен итеративно. Результат = 2. Затрачено 526 тиков
Победил рекурсивный метод
Факториал вычеслен рекурсивно. Результат = 6. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 6. Затрачено 0 тиков
Победил итеративный метод
Факториал вычеслен рекурсивно. Результат = 24. Затрачено 0 тиков
Факториал вычеслен итеративно. Результат = 24. Затрачено 1 тиков
Победил рекурсивный метод
Факториал вычеслен рекурсивно. Результат = 120. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 120. Затрачено 1 тиков
Победил рекурсивный метод
Факториал вычеслен рекурсивно. Результат = 720. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 720. Затрачено 1 тиков
Победил рекурсивный метод
Факториал вычеслен рекурсивно. Результат = 5040. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 5040. Затрачено 0 тиков
Победил итеративный метод
Факториал вычеслен рекурсивно. Результат = 40320. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 40320. Затрачено 1 тиков
Победил рекурсивный метод
Факториал вычеслен рекурсивно. Результат = 362880. Затрачено 1 тиков
Факториал вычеслен итеративно. Результат = 362880. Затрачено 0 тиков
Победил итеративный метод

Why do I get the correct tick value only on the first iteration? What have I done wrong?

Answer the question

In order to leave comments, you need to log in

5 answer(s)
M
Michael, 2016-02-05
@Sing303

This is because of the JIT compiler that is used in .NET
MSIL bytecode is translated into machine code once by the JIT compiler and subsequent execution of that code is much faster because the target code has been generated and cached

S
Stanislav Makarov, 2016-02-05
@Nipheris

Are you kidding me to time the calculation like that?) You don’t think on Electronics that several iterations / recursive calls will be executed so quickly that you won’t even notice. Mikhail probably named the probable reason for this behavior, but this does not negate the fact that you are doing the experiment poorly.
When measuring performance, the same calculations need to be performed many times, for example, 100 thousand times for each option, or even a million. Then you will get a more or less intelligible result for comparison, and you will not stumble upon all sorts of subtleties of the CLR.

N
nirvimel, 2016-02-05
@nirvimel

Everything is correct. ElapsedTicks shows the number of ticks of the timer, but the timer does not have time to tick even once during the calculation of the factorial, or one tick happens accidentally. In the first iteration, many hundreds of ticks pass, since the JIT compiler works on the first call, the running time of the compiled code is negligible compared to the compilation time.
What to do:

  1. Perform a call to the measured function in a loop with a depth of tens or hundreds of thousands of iterations and divide the resulting interval by the number of iterations. The exact selection of the amount is carried out manually so that the total duration of the entire test is a few seconds.
  2. Before the first real measurement, it is necessary to do a "warm-up" - several tens of thousands of idle iterations without measurements.

V
Vitaly Pukhov, 2016-02-05
@Neuroware

Quite strange, the code looks correct, as a "crutch" I can advise you to reset both stopwatch periodically

D
Dmitry Kovalsky, 2016-02-05
@dmitryKovalskiy

And you put a break at the beginning of the loop and look at the state of the objects at each iteration. Also check that all code is executed on each iteration.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question