One of these days, going through some code at work I noticed a colleague had made a for loop explicitly defining the iteration variable as a short
(which is an Int16
) instead of an int
(or Int32
) as usual (or in my case var
, which ends up being an int
anyway).
Something like the following, just for context:
After seeing this I thought, yeah, he's right, we should be more careful and use the types we really need. If we're iterating on a short range of values, why not use short
(or a even smaller type)? It may even have a (probably almost unnoticeable) gain in performance as we're saving memory right? Oh how wrong was I 😇
I began to wonder, why is it so unusual for us to see short
s used in this context, and in the spirit of finding excuses for doing anything but what one's supposed to do, I went on searching for an answer (you can experience this massive search engine endeavor here).
I ended up in this MSDN question from 2006 that has answers for this.
TLDR:
It's a performance thing. A CPU works more efficient when the data with equals to the native CPU register width. This applies indirect to .NET code as well.
In most cases using int in a loop is more efficient than using short. My simple tests showed a performance gain of ~10% when using int.
Some more link clicking took me to Stack Overflow and this question with some more explanations if you're interested in checking it out.
Of course I wanted to check it out for myself and rolled a kind of stupid benchmark just for fun (using the awesome BenchmarkDotNet library).
I even added a long
(Int64
) to the mix just to see the result, which was:
Method | Mean | Error | StdDev | Scaled | ScaledSD | Allocated |
---|---|---|---|---|---|---|
ForUsingInt | 9.601 us | 0.1850 us | 0.2594 us | 1.00 | 0.00 | 0 B |
ForUsingShort | 17.963 us | 0.3835 us | 0.4565 us | 1.87 | 0.07 | 0 B |
ForUsingLong | 9.112 us | 0.2013 us | 0.1977 us | 0.95 | 0.03 | 0 B |
So, as expected given the previous explanations, the int
outperforms the short
. The long
keeps up with the int
(maybe because I'm on a 64 bit machine, so a long
is of native register size?). I would take this performance differences with a grain of salt, as in the real world we don't have an empty for
(hopefully), but yup, there is a difference.
If you want to take the benchmark and dig around a little more, you can get it from this repo.
NOTE: if I messed up on the benchmark by not taking something into consideration, please let me know.
Thanks for stopping by, cyaz!
PS: originally posted here
Top comments (2)
Good article.
I'd expect the compiler to optimize away this kind of difference (i.e. ignore
short
and uselong
instead).Maybe int32 is on-par with int64 on a 64-bit machine because these machines are still expected to execute a lot of 32-bit code and the hardware is optimized for the conversion?
Yeah, that would be my guess as well (but didn’t dig any deeper).