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.
.Length
could have side-effects (if not an array) – DerisiveTestRunTime.Length
is likelong.MaxValue
, then it would be waiting there for a while. – Chaqueta