C #, for loops and speed test ... Is the exact same loop faster the second time?

public Int64 ReturnDifferenceA() { User[] arrayList; Int64 firstTicks; IList<User> userList; Int64 secondTicks; System.Diagnostics.Stopwatch watch; userList = Enumerable .Range(0, 1000) .Select(currentItem => new User()).ToList(); arrayList = userList.ToArray(); watch = new Stopwatch(); watch.Start(); for (Int32 loopCounter = 0; loopCounter < arrayList.Count(); loopCounter++) { DoThings(arrayList[loopCounter]); } watch.Stop(); firstTicks = watch.ElapsedTicks; watch.Reset(); watch.Start(); for (Int32 loopCounter = 0; loopCounter < arrayList.Count(); loopCounter++) { DoThings(arrayList[loopCounter]); } watch.Stop(); secondTicks = watch.ElapsedTicks; return firstTicks - secondTicks; } 

As you can see, it is really simple. Create a list of users, create an array, start the clock, connect the list and call the method, stop viewing. Reiteration. Complete by returning the difference from the first and second.

Now I'm calling with them:

 differenceList = Enumerable .Range(0, 50) .Select(currentItem => ReturnDifferenceA()).ToList(); average = differenceList.Average(); differenceListA = Enumerable .Range(0, 50) .Select(currentItem => ReturnDifferenceA()).ToList(); averageA = differenceListA.Average(); differenceListB = Enumerable .Range(0, 50) .Select(currentItem => ReturnDifferenceA()).ToList(); averageB = differenceListB.Average(); 

Now the fun part is that all the average values ​​are positive with a relatively large value, from 150 to 300 thousand ticks.

What I don't understand is that I look at the same list, in the same way, with the same method, and yet there is such a difference. Is there any kind of caching?

Another interesting thing: if I iterate over the list before the first section of the stopwatch, the average is about 5,000 or so.

+4
source share
7 answers

by the way, using IEnumerable.Count () in an array is hundreds of times slower than Array.Length ... Although this does not answer the question at all.

+4
source

You work in a high-level language with a runtime that does a lot of caching and performance optimization, this is common. This is sometimes called warming up a virtual machine or warming up a server (when it's a production application).

If something is done multiple times, you will often notice that the first time has a larger measured runtime, and the rest should be aligned to a smaller amount.

I do this in MATLAB code and see that the first time I run the testing cycle, it takes five seconds, and the subsequent time takes a fifth of a second. This is a huge difference because it is an interpreted language that requires some form of compilation, but in fact it does not affect your performance, because the vast majority will be "the second time in any production application.

+5
source

It is possible that DoThings () did not compile JIT into native code until the first call.

+3
source

Because .NET, like the Java platform, is a JIT environment. All high-level .NET code is compiled into bytecode in the Microsoft Intermediate Language.

To run your program, this bytecode must be compiled / translated to your own machine code. However, compiled .NET-programmed files are not stored in native machine code, but in intermediate bytecode of an intermediate virtual machine.

The first run of JIT compiled, so it took extra time. Subsequent runs no longer need to compile JIT, but native code is retrieved from the JIT cache, so it should be faster.

Was your application supported without completing subsequent runs? Then the second reason is also related to VM. (VM: 1 = virtual machine, VM: 2 = virtual memory). All modern generalized operating systems perform their processes in virtual memory, which is a real memory card to allow the operating system to manage and optimize the use of system resources. Lesser-used processes are often flushed to the disk cache so that other processes have optimal resource utilization.

For the first time, your process was not in virtual memory, so it had to carry the overhead of being brought into memory. Because subsequently your process was one of the most recently used top lists (also at the bottom of the list that was recently used), it has not yet been deleted to disk cache.

In addition, resources will be removed by the OS in your process as needed. Thus, for the first round, your process had to go through pushing envelope competition to the OS in order to expand the boundaries of its resources.

The virtual machine allows .NET and Java to abstract most of the software functions to a standalone, machine-independent level, dividing and therefore leaving fewer problems for machine-dependent engineers to solve. Although Microsoft Windows runs on a fairly unified x86 streaming hardware, there are sufficient differences with different OS versions and CPU models to guarantee an abstracted virtual machine to give .NET programmers and users a consistent view.

+1
source

You say that you do not do this 3 times, and the second and third times are relatively close. It seems to me that this happens only for the first time, when the cycle goes slowly.

0
source

I would suspect that the function you are calling is not Just-In-Timed until the first run. What you can try, run it once, then stop it and run it again. Without changing the compilation code, the Just-In-Time from the previous run should still be fine, and any remaining optimizations that you see are actual caching effects at work.

0
source

Put aside the question of letting a VM or machine warm up, caching, optimizing JIT for a moment: what else does your computer do? Are any of the 3e42 system services and task slots trapping some processor? Maybe your Steam client decided to check for updates, or did IE have to do something terribly important, or did your antivirus program interfere?

Your test is only useful to the extent that you can isolate it from all other software running on your field. Before attempting to measure a run, disable each bit of the software.

But then what do I know? - Perhaps your measurement method is controlled by the .net environment (or otherwise) and takes into account only virtual run-time cycles.

0
source

All Articles