-O2 is usually the best choice, unless the code specifically benefits from other optimization levels.
-O3 is safe if your code conforms to the C/C++ standard, but will increase code size by a lot. This means it will occupy more of your CPU cache, which can be detrimental to performance in situations where many processes run in parallel. If your code works with -O2 but not with -O3, it is usually broken in some way.
-Os should be mentioned here too. There is almost never a reason to use it over -O2.
-Ofast does not guarantee that the compiled code does what the C/C++ standard says. It implies -ffast-math which can cause FP calculations to give unexpected results.
-O3 is safe if your code conforms to the C/C++ standard, but will increase code size by a lot. This means it will occupy more of your CPU cache, which can be detrimental to performance in situations where many processes run in parallel. If your code works with -O2 but not with -O3, it is usually broken in some way.
-Os should be mentioned here too. There is almost never a reason to use it over -O2.
-Ofast does not guarantee that the compiled code does what the C/C++ standard says. It implies -ffast-math which can cause FP calculations to give unexpected results.
Comment