I\'ve been through a few questions over the network about this subject but I didn\'t find any answer for my question, or it\'s for another language or it doesn\'t answer totally
Is (explicit or not) useless code ignored by the compiler?
You can't easily determine it's useless, so the compiler can't either. The getter of TestRunTime.Length
can have side-effects, for example.
The background is that I maintain a lot of code (that I didn't write) and I was wondering if useless code should be a target
Before you refactor a piece of code, you have to verify what it does in order to be able to change it and say afterwards it still has the same result. Unit tests are a great way of doing this.
For the most part, you shouldn't worry about proactively removing useless code. If you run into performance issues, and your profiler says that some useless code is eating your clock cycles, then go nuclear on it. However, if the code truly does nothing and has no side effects, then it'll probably have little impact on running time.
That said, most compilers are not required to perform any optimizations, so relying on compiler optimizations is not always the smartest option. In many cases though, even a useless spin loop can execute pretty fast. A basic spinlock that loops one million times would compile into something like mov eax, 0 \ inc eax \ cmp eax, 1000000 \ jnz -8
. Even if we discounted on-CPU optimizations, that's only 3 cycles per loop (on a recent RISC style chip) since there is no memory access, so there won't be any cache invalidation. On a 1GHz CPU, that's only 3,000,000/1,000,000,000 seconds, or 3 milliseconds. That would be a pretty significant hit if you tried running it 60 times a second, but in many cases, it probably won't even be noticeable.
A loop like the one I described would almost definitely be peephole optimized to mov eax 1000000
, even in a JIT environment. It would likely be optimized further than that, but given no other context, that optimization is reasonable and would cause no ill effects.
tl;dr: If your profiler says that dead/useless code is using a noticeable amount of your run-time resources, remove it. Don't go on a witch hunt for dead code though; leave that for the rewrite/massive refactor down the line.
Bonus: If the code generator knew that eax
wasn't going to be read for anything other than the loop condition and wanted to retain the spinlock, it could generate mov eax, 1000000 \ dec eax \ jnz -3
and reduce the penalty of the loop by a cycle. Most compilers would just remove it entirely though.
I've made a little form to test it according to a few answerers ideas about using long.MaxValue
, here's my reference code:
public Form1()
{
InitializeComponent();
Stopwatch test = new Stopwatch();
test.Start();
myTextBox.Text = test.Elapsed.ToString();
}
and here's the code with kinda useless code:
public Form1()
{
InitializeComponent();
Stopwatch test = new Stopwatch();
test.Start();
for (int i = 0; i < int.MaxValue; i++)
{
}
myTextBox.Text = test.Elapsed.ToString();
}
You'll remark that I used int.MaxValue
instead of long.MaxValue
, I didn't want to spend the year day on this one.
As you can see:
---------------------------------------------------------------------
| | Debug | Release |
---------------------------------------------------------------------
|Ref | 00:00:00.0000019 | 00:00:00.0000019 |
|Useless code | 00:00:05.3837568 | 00:00:05.2728447 |
---------------------------------------------------------------------
The code isn't optimized. Hang on a bit, I'll try with some int[]
to test int[].Lenght
:
public Form1()
{
InitializeComponent();
int[] myTab = functionThatReturnInts(1);
Stopwatch test = new Stopwatch();
test.Start();
for (int i = 0; i < myTab.Length; i++)
{
}
myTextBox.Text = test.Elapsed.ToString();
}
public int[] functionThatReturnInts(int desiredSize)
{
return Enumerable.Repeat(42, desiredSize).ToArray();
}
And here's the results:
---------------------------------------------
| Size | Release |
---------------------------------------------
| 1 | 00:00:00.0000015 |
| 100 | 00:00:00 |
| 10 000 | 00:00:00.0000035 |
| 1 000 000 | 00:00:00.0003236 |
| 100 000 000 | 00:00:00.0312673 |
---------------------------------------------
So even with arrays, it doesn't get optimized at all.