Does caching calculated loop indexes make a difference?

Does caching calculated loop indexes make a difference?

Recently I was reviewing code to a real time financial application. Within a major for-loop construct, I came across the following subset of C# code:
 

Look how many times [index – 1] is referenced in the above code sample.

 

Every programmer knows that mathematical computations can require a lot of CPU time depending on the calculation. In the above example, while subtraction itself isn’t the worst performance-wise, repeating the same calculation numerous times can impact performance.

 

That’s where this Curious Consultant started wondering… is there a performance gain in C# if instead of calculating indexes on the fly, we do it once at the beginning of the loop, store that value, and use that value instead? What would happen if we removed the multiple subtraction operations? Eg, caching calculated loop indexes.

 

Let’s find out!

 

Constructing the Test

There is 1 method used for this test:

  • the first part calculates the index we’ll use to access objects and store in a local variable to provide a caching mechanism:
  • the second part does it straight up every time. x – 1. x – 1. x – 1:

 

We perform this looping while accessing common C# arrays and objects:

 

The code is written in Visual Studio 2017 targeting .Net Framework version 4.8 x64, compiled in “Release” mode the build option “Optimize Code” checked. The source code is available at the end of this blog so you can benchmark it on your own system.

 

Assumptions:

  • No exception handling as no exceptions should occur
  • to make the test worth-while, the cached index value had to be used at least half a dozen times to overcome the the cost of allocating the variable and assigning it.

 

The exe file was run under Windows 10 Professional 64-bit with 32GB of memory.

 

The test was run with each child method called the following number of times:

  • 1,000
  • 10,000
  • 1,000,000
  • 10,000,000
  • 100,000,000

 

What do you think will happen?

Before starting, I predicted that the cached value would show a clear winning streak in the results. Whether it won by a little or a lot didn’t bother me so much as that it demonstrated a clear victory.

 

This test was run 3 times.

 

All times are indicated in minutes.seconds.milliseconds format. Lower numbers indicate faster run time performance.

 

Winners are highlighted in green; there are no points for second place.

 

 

Number of Loops

Run #1

1,000

10,000

1,000,000

10,000,000

100,000,000

With Caching

00:00.0000025

00:00.0001509

00:00.0010144

00:00.0466154

00:05.1184002

Without Caching

00:00.0000006

00:00.0001142

00:00.0004692

00:00.0444236

00:05.1111640

Run #2

1,000

10,000

1,000,000

10,000,000

100,000,000

With Caching

00:00.0000026

00:00.0001911

00:00.0008241

00:00.0433287

00:05.0532665

Without Caching

00:00.0000004

00:00.0000780

00:00.0003955

00:00.0458396

00:05.0436073

Run #3

1,000

10,000

1,000,000

10,000,000

100,000,000

With Caching

00:00.0000024

00:00.0002148

00:00.0004917

00:00.0459788

00:05.0204457

Without Caching

00:00.0000003

00:00.0000545

00:00.0004701

00:00.0479565

00:05.0069124

 

In Summary:

The prediction certainly was wrong. In C#, it’s quite evident from the results that calculating the array / object index every single time won hands down.

 

And this is when [x – 1] is used at least 8 times in the code.

 

I could be wrong, but I suspect this happens because when doing the [x – 1], the CPU isn’t having to do a variable lookup, get the value, and place it where needed. Instead, it does a quick calculation, and doesn’t have the store the results anywhere, thus saving on memory lookup operations.

 

So in the more practical world, caching a calculated loop index isn’t the way to go unless your own benchmarks can confirm a higher win rate.

 

The Code:

 

David Lozinski