He escuchado de varias fuentes (aunque principalmente de un colega mío), que compilar con un nivel de optimización de -O3
g ++ es de alguna manera 'peligroso', y debe evitarse en general a menos que se demuestre que es necesario.
¿Es esto cierto? Y si es así, ¿por qué? ¿Debería seguir -O2
?
c++
optimization
g++
compiler-flags
Dunnie
fuente
fuente
-O3
se considera particularmente con errores? Creo que quizás pueda "empeorar" el comportamiento indefinido, ya que puede hacer cosas raras y maravillosas basadas en ciertas suposiciones, pero eso sería culpa tuya. En general, diría que está bien.-O2
se enciende-fstrict-aliasing
, y si su código sobrevive, entonces probablemente sobrevivirá a otras optimizaciones, ya que esa es una de las personas que se equivocan una y otra vez. Dicho esto,-fpredictive-commoning
solo está-O3
habilitado, y habilitarlo podría habilitar errores en su código causados por suposiciones incorrectas sobre concurrencia. Cuanto menos incorrecto sea su código, menos peligrosa es la optimización ;-)-Ofast
, apaga el manejo de NaNs que cumple con IEEE, por ejemploRespuestas:
En los primeros días de gcc (2.8, etc.) y en los tiempos de egcs, y redhat 2.96 -O3 era bastante defectuoso a veces. Pero esto fue hace más de una década, y -O3 no es muy diferente a otros niveles de optimizaciones (en errores).
Sin embargo, tiende a revelar casos en los que las personas confían en un comportamiento indefinido, debido a que se basan más estrictamente en las reglas, y especialmente en los casos esquimales, de los idiomas.
Como nota personal, llevo muchos años ejecutando software de producción en el sector financiero con -O3 y todavía no he encontrado un error que no hubiera estado allí si hubiera usado -O2.
Por demanda popular, aquí una adición:
-O3 y especialmente indicadores adicionales como -funroll-loops (no habilitado por -O3) a veces pueden generar más código de máquina. Bajo ciertas circunstancias (por ejemplo, en una CPU con caché de instrucciones L1 excepcionalmente pequeña) esto puede causar una desaceleración debido a todo el código de, por ejemplo, algún bucle interno que ahora ya no se ajusta a L1I. En general, gcc se esfuerza por no generar tanto código, pero como generalmente optimiza el caso genérico, esto puede suceder. Las opciones especialmente propensas a esto (como el desenrollado de bucle) normalmente no se incluyen en -O3 y se marcan en consecuencia en la página de manual. Como tal, generalmente es una buena idea usar -O3 para generar código rápido, y solo recurrir a -O2 u -Os (que intenta optimizar el tamaño del código) cuando sea apropiado (por ejemplo, cuando un generador de perfiles indica que L1I falla).
Si desea llevar la optimización al extremo, puede modificar gcc a través de --param los costos asociados con ciertas optimizaciones. Además, tenga en cuenta que gcc ahora tiene la capacidad de poner atributos en las funciones que controlan la configuración de optimización solo para estas funciones, por lo que cuando encuentre que tiene un problema con -O3 en una función (o si desea probar indicadores especiales solo para esa función), no necesita compilar todo el archivo o incluso todo el proyecto con O2.
otoh parece que se debe tener cuidado al usar -Ofast, que establece:
lo que me hace concluir que -O3 está destinado a cumplir totalmente con los estándares.
fuente
std::sort
es poco probable que el análisis estático que busca llamadas a funciones ayude. Usar algo como stackoverflow.com/questions/109710/… ayudaría, o tal vez escribir la fuente para aprovechar la ordenación: escanee hasta que vea> = 128, luego comience a sumar. En cuanto al código hinchado, sí, tengo la intención de informarlo. : PEn mi experiencia un tanto a cuadros, aplicar
-O3
a un programa completo casi siempre lo hace más lento (en relación con-O2
), ya que activa el desenrollado y la línea de bucle agresivo que hacen que el programa ya no encaje en el caché de instrucciones. Para programas más grandes, esto también puede ser cierto en-O2
relación con-Os
!El patrón de uso previsto para
-O3
es, después de perfilar su programa, lo aplica manualmente a un pequeño puñado de archivos que contienen bucles internos críticos que realmente se benefician de estos intercambios agresivos de espacio por velocidad. Las versiones más nuevas de GCC tienen un modo de optimización guiado por perfil que puede (IIUC) aplicar selectivamente las-O3
optimizaciones a funciones activas, automatizando efectivamente este proceso.fuente
La opción -O3 activa optimizaciones más costosas, como la función en línea, además de todas las optimizaciones de los niveles inferiores '-O2' y '-O1'. El nivel de optimización '-O3' puede aumentar la velocidad del ejecutable resultante, pero también puede aumentar su tamaño. En algunas circunstancias donde estas optimizaciones no son favorables, esta opción podría hacer que un programa sea más lento.
fuente
Sí, O3 tiene errores. Soy un desarrollador de compiladores e identifiqué errores claros y obvios de gcc causados por O3 que genera instrucciones de ensamblaje SIMD con errores al construir mi propio software. Por lo que he visto, la mayoría del software de producción viene con O2, lo que significa que O3 obtendrá menos atención en las pruebas de errores y correcciones de errores.
Piénselo de esta manera: O3 agrega más transformaciones sobre O2, lo que agrega más transformaciones sobre O1. Estadísticamente hablando, más transformaciones significa más errores. Eso es cierto para cualquier compilador.
fuente
Recientemente tuve un problema al usar la optimización con
g++
. El problema estaba relacionado con una tarjeta PCI, donde los registros (para comando y datos) estaban representados por una dirección de memoria. Mi controlador asignó la dirección física a un puntero dentro de la aplicación y se la dio al proceso llamado, que funcionó así:La tarjeta no actuó como se esperaba. Cuando vi la asamblea entendí que el compilador solo escribía
someCommand[ the last ]
enpciMemory
, omitiendo todas las escrituras anteriores.En conclusión: sea preciso y atento con la optimización.
fuente
pciMemory
comovolatile
.pciMemory
porque todas las demás escrituras probablemente no tengan efecto. Para el optimizador es increíble porque puede eliminar muchas instrucciones inútiles y que consumen mucho tiempo.