I think you have a wrong understanding about optimization, so here are some facts about it:
First of all, optimization is completely irrelevant for 99% of your code! That is the most important fact about optimization: The vast majority of any code is executed so seldomly, that there is virtually no payoff in optimizing it.
Thus, the most important skill you need to optimize your code, is to determine where to optimize. Most people use profilers for that.
However, the most important optimizations are usually on the algorithmic level. That is, if your basic code structure is bad, you can micro-optimize it all you want, it will never perform well, while an entirely crappy implementation using a more advantageous structure outperforms it anytime. And it is entirely up to you as a programmer, to find the better code structures, and to use them to your advantage. Your compiler can't do this, because it simply cannot see the big picture.
In my experience, the things that you need to look at on the algorithmic level are mainly:
Where do copies occur?
This was a common failure in C++ code until move construction came along. Still, it's better not to have to copy/move your data all the time. Especially, it needs to be avoided to incur quadratic copying costs, as you typically do when you concatenate strings in a loop.
Where do I use expensive operations like disk accesses/network communication?
You can perform a lot of computation while the system fetches a single block of data from a spinning disk. Thus, when you have operations with high costs, these are the ones that need to be optimized. Your compiler won't help you one bit with that. Other operations to look for: Locks, system calls, and memory allocations.
Can I represent my data in such a way that all the questions I have to ask about the data can be answered in a trivial, low-cost way?
This is the most tricky, effective, and fun thing to do. When you do it earnestly, you'll find that you can get the complexities of many problems down to a linear or even constant time complexity.
So, to answer your question more directly:
Should I write my code to be clear what I am doing and rely on the
optimizer to clean up my code efficiency, or should I be obsessive
about getting every last ounce of power out of my code?
The 99% of performance irrelevant code should definitely see no micro-optimization. It's entirely contraproductive.
And how much speed/size am I losing on by choosing one option over the
other?
None in 99% of your code. It's the last percent that matters. My experience is, that micro-optimizations easily yield a speedup of 2x or more. But as I said, the power of micro-optimizations is limited: What is a 2x improvement when you can improve the complexity of your algorithm from O(N^2)
to O(1)
? (Still, there are cases where you should go for the O(N^2)
algorithm because your problem sizes are too small!)
TL,DR: Don't even think about micro-optimization before you have done a thorough analysis!