¿Hay algún inconveniente en usar -O3 en GCC?

7 minutos de lectura

He sido ingeniero de software durante 13 años en varios idiomas, aunque recién ahora me estoy abriendo paso en C y luego en C++. Mientras aprendo C, estoy usando el compilador GCC para compilar mis programas, y me pregunto si hay algún problema con el uso de -O3 u otras marcas de optimización. ¿Existe la posibilidad de que mi software se rompa de formas que no pueda detectar sin probar el código compilado, o tal vez durante la compilación cruzada, sin darme cuenta podría estropear algo para una plataforma diferente?

Antes de activar ciegamente esas opciones, me gustaría saber qué puedo esperar. Además, como -Ofast activa las banderas que no cumplen con los estándares, me inclino por no usar eso. ¿Tengo razón en mis suposiciones de que -Ofast probablemente tendrá “efectos secundarios”?

he echado un vistazo https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html antes de publicar esta pregunta.

  • Creo que es un caso de -O2 tiene mucho más kilometraje que -O3. Te recomendaría que te asegures de probar los binarios…

    – viejo contador de tiempo

    13 de diciembre de 2015 a las 1:17

  • deberías probar todos tus binarios de todos modos…

    – viejo contador de tiempo

    13 de diciembre de 2015 a las 1:18

  • @dwelch Tienes razón. Después de escribir eso sobre las pruebas, me di cuenta de que no podía probarlo antes de compilarlo. Supongo que estoy acostumbrado a las pruebas de lenguaje con guión donde puedo evadir la interfaz pública.

    –Rick Mac Gillis

    13 de diciembre de 2015 a las 1:19


  • Si explota el comportamiento indefinido, es posible que obtenga algunas sorpresas. Para código compatible: el código no debe comportarse de manera diferente. Sin embargo, su pregunta no puede responderse sin una revisión del código (y eso está fuera de tema en SO).

    – demasiado honesto para este sitio

    13 de diciembre de 2015 a las 1:24

  • Si aún desea depurar su programa, debe usar -Og. Sin embargo, si su código se rompe con la optimización activada, es muy posible que también tenga un mal comportamiento con la próxima versión de gcc o cuando use una arquitectura diferente, un compilador, agregue otra línea de código, etc. Confiar en UB siempre es una invitación al desastre.

    – demasiado honesto para este sitio

    13 de diciembre de 2015 a las 1:28


El único inconveniente de -O3 debería ser la incapacidad de seguir el código en un depurador.

El uso de -Ofast puede afectar algunas de sus operaciones de punto flotante causando errores de redondeo, pero a menos que esté ejecutando cadenas específicamente largas de cálculos de punto flotante, es poco probable que lo note.

Es probable que el código roto (código con punteros incorrectos o declaraciones con un comportamiento indefinido) se comporte de manera diferente en diferentes niveles de optimización; la primera reacción de muchos programadores es culpar al compilador; habilitar todas las advertencias y corregirlas generalmente ayuda.

  • ¿Las advertencias y los errores no están habilitados de forma predeterminada? Eso apesta. ¿Supongo que uso `-Wall` y` -Eall` para eso? Acabo de encontrar ¿Cómo activar (literalmente) TODAS las advertencias de GCC?

    –Rick Mac Gillis

    13 de diciembre de 2015 a las 1:40


  • Al contrario de lo que creerías -Wall no habilita todas las advertencias, sino solo el subconjunto más útil: hay más advertencias que puede Chequea aquí

    – Sorén

    13 de diciembre de 2015 a las 1:44

  • @RickMacGillis -Wall -Wextra -pedantic es útil, y también recuerde especificar manualmente un estándar de idioma (-std=c11 o -std=c++14), o en su lugar le dará el modo GNU con un montón de extensiones (útiles, pero no estándar).

    – Leushenko

    13 de diciembre de 2015 a las 1:47


  • @Leushenko: Las extensiones normalmente no deberían interferir con el código compatible.

    – demasiado honesto para este sitio

    13 de diciembre de 2015 a las 1:56

  • -Wconversion también es para recomendar. Pero tenga en cuenta que podría generar algunas advertencias si su código no está escrito con cuidado. Pero las advertencias son excelentes para señalarle posibles problemas de conversión.

    – demasiado honesto para este sitio

    13 de diciembre de 2015 a las 1:58


avatar de usuario
DaoWen

Es importante recordar que casi todas las optimizaciones del compilador son heurística. En otras palabras, una “optimización” es sólo una intentar para hacer su programa más “óptimo”, pero muy bien podría tener el efecto contrario. Simplemente porque -O3 se supone que es mejor que -O2y -O2 debería ser mejor que -O1—eso no significa que, de hecho, siempre es así como funciona.

A veces, una “optimización” habilitada por -O3 en realidad podría ralentizar su programa en comparación con la versión generada con -O2 o -O1. Debe experimentar con diferentes niveles de optimización para ver qué funciona mejor para su código específico. Incluso puede activar y desactivar optimizaciones individuales si realmente desea ajustarlo.

En resumen, sí, puede haber desventajas al usar -O3. He observado personalmente que muchas de las cosas que he escrito funcionan mejor con -O2 que con -O3—pero eso es realmente específico del programa.


FYI, aquí hay otra pregunta SO que pregunta por qué -O2 da mejores resultados que -O3 para un programa específico: indicador de optimización gcc -O3 hace que el código sea más lento que -O2

“Me gustaría saber qué puedo esperar”

He estado usando C++ (principalmente GCC en vxWorks) en sistemas integrados durante más de 2 décadas. Tengo un gran respeto por los escritores de compiladores.


Confíe en su compilador: en mi humilde opinión, -O3 nunca ha descifrado ningún código… pero, en ocasiones, ha revelado errores de codificación interesantes.


Elegir: Los equipos deben elegir si no para “enviar lo que prueba y probar lo que envía”, independientemente de la elección -O1 o -O3. Los equipos con los que he trabajado siempre se han comprometido a enviar y probar con -O3.


Single Step puede ser poco cooperativo: a nivel de práctica personal, cuando uso el código -O3, normalmente ‘abandono’ gdb single step. Hago mucho más uso de los puntos de interrupción, y hay ligeras variaciones en las opciones de codificación para hacer que las variables automáticas (datos de pila) y los datos de clase sean más ‘visibles’. (Puede hacer que el comando gdb ‘p’ sea su amigo inconveniente).


Un solo paso es necesario: tenga en cuenta que aunque “probamos y enviamos” usando -O3, depuramos usando el código -O1 casi exclusivamente.


La depuración es necesaria: la compensación entre la depuración de -01 pero la prueba y el envío de -O3 son las recompilaciones adicionales necesarias para cambiar los dos ejecutables. El tiempo ahorrado en -O1 para explorar, identificar y corregir los errores de código tiene que compensar las 2 reconstrucciones (a -01 y de regreso a -O3).


Automatización de prueba de regresión: quiero decir que la prueba de sistemas (también conocida como prueba de integración o prueba de regresión) de -O3 tiene que aumentar un nivel, pero realmente no puedo describirlo… tal vez debería recomendar que el nivel de automatización de prueba ser mayor (¡cada una de las PRUEBAS DE REGRESIÓN!). Pero no estoy seguro. El nivel de automatización de la prueba de regresión probablemente se correlaciona más con el tamaño del equipo que con el nivel de rendimiento.


Un sistema embebido ‘exitoso’ hace 2 cosas. Cumple con los requisitos. Y, creo que lo más importante, en todo el comportamiento humano visible, actúa como un escritorio con poca carga. Para cualquier acción (pulsación de botón, desconexión del cable, error inducido por el equipo de prueba o incluso un cambio leve de la luz de estado), los resultados no tienen un retraso perceptible por el ser humano. -O3 ayuda. Un sistema exitoso se puede hacer… lo he visto.

Dado que -O3 comienza a mover su código para optimizarlo, en algunos casos puede ver que sus resultados son diferentes o sus interrupciones.

Si prueba la corrección de su código con -O3 y encuentra un problema que no puede depurar, se recomienda cambiar a -O0 para ver si obtiene el mismo comportamiento.

¿Ha sido útil esta solución?